From 9bb5bdb80f498315da1824cde0d979ae7c2e5f13 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 15 Aug 2023 17:03:41 +0200 Subject: [PATCH] Fixing crashes with objects residing at large world coordinate values fixes issue SPE-1844 --- src/libslic3r/Arrange/SceneBuilder.cpp | 45 +++++++++++++++++++++- src/libslic3r/Arrange/SceneBuilder.hpp | 29 ++++++++++++++ tests/arrange/test_arrange_integration.cpp | 18 ++++++--- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/Arrange/SceneBuilder.cpp b/src/libslic3r/Arrange/SceneBuilder.cpp index f2bbc38876..e661eee30f 100644 --- a/src/libslic3r/Arrange/SceneBuilder.cpp +++ b/src/libslic3r/Arrange/SceneBuilder.cpp @@ -262,6 +262,47 @@ Transform3d YStriderVBedHandler::get_physical_bed_trafo(int bed_index) const return tr; } +Vec2i GridStriderVBedHandler::raw2grid(int bed_idx) const +{ + Vec2i ret{bed_idx % ColsOutside, bed_idx / ColsOutside}; + + return ret; +} + +int GridStriderVBedHandler::grid2raw(const Vec2i &crd) const +{ + assert(crd.x() < ColsOutside - 1 && crd.y() < ColsOutside - 1); + + return crd.y() * ColsOutside + crd.x(); +} + +int GridStriderVBedHandler::get_bed_index(const VBedPlaceable &obj) const +{ + Vec2i crd = {m_xstrider.get_bed_index(obj), m_ystrider.get_bed_index(obj)}; + + return grid2raw(crd); +} + +bool GridStriderVBedHandler::assign_bed(VBedPlaceable &inst, int bed_idx) +{ + Vec2i crd = raw2grid(bed_idx); + + bool retx = m_xstrider.assign_bed(inst, crd.x()); + bool rety = m_ystrider.assign_bed(inst, crd.y()); + + return retx && rety; +} + +Transform3d GridStriderVBedHandler::get_physical_bed_trafo(int bed_idx) const +{ + Vec2i crd = raw2grid(bed_idx); + + Transform3d ret = m_xstrider.get_physical_bed_trafo(crd.x()) * + m_ystrider.get_physical_bed_trafo(crd.y()); + + return ret; +} + FixedSelection::FixedSelection(const Model &m) : m_wp{true} { m_seldata.resize(m.objects.size()); @@ -805,7 +846,7 @@ std::unique_ptr VirtualBedHandler::create(const ExtendedBed & if (is_infinite_bed(bed)) { ret = std::make_unique(); } else { - // The gap between logical beds in the x axis expressed in ratio of + // The gap between logical beds expressed in ratio of // the current bed width. constexpr double LogicalBedGap = 1. / 10.; @@ -814,7 +855,7 @@ std::unique_ptr VirtualBedHandler::create(const ExtendedBed & auto bedwidth = bedbb.size().x(); coord_t xgap = LogicalBedGap * bedwidth; - ret = std::make_unique(bedbb, xgap); + ret = std::make_unique(bedbb, xgap); } return ret; diff --git a/src/libslic3r/Arrange/SceneBuilder.hpp b/src/libslic3r/Arrange/SceneBuilder.hpp index 4fdd74eb19..8315424ba6 100644 --- a/src/libslic3r/Arrange/SceneBuilder.hpp +++ b/src/libslic3r/Arrange/SceneBuilder.hpp @@ -330,6 +330,35 @@ public: Transform3d get_physical_bed_trafo(int bed_index) const override; }; +class GridStriderVBedHandler: public VirtualBedHandler +{ + // This vbed handler defines a grid of virtual beds with a large number + // of columns so that it behaves as XStrider for regular cases. + // The goal is to handle objects residing at world coordinates + // 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 = std::sqrt(std::numeric_limits::max()); + + XStriderVBedHandler m_xstrider; + YStriderVBedHandler m_ystrider; + +public: + GridStriderVBedHandler(const BoundingBox &bedbb, + coord_t gap) + : m_xstrider{bedbb, gap} + , m_ystrider{bedbb, gap} + {} + + Vec2i raw2grid(int bedidx) const; + int grid2raw(const Vec2i &crd) const; + + int get_bed_index(const VBedPlaceable &obj) const override; + bool assign_bed(VBedPlaceable &inst, int bed_idx) override; + + Transform3d get_physical_bed_trafo(int bed_index) const override; +}; + std::vector selected_object_indices(const SelectionMask &sm); std::vector selected_instance_indices(int obj_idx, const SelectionMask &sm); diff --git a/tests/arrange/test_arrange_integration.cpp b/tests/arrange/test_arrange_integration.cpp index f5dc761f00..b60b87fce9 100644 --- a/tests/arrange/test_arrange_integration.cpp +++ b/tests/arrange/test_arrange_integration.cpp @@ -326,10 +326,18 @@ auto create_vbed_handler(const Slic3r::Boundi return Slic3r::arr2::YStriderVBedHandler{bedbb, gap}; } -TEMPLATE_TEST_CASE("Common virtual bed handlers", "[arrange2][integration][vbeds]", - Slic3r::arr2::PhysicalOnlyVBedHandler, - Slic3r::arr2::XStriderVBedHandler, - Slic3r::arr2::YStriderVBedHandler) +template<> +auto create_vbed_handler(const Slic3r::BoundingBox &bedbb, coord_t gap) +{ + return Slic3r::arr2::GridStriderVBedHandler{bedbb, gap}; +} + +TEMPLATE_TEST_CASE("Common virtual bed handlers", + "[arrange2][integration][vbeds]", + Slic3r::arr2::PhysicalOnlyVBedHandler, + Slic3r::arr2::XStriderVBedHandler, + Slic3r::arr2::YStriderVBedHandler, + Slic3r::arr2::GridStriderVBedHandler) { using namespace Slic3r; using VBP = arr2::VBedPlaceableMI; @@ -413,7 +421,7 @@ TEMPLATE_TEST_CASE("Common virtual bed handlers", "[arrange2][integration][vbeds WHEN ("moving back to the physical bed") { auto &mi_back_to_phys = *model.objects.front()->add_instance(mi_to_move); - bool moved_back_to_physical = vbedh->assign_bed(VBP{mi_back_to_phys}, 0); + bool moved_back_to_physical = vbedh->assign_bed(VBP{mi_back_to_phys}, arr2::PhysicalBedId); THEN("model instance should actually move back to the physical bed") {