diff --git a/src/libslic3r/Arrange/Core/ArrangeItemTraits.hpp b/src/libslic3r/Arrange/Core/ArrangeItemTraits.hpp index 5806627eb1..81acc863cf 100644 --- a/src/libslic3r/Arrange/Core/ArrangeItemTraits.hpp +++ b/src/libslic3r/Arrange/Core/ArrangeItemTraits.hpp @@ -93,6 +93,11 @@ template bool is_fixed(const ArrItem &ap) return get_bed_index(ap) >= PhysicalBedId; } +template bool is_on_physical_bed(const ArrItem &ap) +{ + return get_bed_index(ap) == PhysicalBedId; +} + template void translate(ArrItem &ap, const Vec2crd &t) { set_translation(ap, get_translation(ap) + t); diff --git a/src/libslic3r/Arrange/Core/NFP/RectangleOverfitPackingStrategy.hpp b/src/libslic3r/Arrange/Core/NFP/RectangleOverfitPackingStrategy.hpp index eb41094df6..8efb0ac27e 100644 --- a/src/libslic3r/Arrange/Core/NFP/RectangleOverfitPackingStrategy.hpp +++ b/src/libslic3r/Arrange/Core/NFP/RectangleOverfitPackingStrategy.hpp @@ -19,6 +19,36 @@ struct CenterAlignmentFn { } }; +template +struct RectangleOverfitPackingContext : public DefaultPackingContext +{ + 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 - struct Context: public DefaultPackingContext { - 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; RectangleOverfitPackingStrategy(PackStrategyNFP s, PostAlignmentFn post_align_fn) @@ -89,6 +95,19 @@ struct PackStrategyTraits_> { } }; +template +struct PackingContextTraits_> + : public PackingContextTraits_> +{ + static void add_packed_item(RectangleOverfitPackingContext &ctx, ArrItem &itm) + { + ctx.add_packed_item(itm); + + // to prevent coords going out of range + ctx.align_pile(); + } +}; + template bool pack(Strategy &strategy, const Bed &bed, diff --git a/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp b/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp index d4ff0244d2..703e6866ff 100644 --- a/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp +++ b/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp @@ -54,6 +54,20 @@ std::unique_ptr> ArrangeTask::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 +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 std::unique_ptr ArrangeTask::process_native(Ctl &ctl) @@ -78,8 +92,15 @@ ArrangeTask::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::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) {