diff --git a/xs/src/libslic3r/Geometry.cpp b/xs/src/libslic3r/Geometry.cpp index 39b626ee31..aaf0352c99 100644 --- a/xs/src/libslic3r/Geometry.cpp +++ b/xs/src/libslic3r/Geometry.cpp @@ -195,47 +195,62 @@ using namespace boost::polygon; // provides also high() and low() namespace Slic3r { namespace Geometry { -static bool -sort_points (Point a, Point b) -{ - return (a.x < b.x) || (a.x == b.x && a.y < b.y); -} +struct SortPoints { + template + bool operator()(const T& a, const T& b) const { + return (b.x > a.x) || (a.x == b.x && b.y > a.y); + } +}; -/* This implementation is based on Andrew's monotone chain 2D convex hull algorithm */ -Polygon -convex_hull(Points points) +// This implementation is based on Andrew's monotone chain 2D convex hull algorithm +template +static T raw_convex_hull(T& points) { assert(points.size() >= 3); // sort input points - std::sort(points.begin(), points.end(), sort_points); + std::sort(points.begin(), points.end(), SortPoints()); int n = points.size(), k = 0; - Polygon hull; + T hull; if (n >= 3) { - hull.points.resize(2*n); + hull.resize(2*n); // Build lower hull for (int i = 0; i < n; i++) { - while (k >= 2 && points[i].ccw(hull.points[k-2], hull.points[k-1]) <= 0) k--; - hull.points[k++] = points[i]; + while (k >= 2 && points[i].ccw(hull[k-2], hull[k-1]) <= 0) k--; + hull[k++] = points[i]; } // Build upper hull for (int i = n-2, t = k+1; i >= 0; i--) { - while (k >= t && points[i].ccw(hull.points[k-2], hull.points[k-1]) <= 0) k--; - hull.points[k++] = points[i]; + while (k >= t && points[i].ccw(hull[k-2], hull[k-1]) <= 0) k--; + hull[k++] = points[i]; } - hull.points.resize(k); + hull.resize(k); - assert( hull.points.front().coincides_with(hull.points.back()) ); - hull.points.pop_back(); + assert( hull.front().coincides_with(hull.back()) ); + hull.pop_back(); } return hull; } +Pointf3s +convex_hull(Pointf3s points) +{ + return raw_convex_hull(points); +} + +Polygon +convex_hull(Points points) +{ + Polygon hull; + hull.points = raw_convex_hull(points); + return hull; +} + Polygon convex_hull(const Polygons &polygons) { @@ -243,7 +258,7 @@ convex_hull(const Polygons &polygons) for (Polygons::const_iterator p = polygons.begin(); p != polygons.end(); ++p) { pp.insert(pp.end(), p->points.begin(), p->points.end()); } - return convex_hull(pp); + return convex_hull(std::move(pp)); } /* accepts an arrayref of points and returns a list of indices diff --git a/xs/src/libslic3r/Geometry.hpp b/xs/src/libslic3r/Geometry.hpp index c2c3dc8b75..956ef82aab 100644 --- a/xs/src/libslic3r/Geometry.hpp +++ b/xs/src/libslic3r/Geometry.hpp @@ -108,8 +108,10 @@ inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, co return true; } +Pointf3s convex_hull(Pointf3s points); Polygon convex_hull(Points points); Polygon convex_hull(const Polygons &polygons); + void chained_path(const Points &points, std::vector &retval, Point start_near); void chained_path(const Points &points, std::vector &retval); template void chained_path_items(Points &points, T &items, T &retval); diff --git a/xs/src/libslic3r/Point.cpp b/xs/src/libslic3r/Point.cpp index 2abcd26af4..349b00bb67 100644 --- a/xs/src/libslic3r/Point.cpp +++ b/xs/src/libslic3r/Point.cpp @@ -263,6 +263,12 @@ operator<<(std::ostream &stm, const Pointf &pointf) return stm << pointf.x << "," << pointf.y; } +double +Pointf::ccw(const Pointf &p1, const Pointf &p2) const +{ + return (double)(p2.x - p1.x)*(double)(this->y - p1.y) - (double)(p2.y - p1.y)*(double)(this->x - p1.x); +} + std::string Pointf::wkt() const { diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index 87104674f4..347966c03a 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -221,6 +221,7 @@ public: static Pointf new_unscale(const Point &p) { return Pointf(unscale(p.x), unscale(p.y)); }; + double ccw(const Pointf &p1, const Pointf &p2) const; std::string wkt() const; std::string dump_perl() const; void scale(double factor);