From e4247f9856de0a928bce6bc1f86e4f47858feb90 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 24 Sep 2019 14:54:33 +0200 Subject: [PATCH] libslic3r core enhancements * ClipperUtils extended with ExPolygon to clipper paths conversion and improved PolyTree traversal * Added ExPolygon constructor with Polygon argument * Removed BoundingBox warnings on clang * Removed Geometry warnings on clang --- src/libslic3r/BoundingBox.hpp | 55 ++++++++--- src/libslic3r/ClipperUtils.cpp | 172 ++++++++++++++++++++++++++++----- src/libslic3r/ClipperUtils.hpp | 14 ++- src/libslic3r/ExPolygon.hpp | 3 + src/libslic3r/Geometry.hpp | 5 + 5 files changed, 210 insertions(+), 39 deletions(-) diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp index b1ebdcfbc..4fbe72163 100644 --- a/src/libslic3r/BoundingBox.hpp +++ b/src/libslic3r/BoundingBox.hpp @@ -15,7 +15,7 @@ public: PointClass max; bool defined; - BoundingBoxBase() : defined(false), min(PointClass::Zero()), max(PointClass::Zero()) {} + BoundingBoxBase() : min(PointClass::Zero()), max(PointClass::Zero()), defined(false) {} BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) : min(pmin), max(pmax), defined(pmin(0) < pmax(0) && pmin(1) < pmax(1)) {} BoundingBoxBase(const std::vector& points) : min(PointClass::Zero()), max(PointClass::Zero()) @@ -59,7 +59,7 @@ template class BoundingBox3Base : public BoundingBoxBase { public: - BoundingBox3Base() : BoundingBoxBase() {}; + BoundingBox3Base() : BoundingBoxBase() {} BoundingBox3Base(const PointClass &pmin, const PointClass &pmax) : BoundingBoxBase(pmin, pmax) { if (pmin(2) >= pmax(2)) BoundingBoxBase::defined = false; } @@ -100,6 +100,33 @@ public: } }; +// Will prevent warnings caused by non existing definition of template in hpp +extern template void BoundingBoxBase::scale(double factor); +extern template void BoundingBoxBase::scale(double factor); +extern template void BoundingBoxBase::scale(double factor); +extern template void BoundingBoxBase::offset(coordf_t delta); +extern template void BoundingBoxBase::offset(coordf_t delta); +extern template void BoundingBoxBase::merge(const Point &point); +extern template void BoundingBoxBase::merge(const Vec2d &point); +extern template void BoundingBoxBase::merge(const Points &points); +extern template void BoundingBoxBase::merge(const Pointfs &points); +extern template void BoundingBoxBase::merge(const BoundingBoxBase &bb); +extern template void BoundingBoxBase::merge(const BoundingBoxBase &bb); +extern template Point BoundingBoxBase::size() const; +extern template Vec2d BoundingBoxBase::size() const; +extern template double BoundingBoxBase::radius() const; +extern template double BoundingBoxBase::radius() const; +extern template Point BoundingBoxBase::center() const; +extern template Vec2d BoundingBoxBase::center() const; +extern template void BoundingBox3Base::merge(const Vec3d &point); +extern template void BoundingBox3Base::merge(const Pointf3s &points); +extern template void BoundingBox3Base::merge(const BoundingBox3Base &bb); +extern template Vec3d BoundingBox3Base::size() const; +extern template double BoundingBox3Base::radius() const; +extern template void BoundingBox3Base::offset(coordf_t delta); +extern template Vec3d BoundingBox3Base::center() const; +extern template coordf_t BoundingBox3Base::max_size() const; + class BoundingBox : public BoundingBoxBase { public: @@ -113,9 +140,9 @@ public: // to encompass the original bounding box. void align_to_grid(const coord_t cell_size); - BoundingBox() : BoundingBoxBase() {}; - BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase(pmin, pmax) {}; - BoundingBox(const Points &points) : BoundingBoxBase(points) {}; + BoundingBox() : BoundingBoxBase() {} + BoundingBox(const Point &pmin, const Point &pmax) : BoundingBoxBase(pmin, pmax) {} + BoundingBox(const Points &points) : BoundingBoxBase(points) {} BoundingBox(const Lines &lines); friend BoundingBox get_extents_rotated(const Points &points, double angle); @@ -124,25 +151,25 @@ public: class BoundingBox3 : public BoundingBox3Base { public: - BoundingBox3() : BoundingBox3Base() {}; - BoundingBox3(const Vec3crd &pmin, const Vec3crd &pmax) : BoundingBox3Base(pmin, pmax) {}; - BoundingBox3(const Points3& points) : BoundingBox3Base(points) {}; + BoundingBox3() : BoundingBox3Base() {} + BoundingBox3(const Vec3crd &pmin, const Vec3crd &pmax) : BoundingBox3Base(pmin, pmax) {} + BoundingBox3(const Points3& points) : BoundingBox3Base(points) {} }; class BoundingBoxf : public BoundingBoxBase { public: - BoundingBoxf() : BoundingBoxBase() {}; - BoundingBoxf(const Vec2d &pmin, const Vec2d &pmax) : BoundingBoxBase(pmin, pmax) {}; - BoundingBoxf(const std::vector &points) : BoundingBoxBase(points) {}; + BoundingBoxf() : BoundingBoxBase() {} + BoundingBoxf(const Vec2d &pmin, const Vec2d &pmax) : BoundingBoxBase(pmin, pmax) {} + BoundingBoxf(const std::vector &points) : BoundingBoxBase(points) {} }; class BoundingBoxf3 : public BoundingBox3Base { public: - BoundingBoxf3() : BoundingBox3Base() {}; - BoundingBoxf3(const Vec3d &pmin, const Vec3d &pmax) : BoundingBox3Base(pmin, pmax) {}; - BoundingBoxf3(const std::vector &points) : BoundingBox3Base(points) {}; + BoundingBoxf3() : BoundingBox3Base() {} + BoundingBoxf3(const Vec3d &pmin, const Vec3d &pmax) : BoundingBox3Base(pmin, pmax) {} + BoundingBoxf3(const std::vector &points) : BoundingBox3Base(points) {} BoundingBoxf3 transformed(const Transform3d& matrix) const; }; diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index c3183bd8e..b863b4712 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -194,6 +194,19 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polygons &input) return retval; } +ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const ExPolygons &input) +{ + ClipperLib::Paths retval; + for (auto &ep : input) { + retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(ep.contour)); + + for (auto &h : ep.holes) + retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(h)); + } + + return retval; +} + ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input) { ClipperLib::Paths retval; @@ -472,14 +485,16 @@ ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, return union_ex(polys); } -template -T -_clipper_do(const ClipperLib::ClipType clipType, const Polygons &subject, - const Polygons &clip, const ClipperLib::PolyFillType fillType, const bool safety_offset_) +template +T _clipper_do(const ClipperLib::ClipType clipType, + TSubj && subject, + TClip && clip, + const ClipperLib::PolyFillType fillType, + const bool safety_offset_) { // read input - ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); - ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip); + ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(std::forward(subject)); + ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(std::forward(clip)); // perform safety offset if (safety_offset_) { @@ -648,12 +663,26 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons return retval; } -ClipperLib::PolyTree -union_pt(const Polygons &subject, bool safety_offset_) +ClipperLib::PolyTree union_pt(const Polygons &subject, bool safety_offset_) { return _clipper_do(ClipperLib::ctUnion, subject, Polygons(), ClipperLib::pftEvenOdd, safety_offset_); } +ClipperLib::PolyTree union_pt(const ExPolygons &subject, bool safety_offset_) +{ + return _clipper_do(ClipperLib::ctUnion, subject, Polygons(), ClipperLib::pftEvenOdd, safety_offset_); +} + +ClipperLib::PolyTree union_pt(Polygons &&subject, bool safety_offset_) +{ + return _clipper_do(ClipperLib::ctUnion, std::move(subject), Polygons(), ClipperLib::pftEvenOdd, safety_offset_); +} + +ClipperLib::PolyTree union_pt(ExPolygons &&subject, bool safety_offset_) +{ + return _clipper_do(ClipperLib::ctUnion, std::move(subject), Polygons(), ClipperLib::pftEvenOdd, safety_offset_); +} + Polygons union_pt_chained(const Polygons &subject, bool safety_offset_) { @@ -664,28 +693,123 @@ union_pt_chained(const Polygons &subject, bool safety_offset_) return retval; } -void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval) +static ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes) +{ + // collect ordering points + Points ordering_points; + ordering_points.reserve(nodes.size()); + for (const ClipperLib::PolyNode *node : nodes) + ordering_points.emplace_back(Point(node->Contour.front().X, node->Contour.front().Y)); + + // perform the ordering + ClipperLib::PolyNodes ordered_nodes = chain_clipper_polynodes(ordering_points, nodes); + + return ordered_nodes; +} + +enum class e_ordering { + ORDER_POLYNODES, + DONT_ORDER_POLYNODES +}; + +template +void foreach_node(const ClipperLib::PolyNodes &nodes, + std::function fn); + +template<> void foreach_node( + const ClipperLib::PolyNodes & nodes, + std::function fn) +{ + for (auto &n : nodes) fn(n); +} + +template<> void foreach_node( + const ClipperLib::PolyNodes & nodes, + std::function fn) +{ + auto ordered_nodes = order_nodes(nodes); + for (auto &n : ordered_nodes) fn(n); +} + +template +void _traverse_pt(const ClipperLib::PolyNodes &nodes, Polygons *retval) { /* use a nearest neighbor search to order these children TODO: supply start_near to chained_path() too? */ - // collect ordering points - Points ordering_points; - ordering_points.reserve(nodes.size()); - for (ClipperLib::PolyNode *pn : nodes) - ordering_points.emplace_back(Point(pn->Contour.front().X, pn->Contour.front().Y)); - - // perform the ordering - ClipperLib::PolyNodes ordered_nodes = chain_clipper_polynodes(ordering_points, nodes); - // push results recursively - for (ClipperLib::PolyNode *pn : ordered_nodes) { + foreach_node(nodes, [&retval](const ClipperLib::PolyNode *node) { // traverse the next depth - traverse_pt(pn->Childs, retval); - retval->emplace_back(ClipperPath_to_Slic3rPolygon(pn->Contour)); - if (pn->IsHole()) - retval->back().reverse(); // ccw - } + _traverse_pt(node->Childs, retval); + retval->emplace_back(ClipperPath_to_Slic3rPolygon(node->Contour)); + if (node->IsHole()) retval->back().reverse(); // ccw + }); +} + +template +void _traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *retval) +{ + if (!retval || !tree) return; + + ExPolygons &retv = *retval; + + std::function hole_fn; + + auto contour_fn = [&retv, &hole_fn](const ClipperLib::PolyNode *pptr) { + ExPolygon poly; + poly.contour.points = ClipperPath_to_Slic3rPolygon(pptr->Contour); + auto fn = std::bind(hole_fn, std::placeholders::_1, poly); + foreach_node(pptr->Childs, fn); + retv.push_back(poly); + }; + + hole_fn = [&contour_fn](const ClipperLib::PolyNode *pptr, ExPolygon& poly) + { + poly.holes.emplace_back(); + poly.holes.back().points = ClipperPath_to_Slic3rPolygon(pptr->Contour); + foreach_node(pptr->Childs, contour_fn); + }; + + contour_fn(tree); +} + +template +void _traverse_pt(const ClipperLib::PolyNodes &nodes, ExPolygons *retval) +{ + // Here is the actual traverse + foreach_node(nodes, [&retval](const ClipperLib::PolyNode *node) { + _traverse_pt(node, retval); + }); +} + +void traverse_pt(const ClipperLib::PolyNode *tree, ExPolygons *retval) +{ + _traverse_pt(tree, retval); +} + +void traverse_pt_unordered(const ClipperLib::PolyNode *tree, ExPolygons *retval) +{ + _traverse_pt(tree, retval); +} + +void traverse_pt(const ClipperLib::PolyNodes &nodes, Polygons *retval) +{ + _traverse_pt(nodes, retval); +} + +void traverse_pt(const ClipperLib::PolyNodes &nodes, ExPolygons *retval) +{ + _traverse_pt(nodes, retval); +} + +void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Polygons *retval) +{ + _traverse_pt(nodes, retval); +} + +void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, ExPolygons *retval) +{ + _traverse_pt(nodes, retval); } Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear) diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index 0e58d7fac..d8f8a8f94 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -34,6 +34,7 @@ Slic3r::ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree& polytree); ClipperLib::Path Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input); ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polygons &input); +ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const ExPolygons &input); ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input); Slic3r::Polygon ClipperPath_to_Slic3rPolygon(const ClipperLib::Path &input); Slic3r::Polyline ClipperPath_to_Slic3rPolyline(const ClipperLib::Path &input); @@ -215,8 +216,19 @@ inline Slic3r::ExPolygons union_ex(const Slic3r::Surfaces &subject, bool safety_ ClipperLib::PolyTree union_pt(const Slic3r::Polygons &subject, bool safety_offset_ = false); +ClipperLib::PolyTree union_pt(const Slic3r::ExPolygons &subject, bool safety_offset_ = false); +ClipperLib::PolyTree union_pt(Slic3r::Polygons &&subject, bool safety_offset_ = false); +ClipperLib::PolyTree union_pt(Slic3r::ExPolygons &&subject, bool safety_offset_ = false); + Slic3r::Polygons union_pt_chained(const Slic3r::Polygons &subject, bool safety_offset_ = false); -void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons* retval); + +void traverse_pt(const ClipperLib::PolyNodes &nodes, Slic3r::Polygons *retval); +void traverse_pt(const ClipperLib::PolyNodes &nodes, Slic3r::ExPolygons *retval); +void traverse_pt(const ClipperLib::PolyNode *tree, Slic3r::ExPolygons *retval); + +void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Slic3r::Polygons *retval); +void traverse_pt_unordered(const ClipperLib::PolyNodes &nodes, Slic3r::ExPolygons *retval); +void traverse_pt_unordered(const ClipperLib::PolyNode *tree, Slic3r::ExPolygons *retval); /* OTHER */ Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject, bool preserve_collinear = false); diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index afbc0931e..a7ef2784c 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -24,6 +24,9 @@ public: ExPolygon& operator=(const ExPolygon &other) { contour = other.contour; holes = other.holes; return *this; } ExPolygon& operator=(ExPolygon &&other) { contour = std::move(other.contour); holes = std::move(other.holes); return *this; } + inline explicit ExPolygon(const Polygon &p): contour(p) {} + inline explicit ExPolygon(Polygon &&p): contour(std::move(p)) {} + Polygon contour; Polygons holes; diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index a574209d8..394a6e502 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -14,6 +14,11 @@ using boost::polygon::voronoi_builder; using boost::polygon::voronoi_diagram; +namespace ClipperLib { +class PolyNode; +using PolyNodes = std::vector; +} + namespace Slic3r { namespace Geometry { // Generic result of an orientation predicate.