From fd437dcaf5f392dffb15eadcd359a4de92d0000b Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 2 May 2023 15:48:24 +0200 Subject: [PATCH] Little refactoring of douglas_peucker() --- src/libslic3r/ExPolygon.cpp | 4 ++-- src/libslic3r/Geometry.cpp | 16 ++++++------- src/libslic3r/MultiPoint.cpp | 2 +- src/libslic3r/MultiPoint.hpp | 2 +- src/libslic3r/Polygon.cpp | 45 +++++++++++++++++++++++++----------- src/libslic3r/Polygon.hpp | 3 ++- src/libslic3r/Polyline.cpp | 2 +- 7 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 42f026e0b..19489bddb 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -184,14 +184,14 @@ Polygons ExPolygon::simplify_p(double tolerance) const { Polygon p = this->contour; p.points.push_back(p.points.front()); - p.points = MultiPoint::_douglas_peucker(p.points, tolerance); + p.points = MultiPoint::douglas_peucker(p.points, tolerance); p.points.pop_back(); pp.emplace_back(std::move(p)); } // holes for (Polygon p : this->holes) { p.points.push_back(p.points.front()); - p.points = MultiPoint::_douglas_peucker(p.points, tolerance); + p.points = MultiPoint::douglas_peucker(p.points, tolerance); p.points.pop_back(); pp.emplace_back(std::move(p)); } diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index 5542d73ee..f2860ea8e 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -52,15 +52,15 @@ template bool contains(const ExPolygons &vector, const Point &point); void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval) { - Polygons pp; - for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++it) { - Polygon p = *it; - p.points.push_back(p.points.front()); - p.points = MultiPoint::_douglas_peucker(p.points, tolerance); - p.points.pop_back(); - pp.push_back(p); + Polygons simplified_raw; + for (const Polygon &source_polygon : polygons) { + Points simplified = MultiPoint::douglas_peucker(to_polyline(source_polygon).points, tolerance); + if (simplified.size() > 3) { + simplified.pop_back(); + simplified_raw.push_back(Polygon{ std::move(simplified) }); + } } - *retval = Slic3r::simplify_polygons(pp); + *retval = Slic3r::simplify_polygons(simplified_raw); } double linint(double value, double oldmin, double oldmax, double newmin, double newmax) diff --git a/src/libslic3r/MultiPoint.cpp b/src/libslic3r/MultiPoint.cpp index bb4d62cc0..ce54a54c0 100644 --- a/src/libslic3r/MultiPoint.cpp +++ b/src/libslic3r/MultiPoint.cpp @@ -103,7 +103,7 @@ bool MultiPoint::remove_duplicate_points() return false; } -Points MultiPoint::_douglas_peucker(const Points &pts, const double tolerance) +Points MultiPoint::douglas_peucker(const Points &pts, const double tolerance) { Points result_pts; double tolerance_sq = tolerance * tolerance; diff --git a/src/libslic3r/MultiPoint.hpp b/src/libslic3r/MultiPoint.hpp index 4cf4b5e14..62b53255b 100644 --- a/src/libslic3r/MultiPoint.hpp +++ b/src/libslic3r/MultiPoint.hpp @@ -81,7 +81,7 @@ public: } } - static Points _douglas_peucker(const Points &points, const double tolerance); + static Points douglas_peucker(const Points &points, const double tolerance); static Points visivalingam(const Points& pts, const double& tolerance); inline auto begin() { return points.begin(); } diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 299e22adc..88ac1b03f 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -96,7 +96,7 @@ bool Polygon::make_clockwise() void Polygon::douglas_peucker(double tolerance) { this->points.push_back(this->points.front()); - Points p = MultiPoint::_douglas_peucker(this->points, tolerance); + Points p = MultiPoint::douglas_peucker(this->points, tolerance); p.pop_back(); this->points = std::move(p); } @@ -110,7 +110,7 @@ Polygons Polygon::simplify(double tolerance) const // on the whole polygon Points points = this->points; points.push_back(points.front()); - Polygon p(MultiPoint::_douglas_peucker(points, tolerance)); + Polygon p(MultiPoint::douglas_peucker(points, tolerance)); p.points.pop_back(); Polygons pp; @@ -577,23 +577,40 @@ void remove_collinear(Polygons &polys) remove_collinear(poly); } -Polygons polygons_simplify(const Polygons &source_polygons, double tolerance) +static inline void simplify_polygon_impl(const Points &points, double tolerance, bool strictly_simple, Polygons &out) +{ + Points simplified = MultiPoint::douglas_peucker(points, tolerance); + // then remove the last (repeated) point. + simplified.pop_back(); + // Simplify the decimated contour by ClipperLib. + bool ccw = ClipperLib::Area(simplified) > 0.; + for (Points& path : ClipperLib::SimplifyPolygons(ClipperUtils::SinglePathProvider(simplified), ClipperLib::pftNonZero, strictly_simple)) { + if (!ccw) + // ClipperLib likely reoriented negative area contours to become positive. Reverse holes back to CW. + std::reverse(path.begin(), path.end()); + out.emplace_back(std::move(path)); + } +} + +Polygons polygons_simplify(Polygons &&source_polygons, double tolerance, bool strictly_simple /* = true */) +{ + Polygons out; + out.reserve(source_polygons.size()); + for (Polygon &source_polygon : source_polygons) { + // Run Douglas / Peucker simplification algorithm on an open polyline (by repeating the first point at the end of the polyline), + source_polygon.points.emplace_back(source_polygon.points.front()); + simplify_polygon_impl(source_polygon.points, tolerance, strictly_simple, out); + } + return out; +} + +Polygons polygons_simplify(const Polygons &source_polygons, double tolerance, bool strictly_simple /* = true */) { Polygons out; out.reserve(source_polygons.size()); for (const Polygon &source_polygon : source_polygons) { // Run Douglas / Peucker simplification algorithm on an open polyline (by repeating the first point at the end of the polyline), - Points simplified = MultiPoint::_douglas_peucker(to_polyline(source_polygon).points, tolerance); - // then remove the last (repeated) point. - simplified.pop_back(); - // Simplify the decimated contour by ClipperLib. - bool ccw = ClipperLib::Area(simplified) > 0.; - for (Points &path : ClipperLib::SimplifyPolygons(ClipperUtils::SinglePathProvider(simplified), ClipperLib::pftNonZero)) { - if (! ccw) - // ClipperLib likely reoriented negative area contours to become positive. Reverse holes back to CW. - std::reverse(path.begin(), path.end()); - out.emplace_back(std::move(path)); - } + simplify_polygon_impl(to_polyline(source_polygon).points, tolerance, strictly_simple, out); } return out; } diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index bf4a087b0..e0c3958fd 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -149,7 +149,8 @@ inline void polygons_append(Polygons &dst, Polygons &&src) } } -Polygons polygons_simplify(const Polygons &polys, double tolerance); +Polygons polygons_simplify(Polygons &&polys, double tolerance, bool strictly_simple = true); +Polygons polygons_simplify(const Polygons &polys, double tolerance, bool strictly_simple = true); inline void polygons_rotate(Polygons &polys, double angle) { diff --git a/src/libslic3r/Polyline.cpp b/src/libslic3r/Polyline.cpp index 5743e38bd..524736575 100644 --- a/src/libslic3r/Polyline.cpp +++ b/src/libslic3r/Polyline.cpp @@ -110,7 +110,7 @@ Points Polyline::equally_spaced_points(double distance) const void Polyline::simplify(double tolerance) { - this->points = MultiPoint::_douglas_peucker(this->points, tolerance); + this->points = MultiPoint::douglas_peucker(this->points, tolerance); } #if 0