Fix arranging unprintable objects

fixes #10911
fixes SPE-1830
This commit is contained in:
tamasmeszaros 2023-07-31 15:02:41 +02:00
parent 708f58949d
commit b2a2710128
3 changed files with 76 additions and 27 deletions

View File

@ -93,6 +93,11 @@ template<class ArrItem> bool is_fixed(const ArrItem &ap)
return get_bed_index(ap) >= PhysicalBedId;
}
template<class ArrItem> bool is_on_physical_bed(const ArrItem &ap)
{
return get_bed_index(ap) == PhysicalBedId;
}
template<class ArrItem> void translate(ArrItem &ap, const Vec2crd &t)
{
set_translation(ap, get_translation(ap) + t);

View File

@ -19,6 +19,36 @@ struct CenterAlignmentFn {
}
};
template<class ArrItem>
struct RectangleOverfitPackingContext : public DefaultPackingContext<ArrItem>
{
BoundingBox limits;
int bed_index;
PostAlignmentFn post_alignment_fn;
explicit RectangleOverfitPackingContext(const BoundingBox limits,
int bedidx,
PostAlignmentFn alignfn = CenterAlignmentFn{})
: limits{limits}, bed_index{bedidx}, post_alignment_fn{alignfn}
{}
void align_pile()
{
// Here, the post alignment can be safely done. No throwing
// functions are called!
if (fixed_items_range(*this).empty()) {
auto itms = packed_items_range(*this);
auto pilebb = bounding_box(itms);
for (auto &itm : itms) {
translate(itm, post_alignment_fn(limits, pilebb));
}
}
}
~RectangleOverfitPackingContext() { align_pile(); }
};
// With rectange bed, and no fixed items, an infinite bed with
// RectangleOverfitKernelWrapper can produce better results than a pure
// RectangleBed with inner-fit polygon calculation.
@ -29,31 +59,7 @@ struct RectangleOverfitPackingStrategy {
PostAlignmentFn post_alignment_fn = CenterAlignmentFn{};
template<class ArrItem>
struct Context: public DefaultPackingContext<ArrItem> {
BoundingBox limits;
int bed_index;
PostAlignmentFn post_alignment_fn;
explicit Context(const BoundingBox limits,
int bedidx,
PostAlignmentFn alignfn = CenterAlignmentFn{})
: limits{limits}, bed_index{bedidx}, post_alignment_fn{alignfn}
{}
~Context()
{
// Here, the post alignment can be safely done. No throwing
// functions are called!
if (fixed_items_range(*this).empty()) {
auto itms = packed_items_range(*this);
auto pilebb = bounding_box(itms);
for (auto &itm : itms) {
translate(itm, post_alignment_fn(limits, pilebb));
}
}
}
};
using Context = RectangleOverfitPackingContext<ArrItem>;
RectangleOverfitPackingStrategy(PackStrategyNFP<Args...> s,
PostAlignmentFn post_align_fn)
@ -89,6 +95,19 @@ struct PackStrategyTraits_<RectangleOverfitPackingStrategy<Args...>> {
}
};
template<class ArrItem>
struct PackingContextTraits_<RectangleOverfitPackingContext<ArrItem>>
: public PackingContextTraits_<DefaultPackingContext<ArrItem>>
{
static void add_packed_item(RectangleOverfitPackingContext<ArrItem> &ctx, ArrItem &itm)
{
ctx.add_packed_item(itm);
// to prevent coords going out of range
ctx.align_pile();
}
};
template<class Strategy, class ArrItem, class Bed, class RemIt>
bool pack(Strategy &strategy,
const Bed &bed,

View File

@ -54,6 +54,20 @@ std::unique_ptr<ArrangeTask<ArrItem>> ArrangeTask<ArrItem>::create(
return task;
}
// Remove all items on the physical bed (not occupyable for unprintable items)
// and shift all items to the next lower bed index, so that arrange will think
// that logical bed no. 1 is the physical one
template<class ItemCont>
void prepare_fixed_unselected(ItemCont &items, int shift)
{
for (auto &itm : items)
set_bed_index(itm, get_bed_index(itm) - shift);
items.erase(std::remove_if(items.begin(), items.end(),
[](auto &itm) { return !is_arranged(itm); }),
items.end());
}
template<class ArrItem>
std::unique_ptr<ArrangeTaskResult>
ArrangeTask<ArrItem>::process_native(Ctl &ctl)
@ -78,8 +92,15 @@ ArrangeTask<ArrItem>::process_native(Ctl &ctl)
} subctl{ctl, *this};
arranger->arrange(printable.selected, printable.unselected, bed, subctl);
arranger->arrange(unprintable.selected, unprintable.unselected, bed, ctl);
auto fixed_items = printable.unselected;
// static (unselected) unprintable objects should not be overlapped by
// movable and printable objects
std::copy(unprintable.unselected.begin(),
unprintable.unselected.end(),
std::back_inserter(fixed_items));
arranger->arrange(printable.selected, fixed_items, bed, subctl);
// Unprintable items should go to the first bed not containing any printable
// items
@ -89,6 +110,10 @@ ArrangeTask<ArrItem>::process_native(Ctl &ctl)
// If there are no printables, leave the physical bed empty
beds = std::max(beds, size_t{1});
prepare_fixed_unselected(unprintable.unselected, beds);
arranger->arrange(unprintable.selected, unprintable.unselected, bed, ctl);
result->add_items(crange(printable.selected));
for (auto &itm : unprintable.selected) {