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..d827be3df6 100644 --- a/src/libslic3r/Arrange/ArrangeImpl.hpp +++ b/src/libslic3r/Arrange/ArrangeImpl.hpp @@ -370,6 +370,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 +422,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/SceneBuilder.cpp b/src/libslic3r/Arrange/SceneBuilder.cpp index a6e37c0b74..bf77dcd948 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,11 +83,32 @@ 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) +{ + constexpr double hi = 1000.; + + return std::abs(bb.min.x()) < hi && + std::abs(bb.min.y()) < hi && + std::abs(bb.max.x()) < hi && + std::abs(bb.max.y()) < hi; +} + ExPolygons extract_full_outline(const ModelInstance &inst, const Transform3d &tr) { ExPolygons outline; for (const ModelVolume *v : inst.get_object()->volumes) { Polygons vol_outline; + + if (!check_coord_bounds(to_2d(v->mesh().transformed_bounding_box(tr)))) { + outline.clear(); + break; + } + vol_outline = project_mesh(v->mesh().its, tr * inst.get_matrix() * v->get_matrix(), [] {}); @@ -105,7 +128,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 @@ -190,7 +220,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 +268,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; @@ -274,7 +318,8 @@ Vec2i GridStriderVBedHandler::raw2grid(int bed_idx) const int GridStriderVBedHandler::grid2raw(const Vec2i &crd) const { - assert(crd.x() < ColsOutside - 1 && crd.y() < ColsOutside - 1); + assert(std::abs(crd.x()) < ColsOutside - 1 && + std::abs(crd.y()) < ColsOutside - 1); return crd.y() * ColsOutside + crd.x(); } diff --git a/src/libslic3r/Arrange/SceneBuilder.hpp b/src/libslic3r/Arrange/SceneBuilder.hpp index c19bd6ed69..f056ed3ff2 100644 --- a/src/libslic3r/Arrange/SceneBuilder.hpp +++ b/src/libslic3r/Arrange/SceneBuilder.hpp @@ -377,6 +377,9 @@ 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); ExPolygons extract_full_outline(const ModelInstance &inst, const Transform3d &tr = Transform3d::Identity()); diff --git a/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp b/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp index c9f48f93e4..8925ea4b95 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 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(); } };