From da00cedc843a444fdf7b1da0ab2ec76242d2113d Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 18 Nov 2022 17:16:47 +0100 Subject: [PATCH] Fixed polygons_simplify() to correctly handle holes. This fixes some missing tree / organic supports in the middle of an object surrounded by walls all around. --- src/libslic3r/ClipperUtils.cpp | 2 +- src/libslic3r/Polygon.cpp | 32 +++++++++++++++++++++-------- src/libslic3r/Polygon.hpp | 37 ++++++++++++++++------------------ 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 7f90fd2f0..ea5015798 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -931,7 +931,7 @@ ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear if (! preserve_collinear) return union_ex(simplify_polygons(subject, false)); - ClipperLib::PolyTree polytree; + ClipperLib::PolyTree polytree; ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 717e25aed..d342f3d91 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -99,9 +99,11 @@ void Polygon::douglas_peucker(double tolerance) this->points = std::move(p); } -// this only works on CCW polygons as CW will be ripped out by Clipper's simplify_polygons() Polygons Polygon::simplify(double tolerance) const { + // Works on CCW polygons only, CW contour will be reoriented to CCW by Clipper's simplify_polygons()! + assert(this->is_counter_clockwise()); + // repeat first point at the end in order to apply Douglas-Peucker // on the whole polygon Points points = this->points; @@ -114,13 +116,6 @@ Polygons Polygon::simplify(double tolerance) const return simplify_polygons(pp); } -void Polygon::simplify(double tolerance, Polygons &polygons) const -{ - Polygons pp = this->simplify(tolerance); - polygons.reserve(polygons.size() + pp.size()); - polygons.insert(polygons.end(), pp.begin(), pp.end()); -} - // Only call this on convex polygons or it will return invalid results void Polygon::triangulate_convex(Polygons* polygons) const { @@ -562,6 +557,27 @@ void remove_collinear(Polygons &polys) remove_collinear(poly); } +Polygons polygons_simplify(const Polygons &source_polygons, double tolerance) +{ + 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)); + } + } + return out; +} + // Do polygons match? If they match, they must have the same topology, // however their contours may be rotated. bool polygons_match(const Polygon &l, const Polygon &r) diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 8a4a2ba0a..b0d33db53 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -67,8 +67,8 @@ public: bool on_boundary(const Point &point, double eps) const { return (this->point_projection(point) - point).cast().squaredNorm() < eps * eps; } + // Works on CCW polygons only, CW contour will be reoriented to CCW by Clipper's simplify_polygons()! Polygons simplify(double tolerance) const; - void simplify(double tolerance, Polygons &polygons) const; void densify(float min_length, std::vector* lengths = nullptr); void triangulate_convex(Polygons* polygons) const; Point centroid() const; @@ -148,14 +148,7 @@ inline void polygons_append(Polygons &dst, Polygons &&src) } } -inline Polygons polygons_simplify(const Polygons &polys, double tolerance) -{ - Polygons out; - out.reserve(polys.size()); - for (const Polygon &p : polys) - polygons_append(out, p.simplify(tolerance)); - return out; -} +Polygons polygons_simplify(const Polygons &polys, double tolerance); inline void polygons_rotate(Polygons &polys, double angle) { @@ -216,18 +209,22 @@ inline Lines to_lines(const Polygons &polys) return lines; } -inline Polylines to_polylines(const Polygons &polys) +inline Polyline to_polyline(const Polygon &polygon) { - Polylines polylines; - polylines.assign(polys.size(), Polyline()); - size_t idx = 0; - for (Polygons::const_iterator it = polys.begin(); it != polys.end(); ++ it) { - Polyline &pl = polylines[idx ++]; - pl.points = it->points; - pl.points.push_back(it->points.front()); - } - assert(idx == polylines.size()); - return polylines; + Polyline out; + out.points.reserve(polygon.size() + 1); + out.points.assign(polygon.points.begin(), polygon.points.end()); + out.points.push_back(polygon.points.front()); + return out; +} + +inline Polylines to_polylines(const Polygons &polygons) +{ + Polylines out; + out.reserve(polygons.size()); + for (const Polygon &polygon : polygons) + out.emplace_back(to_polyline(polygon)); + return out; } inline Polylines to_polylines(Polygons &&polys)