From fec5d92bc8a337492dc4ba7ca3d8e74f658d5a56 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 24 Sep 2021 14:07:46 +0200 Subject: [PATCH] Added various has_duplicate_points() checks, to be used by asserts. Removed some "extern" function modifiers, they have no meaning in C++. --- src/libslic3r/ClipperUtils.cpp | 39 ++++++++++++++++++++++ src/libslic3r/ExPolygon.cpp | 60 +++++++++++++++++++++++++++++++--- src/libslic3r/ExPolygon.hpp | 20 +++++++----- src/libslic3r/Point.cpp | 9 +++++ src/libslic3r/Point.hpp | 30 +++++++++++++++-- src/libslic3r/Polygon.cpp | 21 ++++++++++++ src/libslic3r/Polygon.hpp | 31 ++++++++++-------- 7 files changed, 183 insertions(+), 27 deletions(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index a1dd638cae..e8f87a6e3d 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -126,6 +126,45 @@ ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input) return PolyTreeToExPolygons(std::move(polytree)); } +#if 0 +// Global test. +bool has_duplicate_points(const ClipperLib::PolyTree &polytree) +{ + struct Helper { + static void collect_points_recursive(const ClipperLib::PolyNode &polynode, ClipperLib::Path &out) { + // For each hole of the current expolygon: + out.insert(out.end(), polynode.Contour.begin(), polynode.Contour.end()); + for (int i = 0; i < polynode.ChildCount(); ++ i) + collect_points_recursive(*polynode.Childs[i], out); + } + }; + ClipperLib::Path pts; + for (int i = 0; i < polytree.ChildCount(); ++ i) + Helper::collect_points_recursive(*polytree.Childs[i], pts); + return has_duplicate_points(std::move(pts)); +} +#else +// Local test inside each of the contours. +bool has_duplicate_points(const ClipperLib::PolyTree &polytree) +{ + struct Helper { + static bool has_duplicate_points_recursive(const ClipperLib::PolyNode &polynode) { + if (has_duplicate_points(polynode.Contour)) + return true; + for (int i = 0; i < polynode.ChildCount(); ++ i) + if (has_duplicate_points_recursive(*polynode.Childs[i])) + return true; + return false; + } + }; + ClipperLib::Path pts; + for (int i = 0; i < polytree.ChildCount(); ++ i) + if (Helper::has_duplicate_points_recursive(*polytree.Childs[i])) + return true; + return false; +} +#endif + // Offset outside by 10um, one by one. template static ClipperLib::Paths safety_offset(PathsProvider &&paths) diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 4a40c02c30..bfe0479fea 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -114,10 +114,11 @@ bool ExPolygon::contains(const Polylines &polylines) const bool ExPolygon::contains(const Point &point) const { - if (!this->contour.contains(point)) return false; - for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) { - if (it->contains(point)) return false; - } + if (! this->contour.contains(point)) + return false; + for (const Polygon &hole : this->holes) + if (hole.contains(point)) + return false; return true; } @@ -367,6 +368,57 @@ extern std::vector get_extents_vector(const ExPolygons &polygons) return out; } +bool has_duplicate_points(const ExPolygon &expoly) +{ +#if 1 + // Check globally. + size_t cnt = expoly.contour.points.size(); + for (const Polygon &hole : expoly.holes) + cnt += hole.points.size(); + std::vector allpts; + allpts.reserve(cnt); + allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end()); + for (const Polygon &hole : expoly.holes) + allpts.insert(allpts.end(), hole.points.begin(), hole.points.end()); + return has_duplicate_points(std::move(allpts)); +#else + // Check per contour. + if (has_duplicate_points(expoly.contour)) + return true; + for (const Polygon &hole : expoly.holes) + if (has_duplicate_points(hole)) + return true; + return false; +#endif +} + +bool has_duplicate_points(const ExPolygons &expolys) +{ +#if 1 + // Check globally. + size_t cnt = 0; + for (const ExPolygon &expoly : expolys) { + cnt += expoly.contour.points.size(); + for (const Polygon &hole : expoly.holes) + cnt += hole.points.size(); + } + std::vector allpts; + allpts.reserve(cnt); + for (const ExPolygon &expoly : expolys) { + allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end()); + for (const Polygon &hole : expoly.holes) + allpts.insert(allpts.end(), hole.points.begin(), hole.points.end()); + } + return has_duplicate_points(std::move(allpts)); +#else + // Check per contour. + for (const ExPolygon &expoly : expolys) + if (has_duplicate_points(expoly)) + return true; + return false; +#endif +} + bool remove_sticks(ExPolygon &poly) { return remove_sticks(poly.contour) || remove_sticks(poly.holes); diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 464310ac00..6f38846736 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -351,20 +351,24 @@ inline ExPolygons expolygons_simplify(const ExPolygons &expolys, double toleranc return out; } -extern BoundingBox get_extents(const ExPolygon &expolygon); -extern BoundingBox get_extents(const ExPolygons &expolygons); -extern BoundingBox get_extents_rotated(const ExPolygon &poly, double angle); -extern BoundingBox get_extents_rotated(const ExPolygons &polygons, double angle); -extern std::vector get_extents_vector(const ExPolygons &polygons); +BoundingBox get_extents(const ExPolygon &expolygon); +BoundingBox get_extents(const ExPolygons &expolygons); +BoundingBox get_extents_rotated(const ExPolygon &poly, double angle); +BoundingBox get_extents_rotated(const ExPolygons &polygons, double angle); +std::vector get_extents_vector(const ExPolygons &polygons); -extern bool remove_sticks(ExPolygon &poly); -extern void keep_largest_contour_only(ExPolygons &polygons); +// Test for duplicate points. The points are copied, sorted and checked for duplicates globally. +bool has_duplicate_points(const ExPolygon &expoly); +bool has_duplicate_points(const ExPolygons &expolys); + +bool remove_sticks(ExPolygon &poly); +void keep_largest_contour_only(ExPolygons &polygons); inline double area(const ExPolygon &poly) { return poly.area(); } inline double area(const ExPolygons &polys) { double s = 0.; for (auto &p : polys) s += p.area(); return s; } // Removes all expolygons smaller than min_area and also removes all holes smaller than min_area -extern bool remove_small_and_small_holes(ExPolygons &expolygons, double min_area); +bool remove_small_and_small_holes(ExPolygons &expolygons, double min_area); } // namespace Slic3r diff --git a/src/libslic3r/Point.cpp b/src/libslic3r/Point.cpp index 7f351d2598..b1f3a74bb0 100644 --- a/src/libslic3r/Point.cpp +++ b/src/libslic3r/Point.cpp @@ -179,6 +179,15 @@ Point Point::projection_onto(const Line &line) const return ((line.a - *this).cast().squaredNorm() < (line.b - *this).cast().squaredNorm()) ? line.a : line.b; } +bool has_duplicate_points(std::vector &&pts) +{ + std::sort(pts.begin(), pts.end()); + for (size_t i = 1; i < pts.size(); ++ i) + if (pts[i - 1] == pts[i]) + return true; + return false; +} + BoundingBox get_extents(const Points &pts) { return BoundingBox(pts); diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 21eb48c2ee..499ab073d4 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -211,8 +211,34 @@ inline Point lerp(const Point &a, const Point &b, double t) return ((1. - t) * a.cast() + t * b.cast()).cast(); } -extern BoundingBox get_extents(const Points &pts); -extern BoundingBox get_extents(const std::vector &pts); +BoundingBox get_extents(const Points &pts); +BoundingBox get_extents(const std::vector &pts); + +// Test for duplicate points in a vector of points. +// The points are copied, sorted and checked for duplicates globally. +bool has_duplicate_points(std::vector &&pts); +inline bool has_duplicate_points(const std::vector &pts) +{ + std::vector cpy = pts; + return has_duplicate_points(std::move(cpy)); +} + +// Test for duplicate points in a vector of points. +// Only successive points are checked for equality. +inline bool has_duplicate_successive_points(const std::vector &pts) +{ + for (size_t i = 1; i < pts.size(); ++ i) + if (pts[i - 1] == pts[i]) + return true; + return false; +} + +// Test for duplicate points in a vector of points. +// Only successive points are checked for equality. Additionally, first and last points are compared for equality. +inline bool has_duplicate_successive_points_closed(const std::vector &pts) +{ + return has_duplicate_successive_points(pts) || (pts.size() >= 2 && pts.front() == pts.back()); +} namespace int128 { // Exact orientation predicate, diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 5b180afcac..42a6cc2095 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -334,6 +334,27 @@ extern std::vector get_extents_vector(const Polygons &polygons) return out; } +bool has_duplicate_points(const Polygons &polys) +{ +#if 1 + // Check globally. + size_t cnt = 0; + for (const Polygon &poly : polys) + cnt += poly.points.size(); + std::vector allpts; + allpts.reserve(cnt); + for (const Polygon &poly : polys) + allpts.insert(allpts.end(), poly.points.begin(), poly.points.end()); + return has_duplicate_points(std::move(allpts)); +#else + // Check per contour. + for (const Polygon &poly : polys) + if (has_duplicate_points(poly)) + return true; + return false; +#endif +} + static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3) { Point v1 = p2 - p1; diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 3c46a564b2..29800a31d4 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -78,11 +78,16 @@ public: inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; } inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; } -extern BoundingBox get_extents(const Polygon &poly); -extern BoundingBox get_extents(const Polygons &polygons); -extern BoundingBox get_extents_rotated(const Polygon &poly, double angle); -extern BoundingBox get_extents_rotated(const Polygons &polygons, double angle); -extern std::vector get_extents_vector(const Polygons &polygons); +BoundingBox get_extents(const Polygon &poly); +BoundingBox get_extents(const Polygons &polygons); +BoundingBox get_extents_rotated(const Polygon &poly, double angle); +BoundingBox get_extents_rotated(const Polygons &polygons, double angle); +std::vector get_extents_vector(const Polygons &polygons); + +// Test for duplicate points. The points are copied, sorted and checked for duplicates globally. +inline bool has_duplicate_points(Polygon &&poly) { return has_duplicate_points(std::move(poly.points)); } +inline bool has_duplicate_points(const Polygon &poly) { return has_duplicate_points(poly.points); } +bool has_duplicate_points(const Polygons &polys); inline double total_length(const Polygons &polylines) { double total = 0; @@ -102,19 +107,19 @@ inline double area(const Polygons &polys) } // Remove sticks (tentacles with zero area) from the polygon. -extern bool remove_sticks(Polygon &poly); -extern bool remove_sticks(Polygons &polys); +bool remove_sticks(Polygon &poly); +bool remove_sticks(Polygons &polys); // Remove polygons with less than 3 edges. -extern bool remove_degenerate(Polygons &polys); -extern bool remove_small(Polygons &polys, double min_area); -extern void remove_collinear(Polygon &poly); -extern void remove_collinear(Polygons &polys); +bool remove_degenerate(Polygons &polys); +bool remove_small(Polygons &polys, double min_area); +void remove_collinear(Polygon &poly); +void remove_collinear(Polygons &polys); // Append a vector of polygons at the end of another vector of polygons. -inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); } +inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); } -inline void polygons_append(Polygons &dst, Polygons &&src) +inline void polygons_append(Polygons &dst, Polygons &&src) { if (dst.empty()) { dst = std::move(src);