diff --git a/src/libslic3r/Arrange/Arrange.hpp b/src/libslic3r/Arrange/Arrange.hpp index 36ab838739..75e632ad95 100644 --- a/src/libslic3r/Arrange/Arrange.hpp +++ b/src/libslic3r/Arrange/Arrange.hpp @@ -83,11 +83,19 @@ void Arranger::arrange(std::vector &items, arrange(items, fixed, bed, DefaultArrangerCtl{ctl}); } +class EmptyItemOutlineError: public std::exception { + static constexpr const char *Msg = "No outline can be derived for object"; + +public: + const char* what() const noexcept override { return Msg; } +}; + template class ArrangeableToItemConverter { public: virtual ~ArrangeableToItemConverter() = default; + // May throw EmptyItemOutlineError virtual ArrItem convert(const Arrangeable &arrbl, coord_t offs = 0) const = 0; // Returns the extent of simplification that the converter utilizes when diff --git a/src/libslic3r/Arrange/ArrangeImpl.hpp b/src/libslic3r/Arrange/ArrangeImpl.hpp index 2b7f62e87f..79f474bc2d 100644 --- a/src/libslic3r/Arrange/ArrangeImpl.hpp +++ b/src/libslic3r/Arrange/ArrangeImpl.hpp @@ -2,6 +2,7 @@ #define ARRANGEIMPL_HPP #include +#include #include "Arrange.hpp" @@ -43,25 +44,23 @@ void arrange(SelectionStrategy &&selstrategy, std::forward(packingstrategy), items, fixed, RectangleBed{bed.bb}, SelStrategyTag{}); - size_t beds = get_bed_count(crange(items)); - size_t fixed_beds = std::max(beds, get_bed_count(fixed)); - std::vector fixed_is_empty(fixed_beds, true); - - std::vector pilebb(beds); + std::vector bed_indices = get_bed_indices(items, fixed); + std::map pilebb; + std::map bed_occupied; for (auto &itm : items) { auto bedidx = get_bed_index(itm); if (bedidx >= 0) { pilebb[bedidx].merge(fixed_bounding_box(itm)); if (is_wipe_tower(itm)) - fixed_is_empty[bedidx] = false; + bed_occupied[bedidx] = true; } } for (auto &fxitm : fixed) { auto bedidx = get_bed_index(fxitm); - if (bedidx >= 0 || is_wipe_tower(fxitm)) - fixed_is_empty[bedidx] = false; + if (bedidx >= 0) + bed_occupied[bedidx] = true; } auto bedbb = bounding_box(bed); @@ -73,8 +72,9 @@ void arrange(SelectionStrategy &&selstrategy, Pivots pivot = bed.alignment(); - for (size_t bedidx = 0; bedidx < beds; ++bedidx) { - if (! fixed_is_empty[bedidx]) + for (int bedidx : bed_indices) { + if (auto occup_it = bed_occupied.find(bedidx); + occup_it != bed_occupied.end() && occup_it->second) continue; BoundingBox bb; @@ -272,7 +272,7 @@ class DefaultArranger: public Arranger { int pa = get_priority(itm1); int pb = get_priority(itm2); - return pa == pb ? envelope_area(itm1) > envelope_area(itm2) : + return pa == pb ? area(envelope_convex_hull(itm1)) > area(envelope_convex_hull(itm2)) : pa > pb; }; @@ -295,7 +295,11 @@ class DefaultArranger: public Arranger { default: [[fallthrough]]; case ArrangeSettingsView::asAuto: - basekernel = TMArrangeKernel{items.size(), area(bed)}; + if constexpr (std::is_convertible_v){ + basekernel = GravityKernel{}; + } else { + basekernel = TMArrangeKernel{items.size(), area(bed)}; + } break; case ArrangeSettingsView::asPullToCenter: basekernel = GravityKernel{}; @@ -370,6 +374,10 @@ ArrItem ConvexItemConverter::convert(const Arrangeable &arrbl, { auto bed_index = arrbl.get_bed_index(); Polygon outline = arrbl.convex_outline(); + + if (outline.empty()) + throw EmptyItemOutlineError{}; + Polygon envelope = arrbl.convex_envelope(); coord_t infl = offs + coord_t(std::ceil(this->safety_dist() / 2.)); @@ -418,6 +426,10 @@ ArrItem AdvancedItemConverter::get_arritem(const Arrangeable &arrbl, coord_t infl = offs + coord_t(std::ceil(this->safety_dist() / 2.)); auto outline = arrbl.full_outline(); + + if (outline.empty()) + throw EmptyItemOutlineError{}; + auto envelope = arrbl.full_envelope(); if (infl != 0) { diff --git a/src/libslic3r/Arrange/Core/ArrangeBase.hpp b/src/libslic3r/Arrange/Core/ArrangeBase.hpp index 97177d4b3c..d341903d72 100644 --- a/src/libslic3r/Arrange/Core/ArrangeBase.hpp +++ b/src/libslic3r/Arrange/Core/ArrangeBase.hpp @@ -233,8 +233,44 @@ void arrange(SelectionStrategy &&selstrategy, "Arrange unimplemented for this selection strategy"); } +template +std::vector get_bed_indices(const Range &items) +{ + auto bed_indices = reserve_vector(items.size()); + + for (auto &itm : items) + bed_indices.emplace_back(get_bed_index(itm)); + + std::sort(bed_indices.begin(), bed_indices.end()); + auto endit = std::unique(bed_indices.begin(), bed_indices.end()); + + bed_indices.erase(endit, bed_indices.end()); + + return bed_indices; +} + +template +std::vector get_bed_indices(const Range &items, const Range &fixed) +{ + std::vector ret; + + auto iitems = get_bed_indices(items); + auto ifixed = get_bed_indices(fixed); + ret.reserve(std::max(iitems.size(), ifixed.size())); + std::set_union(iitems.begin(), iitems.end(), + ifixed.begin(), ifixed.end(), + std::back_inserter(ret)); + + return ret; +} + template size_t get_bed_count(const Range &items) +{ + return get_bed_indices(items).size(); +} + +template int get_max_bed_index(const Range &items) { auto it = std::max_element(items.begin(), items.end(), @@ -242,11 +278,11 @@ size_t get_bed_count(const Range &items) return get_bed_index(i1) < get_bed_index(i2); }); - size_t beds = 0; + int ret = Unarranged; if (it != items.end()) - beds = get_bed_index(*it) + 1; + ret = get_bed_index(*it); - return beds; + return ret; } struct DefaultStopCondition { diff --git a/src/libslic3r/Arrange/Core/ArrangeFirstFit.hpp b/src/libslic3r/Arrange/Core/ArrangeFirstFit.hpp index ee6940b770..cf8d3e457a 100644 --- a/src/libslic3r/Arrange/Core/ArrangeFirstFit.hpp +++ b/src/libslic3r/Arrange/Core/ArrangeFirstFit.hpp @@ -2,6 +2,7 @@ #define ARRANGEFIRSTFIT_HPP #include +#include #include @@ -88,21 +89,28 @@ void arrange( sorted_items.emplace_back(itm); } - int max_bed_idx = get_bed_count(fixed); - using Context = PackStrategyContext; - auto bed_contexts = reserve_vector(max_bed_idx + 1); + std::map bed_contexts; + auto get_or_init_context = [&ps, &bed, &bed_contexts](int bedidx) -> Context& { + auto ctx_it = bed_contexts.find(bedidx); + if (ctx_it == bed_contexts.end()) { + auto res = bed_contexts.emplace( + bedidx, create_context(ps, bed, bedidx)); + + assert(res.second); + + ctx_it = res.first; + } + + return ctx_it->second; + }; for (auto &itm : fixed) { - if (get_bed_index(itm) >= 0) { - auto bedidx = static_cast(get_bed_index(itm)); - - while (bed_contexts.size() <= bedidx) - bed_contexts.emplace_back( - create_context(ps, bed, bedidx)); - - add_fixed_item(bed_contexts[bedidx], itm); + auto bedidx = get_bed_index(itm); + if (bedidx >= 0) { + Context &ctx = get_or_init_context(bedidx); + add_fixed_item(ctx, itm); } } @@ -124,18 +132,20 @@ void arrange( while (it != sorted_items.end() && !is_cancelled()) { bool was_packed = false; - size_t j = 0; + int bedidx = 0; while (!was_packed && !is_cancelled()) { - for (; j < bed_contexts.size() && !was_packed && !is_cancelled(); j++) { - set_bed_index(*it, int(j)); + for (; !was_packed && !is_cancelled(); bedidx++) { + set_bed_index(*it, bedidx); auto remaining = Range{std::next(static_cast(it)), sorted_items.cend()}; - was_packed = pack(ps, bed, *it, bed_contexts[j], remaining); + Context &ctx = get_or_init_context(bedidx); + + was_packed = pack(ps, bed, *it, ctx, remaining); if(was_packed) { - add_packed_item(bed_contexts[j], *it); + add_packed_item(ctx, *it); auto packed_range = Range{sorted_items.cbegin(), static_cast(it)}; @@ -145,12 +155,6 @@ void arrange( set_bed_index(*it, Unarranged); } } - - if (!was_packed) { - bed_contexts.emplace_back( - create_context(ps, bed, bed_contexts.size())); - j = bed_contexts.size() - 1; - } } ++it; } diff --git a/src/libslic3r/Arrange/Core/Beds.cpp b/src/libslic3r/Arrange/Core/Beds.cpp index 90d5f4f77d..1c96723767 100644 --- a/src/libslic3r/Arrange/Core/Beds.cpp +++ b/src/libslic3r/Arrange/Core/Beds.cpp @@ -110,7 +110,7 @@ template auto call_with_bed(const Points &bed, Fn &&fn) if ((1.0 - parea / area(bb)) < 1e-3) { return fn(RectangleBed{bb}); - } else if (!std::isnan(circ.radius())) + } else if (!std::isnan(circ.radius()) && (1.0 - parea / area(circ)) < 1e-2) return fn(circ); else return fn(IrregularBed{{ExPolygon(bed)}}); diff --git a/src/libslic3r/Arrange/Scene.cpp b/src/libslic3r/Arrange/Scene.cpp index a59b3f9aec..ddcc5ead67 100644 --- a/src/libslic3r/Arrange/Scene.cpp +++ b/src/libslic3r/Arrange/Scene.cpp @@ -54,11 +54,11 @@ std::set selected_geometry_ids(const Scene &sc) return result; } -void arrange(Scene &scene, ArrangeTaskCtl &ctl) +bool arrange(Scene &scene, ArrangeTaskCtl &ctl) { auto task = ArrangeTaskBase::create(Tasks::Arrange, scene); auto result = task->process(ctl); - result->apply_on(scene.model()); + return result->apply_on(scene.model()); } }} // namespace Slic3r::arr2 diff --git a/src/libslic3r/Arrange/Scene.hpp b/src/libslic3r/Arrange/Scene.hpp index f917ed3c2f..16622e464a 100644 --- a/src/libslic3r/Arrange/Scene.hpp +++ b/src/libslic3r/Arrange/Scene.hpp @@ -161,6 +161,14 @@ template void visit_bed(BedFn &&fn, ExtendedBed &bed) boost::apply_visitor(fn, bed); } +inline BoundingBox bounding_box(const ExtendedBed &bed) +{ + BoundingBox bedbb; + visit_bed([&bedbb](auto &rawbed) { bedbb = bounding_box(rawbed); }, bed); + + return bedbb; +} + class Scene; // SceneBuilderBase is intended for Scene construction. A simple constructor @@ -365,10 +373,26 @@ public: } }; -void arrange(Scene &scene, ArrangeTaskCtl &ctl); -inline void arrange(Scene &scene, ArrangeTaskCtl &&ctl = DummyCtl{}) +bool arrange(Scene &scene, ArrangeTaskCtl &ctl); +inline bool arrange(Scene &scene, ArrangeTaskCtl &&ctl = DummyCtl{}) { - arrange(scene, ctl); + return arrange(scene, ctl); +} + +inline bool arrange(Scene &&scene, ArrangeTaskCtl &ctl) +{ + return arrange(scene, ctl); +} + +inline bool arrange(Scene &&scene, ArrangeTaskCtl &&ctl = DummyCtl{}) +{ + return arrange(scene, ctl); +} + +template +bool arrange(SceneBuilderBase &&builder, Ctl &&ctl = {}) +{ + return arrange(Scene{std::move(builder)}, ctl); } } // namespace arr2 diff --git a/src/libslic3r/Arrange/SceneBuilder.cpp b/src/libslic3r/Arrange/SceneBuilder.cpp index a6e37c0b74..53a785ea8d 100644 --- a/src/libslic3r/Arrange/SceneBuilder.cpp +++ b/src/libslic3r/Arrange/SceneBuilder.cpp @@ -64,16 +64,18 @@ void transform_instance(ModelInstance &mi, mi.invalidate_object_bounding_box(); } -BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate) +BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, + const Transform3d &tr, + bool dont_translate) { BoundingBoxf3 bb; const Transform3d inst_matrix = dont_translate ? mi.get_transformation().get_matrix_no_offset() - : mi.get_transformation().get_matrix(); + : mi.get_transformation().get_matrix(); for (ModelVolume *v : mi.get_object()->volumes) { if (v->is_model_part()) { - bb.merge(v->mesh().transformed_bounding_box(inst_matrix + bb.merge(v->mesh().transformed_bounding_box(tr * inst_matrix * v->get_matrix())); } } @@ -81,22 +83,39 @@ BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate return bb; } +BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate) +{ + return instance_bounding_box(mi, Transform3d::Identity(), dont_translate); +} + +bool check_coord_bounds(const BoundingBoxf &bb) +{ + return std::abs(bb.min.x()) < UnscaledCoordLimit && + std::abs(bb.min.y()) < UnscaledCoordLimit && + std::abs(bb.max.x()) < UnscaledCoordLimit && + std::abs(bb.max.y()) < UnscaledCoordLimit; +} + ExPolygons extract_full_outline(const ModelInstance &inst, const Transform3d &tr) { ExPolygons outline; - for (const ModelVolume *v : inst.get_object()->volumes) { - Polygons vol_outline; - vol_outline = project_mesh(v->mesh().its, - tr * inst.get_matrix() * v->get_matrix(), - [] {}); - switch (v->type()) { - case ModelVolumeType::MODEL_PART: - outline = union_ex(outline, vol_outline); - break; - case ModelVolumeType::NEGATIVE_VOLUME: - outline = diff_ex(outline, vol_outline); - break; - default:; + + if (check_coord_bounds(to_2d(instance_bounding_box(inst, tr)))) { + for (const ModelVolume *v : inst.get_object()->volumes) { + Polygons vol_outline; + + vol_outline = project_mesh(v->mesh().its, + tr * inst.get_matrix() * v->get_matrix(), + [] {}); + switch (v->type()) { + case ModelVolumeType::MODEL_PART: + outline = union_ex(outline, vol_outline); + break; + case ModelVolumeType::NEGATIVE_VOLUME: + outline = diff_ex(outline, vol_outline); + break; + default:; + } } } @@ -105,7 +124,14 @@ ExPolygons extract_full_outline(const ModelInstance &inst, const Transform3d &tr Polygon extract_convex_outline(const ModelInstance &inst, const Transform3d &tr) { - return inst.get_object()->convex_hull_2d(tr * inst.get_matrix()); + auto bb = to_2d(instance_bounding_box(inst, tr)); + Polygon ret; + + if (check_coord_bounds(bb)) { + ret = inst.get_object()->convex_hull_2d(tr * inst.get_matrix()); + } + + return ret; } inline static bool is_infinite_bed(const ExtendedBed &ebed) noexcept @@ -171,6 +197,17 @@ void SceneBuilder::build_arrangeable_slicer_model(ArrangeableSlicerModel &amodel m_wipetower_handler = std::make_unique(); } + if (m_fff_print && !m_xl_printer) + m_xl_printer = is_XL_printer(m_fff_print->config()); + + bool has_wipe_tower = false; + m_wipetower_handler->visit( + [&has_wipe_tower](const Arrangeable &arrbl) { has_wipe_tower = true; }); + + if (m_xl_printer && !has_wipe_tower) { + m_bed = XLBed{bounding_box(m_bed)}; + } + amodel.m_vbed_handler = std::move(m_vbed_handler); amodel.m_model = std::move(m_model); amodel.m_selmask = std::move(m_selection); @@ -190,7 +227,14 @@ int XStriderVBedHandler::get_bed_index(const VBedPlaceable &obj) const auto reference_pos_x = (instance_bb.min.x() - bedx); auto stride = unscaled(stride_s); - bedidx = static_cast(std::floor(reference_pos_x / stride)); + auto bedidx_d = std::floor(reference_pos_x / stride); + + if (bedidx_d < std::numeric_limits::min()) + bedidx = std::numeric_limits::min(); + else if (bedidx_d > std::numeric_limits::max()) + bedidx = std::numeric_limits::max(); + else + bedidx = static_cast(bedidx_d); } return bedidx; @@ -231,7 +275,14 @@ int YStriderVBedHandler::get_bed_index(const VBedPlaceable &obj) const auto reference_pos_y = (instance_bb.min.y() - ystart); auto stride = unscaled(stride_s); - bedidx = static_cast(std::floor(reference_pos_y / stride)); + auto bedidx_d = std::floor(reference_pos_y / stride); + + if (bedidx_d < std::numeric_limits::min()) + bedidx = std::numeric_limits::min(); + else if (bedidx_d > std::numeric_limits::max()) + bedidx = std::numeric_limits::max(); + else + bedidx = static_cast(bedidx_d); } return bedidx; @@ -262,21 +313,28 @@ Transform3d YStriderVBedHandler::get_physical_bed_trafo(int bed_index) const return tr; } -const int GridStriderVBedHandler::ColsOutside = - static_cast(std::sqrt(std::numeric_limits::max())); +const int GridStriderVBedHandler::Cols = + 2 * static_cast(std::sqrt(std::numeric_limits::max()) / 2); + +const int GridStriderVBedHandler::HalfCols = Cols / 2; +const int GridStriderVBedHandler::Offset = HalfCols + Cols * HalfCols; Vec2i GridStriderVBedHandler::raw2grid(int bed_idx) const { - Vec2i ret{bed_idx % ColsOutside, bed_idx / ColsOutside}; + bed_idx += Offset; + + Vec2i ret{bed_idx % Cols - HalfCols, bed_idx / Cols - HalfCols}; return ret; } int GridStriderVBedHandler::grid2raw(const Vec2i &crd) const { - assert(crd.x() < ColsOutside - 1 && crd.y() < ColsOutside - 1); + // Overlapping virtual beds will happen if the crd values exceed limits + assert((crd.x() < HalfCols - 1 && crd.x() >= -HalfCols) && + (crd.y() < HalfCols - 1 && crd.y() >= -HalfCols)); - return crd.y() * ColsOutside + crd.x(); + return (crd.x() + HalfCols) + Cols * (crd.y() + HalfCols) - Offset; } int GridStriderVBedHandler::get_bed_index(const VBedPlaceable &obj) const @@ -394,11 +452,11 @@ SceneBuilder &&SceneBuilder::set_bed(const DynamicPrintConfig &cfg) Points bedpts = get_bed_shape(cfg); if (is_XL_printer(cfg)) { - m_bed = XLBed{get_extents(bedpts)}; - } else { - m_bed = arr2::to_arrange_bed(bedpts); + m_xl_printer = true; } + m_bed = arr2::to_arrange_bed(bedpts); + return std::move(*this); } diff --git a/src/libslic3r/Arrange/SceneBuilder.hpp b/src/libslic3r/Arrange/SceneBuilder.hpp index c19bd6ed69..8f4f8a7797 100644 --- a/src/libslic3r/Arrange/SceneBuilder.hpp +++ b/src/libslic3r/Arrange/SceneBuilder.hpp @@ -205,6 +205,7 @@ protected: AnyPtr m_sla_print; AnyPtr m_fff_print; + bool m_xl_printer = false; void set_brim_and_skirt(); @@ -338,7 +339,9 @@ class GridStriderVBedHandler: public VirtualBedHandler // not representable with scaled coordinates. Combining XStrider with // YStrider takes care of the X and Y axis to be mapped into the physical // bed's coordinate region (which is representable in scaled coords) - static const int ColsOutside; + static const int Cols; + static const int HalfCols; + static const int Offset; XStriderVBedHandler m_xstrider; YStriderVBedHandler m_ystrider; @@ -377,6 +380,11 @@ void transform_instance(ModelInstance &mi, BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, bool dont_translate = false); +BoundingBoxf3 instance_bounding_box(const ModelInstance &mi, + const Transform3d &tr, + bool dont_translate = false); + +constexpr double UnscaledCoordLimit = 1000.; ExPolygons extract_full_outline(const ModelInstance &inst, const Transform3d &tr = Transform3d::Identity()); @@ -491,9 +499,9 @@ class ArrangeableSLAPrint : public ArrangeableSlicerModel { static void visit_arrangeable_(Self &&self, const ObjectID &id, Fn &&fn); public: - explicit ArrangeableSLAPrint(const SLAPrint *slaprint, - SceneBuilder &builder) - : m_slaprint{slaprint}, ArrangeableSlicerModel{builder} + explicit ArrangeableSLAPrint(const SLAPrint *slaprint, SceneBuilder &builder) + : m_slaprint{slaprint} + , ArrangeableSlicerModel{builder} { assert(slaprint != nullptr); } diff --git a/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp b/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp index c9f48f93e4..a46152ed98 100644 --- a/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp +++ b/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp @@ -3,6 +3,8 @@ #include +#include + #include "ArrangeTask.hpp" namespace Slic3r { namespace arr2 { @@ -20,16 +22,21 @@ void extract_selected(ArrangeTask &task, bool selected = arrbl.is_selected(); bool printable = arrbl.is_printable(); - auto itm = itm_conv.convert(arrbl, selected ? 0 : -SCALED_EPSILON); + try { + auto itm = itm_conv.convert(arrbl, selected ? 0 : -SCALED_EPSILON); - auto &container_parent = printable ? task.printable : + auto &container_parent = printable ? task.printable : task.unprintable; - auto &container = selected ? + auto &container = selected ? container_parent.selected : container_parent.unselected; - container.emplace_back(std::move(itm)); + container.emplace_back(std::move(itm)); + } catch (const EmptyItemOutlineError &ex) { + BOOST_LOG_TRIVIAL(error) + << "ObjectID " << std::to_string(arrbl.id().id) << ": " << ex.what(); + } }); // If the selection was empty arrange everything @@ -68,6 +75,21 @@ void prepare_fixed_unselected(ItemCont &items, int shift) items.end()); } +inline int find_first_empty_bed(const std::vector& bed_indices, + int starting_from = 0) { + int ret = starting_from; + + for (int idx : bed_indices) { + if (idx == ret) { + ret++; + } else if (idx > ret) { + break; + } + } + + return ret; +} + template std::unique_ptr ArrangeTask::process_native(Ctl &ctl) @@ -102,15 +124,17 @@ ArrangeTask::process_native(Ctl &ctl) arranger->arrange(printable.selected, fixed_items, bed, subctl); - // Unprintable items should go to the first bed not containing any printable - // items - auto beds = std::max(get_bed_count(crange(printable.selected)), - get_bed_count(crange(printable.unselected))); + std::vector printable_bed_indices = + get_bed_indices(crange(printable.selected), crange(printable.unselected)); // If there are no printables, leave the physical bed empty - beds = std::max(beds, size_t{1}); + constexpr int SearchFrom = 1; - prepare_fixed_unselected(unprintable.unselected, beds); + // Unprintable items should go to the first logical (!) bed not containing + // any printable items + int first_empty_bed = find_first_empty_bed(printable_bed_indices, SearchFrom); + + prepare_fixed_unselected(unprintable.unselected, first_empty_bed); arranger->arrange(unprintable.selected, unprintable.unselected, bed, ctl); @@ -118,7 +142,7 @@ ArrangeTask::process_native(Ctl &ctl) for (auto &itm : unprintable.selected) { if (is_arranged(itm)) { - int bedidx = get_bed_index(itm) + beds; + int bedidx = get_bed_index(itm) + first_empty_bed; arr2::set_bed_index(itm, bedidx); } diff --git a/src/libslic3r/Arrange/Tasks/FillBedTaskImpl.hpp b/src/libslic3r/Arrange/Tasks/FillBedTaskImpl.hpp index a99102418f..e874be4575 100644 --- a/src/libslic3r/Arrange/Tasks/FillBedTaskImpl.hpp +++ b/src/libslic3r/Arrange/Tasks/FillBedTaskImpl.hpp @@ -5,6 +5,8 @@ #include "Arrange/Core/NFP/NFPArrangeItemTraits.hpp" +#include + namespace Slic3r { namespace arr2 { template @@ -81,15 +83,20 @@ void extract(FillBedTask &task, auto collect_task_items = [&prototype_geometry_id, &task, &itm_conv](const Arrangeable &arrbl) { - if (arrbl.geometry_id() == prototype_geometry_id) { - if (arrbl.is_printable()) { - auto itm = itm_conv.convert(arrbl); - raise_priority(itm); - task.selected.emplace_back(std::move(itm)); + try { + if (arrbl.geometry_id() == prototype_geometry_id) { + if (arrbl.is_printable()) { + auto itm = itm_conv.convert(arrbl); + raise_priority(itm); + task.selected.emplace_back(std::move(itm)); + } + } else { + auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON); + task.unselected.emplace_back(std::move(itm)); } - } else { - auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON); - task.unselected.emplace_back(std::move(itm)); + } catch (const EmptyItemOutlineError &ex) { + BOOST_LOG_TRIVIAL(error) + << "ObjectID " << std::to_string(arrbl.id().id) << ": " << ex.what(); } }; diff --git a/src/libslic3r/Arrange/Tasks/MultiplySelectionTaskImpl.hpp b/src/libslic3r/Arrange/Tasks/MultiplySelectionTaskImpl.hpp index d4c925c3bf..422c3da243 100644 --- a/src/libslic3r/Arrange/Tasks/MultiplySelectionTaskImpl.hpp +++ b/src/libslic3r/Arrange/Tasks/MultiplySelectionTaskImpl.hpp @@ -3,6 +3,8 @@ #include "MultiplySelectionTask.hpp" +#include + namespace Slic3r { namespace arr2 { template @@ -45,15 +47,20 @@ std::unique_ptr> MultiplySelectionTask:: auto collect_task_items = [&prototype_geometry_id, &task, &itm_conv](const Arrangeable &arrbl) { - if (arrbl.geometry_id() == prototype_geometry_id) { - if (arrbl.is_printable()) { - auto itm = itm_conv.convert(arrbl); - raise_priority(itm); - task.selected.emplace_back(std::move(itm)); + try { + if (arrbl.geometry_id() == prototype_geometry_id) { + if (arrbl.is_printable()) { + auto itm = itm_conv.convert(arrbl); + raise_priority(itm); + task.selected.emplace_back(std::move(itm)); + } + } else { + auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON); + task.unselected.emplace_back(std::move(itm)); } - } else { - auto itm = itm_conv.convert(arrbl, -SCALED_EPSILON); - task.unselected.emplace_back(std::move(itm)); + } catch (const EmptyItemOutlineError &ex) { + BOOST_LOG_TRIVIAL(error) + << "ObjectID " << std::to_string(arrbl.id().id) << ": " << ex.what(); } }; diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index f0294e8a05..b5f53dfed5 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -1,14 +1,11 @@ #include "ModelArrange.hpp" - #include +#include +#include #include #include -#include "Arrange/Core/ArrangeItemTraits.hpp" -#include "Arrange/Items/ArrangeItem.hpp" - -#include "MTUtils.hpp" namespace Slic3r { @@ -27,14 +24,10 @@ bool arrange_objects(Model &model, const arr2::ArrangeBed &bed, const arr2::ArrangeSettingsView &settings) { - arr2::Scene scene{arr2::SceneBuilder{} - .set_bed(bed) - .set_arrange_settings(settings) - .set_model(model)}; - - auto task = arr2::ArrangeTaskBase::create(arr2::Tasks::Arrange, scene); - auto result = task->process(); - return result->apply_on(scene.model()); + return arrange(arr2::SceneBuilder{} + .set_bed(bed) + .set_arrange_settings(settings) + .set_model(model)); } void duplicate_objects(Model &model, diff --git a/tests/arrange/test_arrange.cpp b/tests/arrange/test_arrange.cpp index 0304a29db9..56bba72a53 100644 --- a/tests/arrange/test_arrange.cpp +++ b/tests/arrange/test_arrange.cpp @@ -760,7 +760,7 @@ TEST_CASE("First fit selection strategy", "[arrange2]") THEN("The item should be left unpacked") { - REQUIRE(std::all_of(items.begin(), items.end(), [](auto &itm) { + REQUIRE(std::all_of(items.begin(), items.end(), [](const ArrItem &itm) { return !Slic3r::arr2::is_arranged(itm); })); } @@ -878,7 +878,7 @@ TEST_CASE("First fit selection strategy", "[arrange2]") THEN("all items should fit onto the beds from index 0 to 4") { - REQUIRE(std::all_of(items.begin(), items.end(), [](auto &itm) { + REQUIRE(std::all_of(items.begin(), items.end(), [](const ArrItem &itm) { auto bed_idx = Slic3r::arr2::get_bed_index(itm); return bed_idx >= 0 && bed_idx < Count / Capacity; })); diff --git a/tests/arrange/test_arrange_integration.cpp b/tests/arrange/test_arrange_integration.cpp index b60b87fce9..6d8fda6bff 100644 --- a/tests/arrange/test_arrange_integration.cpp +++ b/tests/arrange/test_arrange_integration.cpp @@ -49,8 +49,8 @@ static Slic3r::Model get_example_model_with_random_cube_objects(size_t N = 0) for (size_t i = 0; i < cube_count; ++i) { ModelInstance *inst = new_object->add_instance(); arr2::transform_instance(*inst, - Vec2d{random_value(-200., 200.), - random_value(-200., 200.)}, + Vec2d{random_value(-arr2::UnscaledCoordLimit / 10., arr2::UnscaledCoordLimit / 10.), + random_value(-arr2::UnscaledCoordLimit / 10., arr2::UnscaledCoordLimit / 10.)}, random_value(0., 2 * PI)); } @@ -168,7 +168,8 @@ TEMPLATE_TEST_CASE("Writing arrange transformations into ModelInstance should be { auto [tx, ty, rot] = GENERATE(map( [](int i) { - return std::make_tuple(-500. + i * 20., -500. + i * 20., + return std::make_tuple(-Slic3r::arr2::UnscaledCoordLimit / 2. + i * Slic3r::arr2::UnscaledCoordLimit / 100., + -Slic3r::arr2::UnscaledCoordLimit / 2. + i * Slic3r::arr2::UnscaledCoordLimit / 100., -PI + i * (2 * PI / 100.)); }, range(0, 100))); diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index 8f9367ce51..fa41f88e2f 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -228,7 +228,7 @@ void init_print(std::vector &&meshes, Slic3r::Print &print, Slic3r object->add_volume(std::move(t)); object->add_instance(); } - arrange_objects(model, arr2::InfiniteBed{}, arr2::ArrangeSettings{}.set_distance_from_objects(min_object_distance(config))); + arrange_objects(model, arr2::to_arrange_bed(get_bed_shape(config)), arr2::ArrangeSettings{}.set_distance_from_objects(min_object_distance(config))); model.center_instances_around_point({100, 100}); for (ModelObject *mo : model.objects) { mo->ensure_on_bed(); diff --git a/tests/fff_print/test_model.cpp b/tests/fff_print/test_model.cpp index d59a655663..243cb10d1d 100644 --- a/tests/fff_print/test_model.cpp +++ b/tests/fff_print/test_model.cpp @@ -42,8 +42,12 @@ SCENARIO("Model construction", "[Model]") { } } model_object->add_instance(); - arrange_objects(model, arr2::InfiniteBed{scaled(Vec2d(100, 100))}, arr2::ArrangeSettings{}.set_distance_from_objects(min_object_distance(config))); - model_object->ensure_on_bed(); + arrange_objects(model, + arr2::to_arrange_bed(get_bed_shape(config)), + arr2::ArrangeSettings{}.set_distance_from_objects( + min_object_distance(config))); + + model_object->ensure_on_bed(); print.auto_assign_extruders(model_object); THEN("Print works?") { print.set_status_silent();