diff --git a/src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp b/src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp index ba4f503c76..df3572deaf 100644 --- a/src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp +++ b/src/libslic3r/Arrange/Core/NFP/Kernels/GravityKernel.hpp @@ -19,7 +19,7 @@ struct GravityKernel { template double placement_fitness(const ArrItem &itm, const Vec2crd &transl) const { - Vec2d center = unscaled(envelope_bounding_box(itm).center()); + Vec2d center = unscaled(envelope_centroid(itm)); center += unscaled(transl); diff --git a/src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp b/src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp index f5dba769d5..dd7742bff5 100644 --- a/src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp +++ b/src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp @@ -65,6 +65,8 @@ public: // Candidate item bounding box auto ibb = envelope_bounding_box(item); ibb.translate(transl); + auto itmcntr = envelope_centroid(item); + itmcntr += transl; // Calculate the full bounding box of the pile with the candidate item auto fullbb = m_pilebb; @@ -115,7 +117,7 @@ public: switch (compute_case) { case WIPE_TOWER: { - score = (unscaled(ibb.center()) - unscaled(active_sink)).squaredNorm(); + score = (unscaled(itmcntr) - unscaled(active_sink)).squaredNorm(); break; } case BIG_ITEM: { @@ -132,7 +134,7 @@ public: auto cc = fullbb.center(); // The gravity center dists[0] = (minc - cc).cast().norm(); dists[1] = (maxc - cc).cast().norm(); - dists[2] = (ibb.center() - cc).template cast().norm(); + dists[2] = (itmcntr - cc).template cast().norm(); dists[3] = (top_left - cc).cast().norm(); dists[4] = (bottom_right - cc).cast().norm(); @@ -191,7 +193,7 @@ public: break; } case LAST_BIG_ITEM: { - score = norm((ibb.center() - m_pilebb.center()).template cast().norm()); + score = norm((itmcntr - m_pilebb.center()).template cast().norm()); break; } case SMALL_ITEM: { @@ -199,7 +201,7 @@ public: // already processed bigger items. // No need to play around with the anchor points, the center will be // just fine for small items - score = norm((ibb.center() - bigbb.center()).template cast().norm()); + score = norm((itmcntr - bigbb.center()).template cast().norm()); break; } } diff --git a/src/libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp b/src/libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp index 009162661c..002d3df6fe 100644 --- a/src/libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp +++ b/src/libslic3r/Arrange/Core/NFP/NFPArrangeItemTraits.hpp @@ -74,6 +74,16 @@ template struct NFPArrangeItemTraits_ { return std::array{0.}; } + + static Vec2crd fixed_centroid(const ArrItem &itm) + { + return fixed_bounding_box(itm).center(); + } + + static Vec2crd envelope_centroid(const ArrItem &itm) + { + return envelope_bounding_box(itm).center(); + } }; template @@ -137,6 +147,16 @@ template double fixed_area(const ArrItem &itm) return NFPArrangeItemTraits::fixed_area(itm); } +template Vec2crd fixed_centroid(const ArrItem &itm) +{ + return NFPArrangeItemTraits::fixed_centroid(itm); +} + +template Vec2crd envelope_centroid(const ArrItem &itm) +{ + return NFPArrangeItemTraits::envelope_centroid(itm); +} + template auto allowed_rotations(const ArrItem &itm) { diff --git a/src/libslic3r/Arrange/Items/ArrangeItem.cpp b/src/libslic3r/Arrange/Items/ArrangeItem.cpp index ff8c761147..63d15e75a6 100644 --- a/src/libslic3r/Arrange/Items/ArrangeItem.cpp +++ b/src/libslic3r/Arrange/Items/ArrangeItem.cpp @@ -13,6 +13,8 @@ namespace Slic3r { namespace arr2 { const Polygons &DecomposedShape::transformed_outline() const { + constexpr auto sc = scaled(1.) * scaled(1.); + if (!m_transformed_outline_valid) { m_transformed_outline = contours(); for (Polygon &poly : m_transformed_outline) { @@ -20,7 +22,6 @@ const Polygons &DecomposedShape::transformed_outline() const poly.translate(translation()); } - auto sc = scaled(1.) * scaled(1.); m_area = std::accumulate(m_transformed_outline.begin(), m_transformed_outline.end(), 0., [sc](double s, const auto &p) { @@ -88,6 +89,29 @@ const Vec2crd &DecomposedShape::min_vertex(size_t idx) const return m_mins[idx]; } +Vec2crd DecomposedShape::centroid() const +{ + constexpr double area_sc = scaled(1.) * scaled(1.); + + if (!m_centroid_valid) { + double total_area = 0.0; + Vec2d cntr = Vec2d::Zero(); + + for (const Polygon& poly : transformed_outline()) { + double parea = poly.area() / area_sc; + Vec2d pcntr = unscaled(poly.centroid()); + total_area += parea; + cntr += pcntr * parea; + } + + cntr /= total_area; + m_centroid = scaled(cntr); + m_centroid_valid = true; + } + + return m_centroid; +} + DecomposedShape decompose(const ExPolygons &shape) { ExPolygons shape_s = expolygons_simplify(shape, scaled(.2)); diff --git a/src/libslic3r/Arrange/Items/ArrangeItem.hpp b/src/libslic3r/Arrange/Items/ArrangeItem.hpp index 1fb276a6be..5362431e49 100644 --- a/src/libslic3r/Arrange/Items/ArrangeItem.hpp +++ b/src/libslic3r/Arrange/Items/ArrangeItem.hpp @@ -55,6 +55,9 @@ class DecomposedShape mutable std::vector m_mins; mutable bool m_reference_vertex_valid = false; + mutable Point m_centroid; + mutable bool m_centroid_valid = false; + mutable Polygon m_convex_hull; mutable BoundingBox m_bounding_box; mutable double m_area = 0; @@ -87,6 +90,7 @@ public: m_translation = v; m_transformed_outline_valid = false; m_reference_vertex_valid = false; + m_centroid_valid = false; } void rotation(double v) @@ -94,6 +98,7 @@ public: m_rotation = v; m_transformed_outline_valid = false; m_reference_vertex_valid = false; + m_centroid_valid = false; } const Polygons &transformed_outline() const; @@ -115,6 +120,8 @@ public: return m_area; } + + Vec2crd centroid() const; }; DecomposedShape decompose(const ExPolygons &polys); @@ -188,6 +195,8 @@ public: { m_shape.reference_vertex(); m_envelope->reference_vertex(); + m_shape.centroid(); + m_envelope->centroid(); } }; @@ -412,6 +421,16 @@ template<> struct NFPArrangeItemTraits_ { return *ret_ptr; } + + static Vec2crd fixed_centroid(const ArrangeItem &itm) + { + return itm.shape().centroid(); + } + + static Vec2crd envelope_centroid(const ArrangeItem &itm) + { + return itm.envelope().centroid(); + } }; template<> struct IsWritableItem_: public std::true_type {}; diff --git a/src/libslic3r/Arrange/Items/SimpleArrangeItem.hpp b/src/libslic3r/Arrange/Items/SimpleArrangeItem.hpp index 4f321c93b0..1d924c1861 100644 --- a/src/libslic3r/Arrange/Items/SimpleArrangeItem.hpp +++ b/src/libslic3r/Arrange/Items/SimpleArrangeItem.hpp @@ -138,6 +138,16 @@ template<> struct NFPArrangeItemTraits_ { return itm.allowed_rotations(); } + + static Vec2crd fixed_centroid(const SimpleArrangeItem &itm) noexcept + { + return itm.shape().centroid(); + } + + static Vec2crd envelope_centroid(const SimpleArrangeItem &itm) noexcept + { + return itm.shape().centroid(); + } }; template<> struct IsWritableItem_: public std::true_type {};