CuraEngine icon indicating copy to clipboard operation
CuraEngine copied to clipboard

Consider updating to clipper2

Open daid opened this issue 3 years ago • 10 comments
trafficstars

libclipper is one of the workhorses for CuraEngine, seeing that there is a newer version which has better performance: http://www.angusj.com/clipper2/Docs/Changes.htm

You might get overall beter performance in Cura if this is used instead.

With love,

Me.

daid avatar Oct 12 '22 11:10 daid

if it isn't the man himself, the O.G.

I wasn't aware that clipper2 existed, so I will definitely look into that. Thank you for the heads up and I will bring it up with our next Cura & Cookies

jellespijker avatar Oct 12 '22 18:10 jellespijker

Sweet! ❤️ Might be a while 'till we get to it, but definitely interested.

rburema avatar Oct 13 '22 06:10 rburema

if it isn't the man himself, the O.G.

I wasn't aware that clipper2 existed, so I will definitely look into that. Thank you for the heads up and I will bring it up with our next Cura & Cookies

I noticed it, and directly went to check if you guys where already using it. Glad to hear Cura&Cookies is still a thing.

I expect good quality from clipper2. I only once had a bug with clipper1 and that was quickly fixed after creating a reproducible case and sending it.

daid avatar Oct 13 '22 07:10 daid

you got all (of the developers) very excited atleast.

I was planning on creating a Conan recipe for clipper2 in the weekend, because currently only clipper1 is in the Conan Center Index https://github.com/conan-io/conan-center-index/blob/master/recipes/clipper/all/conanfile.py). which we use to setup our development environment https://github.com/Ultimaker/Cura/wiki/Running-Cura-from-Source. Once I made a PR for the new clipper2 it would be very easy to integrate build system wise so that we can experiment with the fun stuff.

jellespijker avatar Oct 13 '22 17:10 jellespijker

Hi, I have done the experiment and now have a version of my Cura variant that uses Clipper2. Haven't extensively tested it so I don't have performance figures yet.

smartavionics avatar Oct 23 '22 07:10 smartavionics

@smartavionics was it a drop-in replacement or did you change some fundamental types?

jellespijker avatar Oct 23 '22 17:10 jellespijker

Unfortunately, it's not a drop-in replacement, I had to make a zillion small edits. To give you an idea, here's the diffs I made for IntPoint.h and polygon.h...

diff --git a/src/utils/IntPoint.h b/src/utils/IntPoint.h
index f0e4421e9..8db3336ef 100644
--- a/src/utils/IntPoint.h
+++ b/src/utils/IntPoint.h
@@ -11,7 +11,7 @@ Integer points are used to avoid floating point rounding errors, and because Cli
 #define INLINE static inline
 
 //Include Clipper to get the ClipperLib::IntPoint definition, which we reuse as Point definition.
-#include "clipper.hpp"
+#include "clipper2/clipper.h"
 #include <cmath>
 #include <functional> // for hash function object
 #include <iostream> // auto-serialization / auto-toString()
@@ -37,27 +37,29 @@ namespace cura
 {
 
 /* 64bit Points are used mostly throughout the code, these are the 2D points from ClipperLib */
-typedef ClipperLib::IntPoint Point;
+typedef Clipper2Lib::Point64 Point;
 
-#define POINT_MIN std::numeric_limits<ClipperLib::cInt>::min()
-#define POINT_MAX std::numeric_limits<ClipperLib::cInt>::max()
+#define POINT_MIN std::numeric_limits<int64_t>::min()
+#define POINT_MAX std::numeric_limits<int64_t>::max()
 
-static Point no_point(std::numeric_limits<ClipperLib::cInt>::min(), std::numeric_limits<ClipperLib::cInt>::min());
+static Point no_point(std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::min());
 
 /* Extra operators to make it easier to do math with the 64bit Point objects */
-INLINE Point operator-(const Point& p0) { return Point(-p0.X, -p0.Y); }
-INLINE Point operator+(const Point& p0, const Point& p1) { return Point(p0.X+p1.X, p0.Y+p1.Y); }
-INLINE Point operator-(const Point& p0, const Point& p1) { return Point(p0.X-p1.X, p0.Y-p1.Y); }
-INLINE Point operator*(const Point& p0, const coord_t i) { return Point(p0.X * i, p0.Y * i); }
+/*
+INLINE Point operator-(const Point& p0) { return Point(-p0.x, -p0.x); }
+INLINE Point operator+(const Point& p0, const Point& p1) { return Point(p0.x+p1.x, p0.y+p1.y); }
+INLINE Point operator-(const Point& p0, const Point& p1) { return Point(p0.x-p1.x, p0.y-p1.y); }
+*/
+INLINE Point operator*(const Point& p0, const coord_t i) { return Point(p0.x * i, p0.y * i); }
 template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type> //Use only for numeric types.
-INLINE Point operator*(const Point& p0, const T i) { return Point(p0.X * i, p0.Y * i); }
+INLINE Point operator*(const Point& p0, const T i) { return Point(p0.x * i, p0.y * i); }
 template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type> //Use only for numeric types.
 INLINE Point operator*(const T i, const Point& p0) { return p0 * i; }
-INLINE Point operator/(const Point& p0, const coord_t i) { return Point(p0.X/i, p0.Y/i); }
-INLINE Point operator/(const Point& p0, const Point& p1) { return Point(p0.X/p1.X, p0.Y/p1.Y); }
+INLINE Point operator/(const Point& p0, const coord_t i) { return Point(p0.x/i, p0.y/i); }
+INLINE Point operator/(const Point& p0, const Point& p1) { return Point(p0.x/p1.x, p0.y/p1.y); }
 
-INLINE Point& operator += (Point& p0, const Point& p1) { p0.X += p1.X; p0.Y += p1.Y; return p0; }
-INLINE Point& operator -= (Point& p0, const Point& p1) { p0.X -= p1.X; p0.Y -= p1.Y; return p0; }
+INLINE Point& operator += (Point& p0, const Point& p1) { p0.x += p1.x; p0.y += p1.y; return p0; }
+INLINE Point& operator -= (Point& p0, const Point& p1) { p0.x -= p1.x; p0.y -= p1.y; return p0; }
 
 /* ***** NOTE *****
    TL;DR: DO NOT implement operators *= and /= because of the default values in ClipperLib::IntPoint's constructor.
@@ -73,21 +75,21 @@ INLINE Point& operator -= (Point& p0, const Point& p1) { p0.X -= p1.X; p0.Y -= p
 
 INLINE coord_t vSize2(const Point& p0)
 {
-    return p0.X*p0.X+p0.Y*p0.Y;
+    return p0.x*p0.x+p0.y*p0.y;
 }
 INLINE float vSize2f(const Point& p0)
 {
-    return static_cast<float>(p0.X)*static_cast<float>(p0.X)+static_cast<float>(p0.Y)*static_cast<float>(p0.Y);
+    return static_cast<float>(p0.x)*static_cast<float>(p0.x)+static_cast<float>(p0.y)*static_cast<float>(p0.y);
 }
 
 
 INLINE bool shorterThen(const Point& p0, const coord_t len)
 {
-    if (p0.X > len || p0.X < -len)
+    if (p0.x > len || p0.x < -len)
     {
         return false;
     }
-    if (p0.Y > len || p0.Y < -len)
+    if (p0.y > len || p0.y < -len)
     {
         return false;
     }
@@ -101,8 +103,8 @@ INLINE coord_t vSize(const Point& p0)
 
 INLINE double vSizeMM(const Point& p0)
 {
-    double fx = INT2MM(p0.X);
-    double fy = INT2MM(p0.Y);
+    double fx = INT2MM(p0.x);
+    double fy = INT2MM(p0.y);
     return sqrt(fx*fx+fy*fy);
 }
 
@@ -110,30 +112,30 @@ INLINE Point normal(const Point& p0, coord_t len)
 {
     coord_t _len = vSize(p0);
     if (_len < 1)
-        return Point(len, 0);
+        return Point(len, (coord_t)0);
     return p0 * len / _len;
 }
 
 INLINE Point turn90CCW(const Point& p0)
 {
-    return Point(-p0.Y, p0.X);
+    return Point(-p0.y, p0.x);
 }
 
 INLINE Point rotate(const Point& p0, double angle)
 {
     const double cos_component = std::cos(angle);
     const double sin_component = std::sin(angle);
-    return Point(cos_component * p0.X - sin_component * p0.Y, sin_component * p0.X + cos_component * p0.Y);
+    return Point(cos_component * p0.x - sin_component * p0.y, sin_component * p0.x + cos_component * p0.y);
 }
 
 INLINE coord_t dot(const Point& p0, const Point& p1)
 {
-    return p0.X * p1.X + p0.Y * p1.Y;
+    return p0.x * p1.x + p0.y * p1.y;
 }
 
 INLINE double angle(const Point& p)
 {
-    double angle = std::atan2(p.X, p.Y) / M_PI * 180.0;
+    double angle = std::atan2(p.x, p.y) / M_PI * 180.0;
     if (angle < 0.0) angle += 360.0;
     return angle;
 }
@@ -147,8 +149,8 @@ struct hash<cura::Point> {
     {
         static int prime = 31;
         int result = 89;
-        result = result * prime + pp.X;
-        result = result * prime + pp.Y;
+        result = result * prime + pp.x;
+        result = result * prime + pp.y;
         return result;
     }
 };
@@ -181,8 +183,8 @@ public:
 
     PointMatrix(const Point p)
     {
-        matrix[0] = p.X;
-        matrix[1] = p.Y;
+        matrix[0] = p.x;
+        matrix[1] = p.y;
         double f = sqrt((matrix[0] * matrix[0]) + (matrix[1] * matrix[1]));
         matrix[0] /= f;
         matrix[1] /= f;
@@ -192,12 +194,12 @@ public:
 
     Point apply(const Point p) const
     {
-        return Point(p.X * matrix[0] + p.Y * matrix[1], p.X * matrix[2] + p.Y * matrix[3]);
+        return Point(p.x * matrix[0] + p.y * matrix[1], p.x * matrix[2] + p.y * matrix[3]);
     }
 
     Point unapply(const Point p) const
     {
-        return Point(p.X * matrix[0] + p.Y * matrix[2], p.X * matrix[1] + p.Y * matrix[3]);
+        return Point(p.x * matrix[0] + p.y * matrix[2], p.x * matrix[1] + p.y * matrix[3]);
     }
 };
 
@@ -248,15 +250,15 @@ public:
      */
     Point apply(const Point p) const
     {
-        Point3 result = apply(Point3(p.X, p.Y, 1));
+        Point3 result = apply(Point3(p.x, p.y, 1));
         return Point(result.x / result.z, result.y / result.z);
     }
 
     static Point3Matrix translate(const Point p)
     {
         Point3Matrix ret; // uniform matrix
-        ret.matrix[2] = p.X;
-        ret.matrix[5] = p.Y;
+        ret.matrix[2] = p.x;
+        ret.matrix[5] = p.y;
         return ret;
     }
 
@@ -280,30 +282,30 @@ public:
 
 
 inline Point3 operator+(const Point3& p3, const Point& p2) {
-    return Point3(p3.x + p2.X, p3.y + p2.Y, p3.z);
+    return Point3(p3.x + p2.x, p3.y + p2.y, p3.z);
 }
 inline Point3& operator+=(Point3& p3, const Point& p2) {
-    p3.x += p2.X;
-    p3.y += p2.Y;
+    p3.x += p2.x;
+    p3.y += p2.y;
     return p3;
 }
 
 inline Point operator+(const Point& p2, const Point3& p3) {
-    return Point(p3.x + p2.X, p3.y + p2.Y);
+    return Point(p3.x + p2.x, p3.y + p2.y);
 }
 
 
 inline Point3 operator-(const Point3& p3, const Point& p2) {
-    return Point3(p3.x - p2.X, p3.y - p2.Y, p3.z);
+    return Point3(p3.x - p2.x, p3.y - p2.y, p3.z);
 }
 inline Point3& operator-=(Point3& p3, const Point& p2) {
-    p3.x -= p2.X;
-    p3.y -= p2.Y;
+    p3.x -= p2.x;
+    p3.y -= p2.y;
     return p3;
 }
 
 inline Point operator-(const Point& p2, const Point3& p3) {
-    return Point(p2.X - p3.x, p2.Y - p3.y);
+    return Point(p2.x - p3.x, p2.y - p3.y);
 }
 
 }//namespace cura
diff --git a/src/utils/polygon.h b/src/utils/polygon.h
index 02dc50bee..a701c65fb 100644
--- a/src/utils/polygon.h
+++ b/src/utils/polygon.h
@@ -7,7 +7,7 @@
 #include <vector>
 #include <assert.h>
 #include <float.h>
-#include "clipper.hpp"
+#include "clipper2/clipper.h"
 
 #include <algorithm>    // std::reverse, fill_n array
 #include <cmath> // fabs
@@ -39,7 +39,6 @@ class ListPolyIt;
 typedef std::list<Point> ListPolygon; //!< A polygon represented by a linked list instead of a vector
 typedef std::vector<ListPolygon> ListPolygons; //!< Polygons represented by a vector of linked lists instead of a vector of vectors
 
-const static int clipper_init = (0);
 #define NO_INDEX (std::numeric_limits<unsigned int>::max())
 
 class ConstPolygonPointer;
@@ -56,10 +55,10 @@ class ConstPolygonRef
     friend class PolygonRef;
     friend class ConstPolygonPointer;
 protected:
-    ClipperLib::Path* path;
+    Clipper2Lib::Path64* path;
 public:
-    ConstPolygonRef(const ClipperLib::Path& polygon)
-    : path(const_cast<ClipperLib::Path*>(&polygon))
+    ConstPolygonRef(const Clipper2Lib::Path64& polygon)
+    : path(const_cast<Clipper2Lib::Path64*>(&polygon))
     {}
 
     virtual ~ConstPolygonRef()
@@ -89,22 +88,22 @@ public:
         return (*path)[index];
     }
 
-    const ClipperLib::Path& operator*() const
+    const Clipper2Lib::Path64& operator*() const
     {
         return *path;
     }
 
-    ClipperLib::Path::const_iterator begin() const
+    Clipper2Lib::Path64::const_iterator begin() const
     {
         return path->begin();
     }
 
-    ClipperLib::Path::const_iterator end() const
+    Clipper2Lib::Path64::const_iterator end() const
     {
         return path->end();
     }
 
-    ClipperLib::Path::const_reference back() const
+    Clipper2Lib::Path64::const_reference back() const
     {
         return path->back();
     }
@@ -122,10 +121,10 @@ public:
      */
     bool orientation() const
     {
-        return ClipperLib::Orientation(*path);
+        return Clipper2Lib::IsPositive(*path);
     }
 
-    Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const;
+    Polygons offset(int distance, Clipper2Lib::JoinType joinType = Clipper2Lib::JoinType::Miter, double miter_limit = 1.2) const;
 
     int64_t polygonLength() const
     {
@@ -147,8 +146,8 @@ public:
         Point ret = Point(POINT_MAX, POINT_MAX);
         for(Point p : *path)
         {
-            ret.X = std::min(ret.X, p.X);
-            ret.Y = std::min(ret.Y, p.Y);
+            ret.x = std::min(ret.x, p.x);
+            ret.y = std::min(ret.y, p.y);
         }
         return ret;
     }
@@ -158,15 +157,15 @@ public:
         Point ret = Point(POINT_MIN, POINT_MIN);
         for(Point p : *path)
         {
-            ret.X = std::max(ret.X, p.X);
-            ret.Y = std::max(ret.Y, p.Y);
+            ret.x = std::max(ret.x, p.x);
+            ret.y = std::max(ret.y, p.y);
         }
         return ret;
     }
 
     double area() const
     {
-        return ClipperLib::Area(*path);
+        return Clipper2Lib::Area(*path);
     }
 
     Point centerOfMass() const
@@ -176,10 +175,10 @@ public:
         for(unsigned int n=0; n<path->size(); n++)
         {
             Point p1 = (*path)[n];
-            double second_factor = (p0.X * p1.Y) - (p1.X * p0.Y);
+            double second_factor = (p0.x * p1.y) - (p1.x * p0.y);
 
-            x += double(p0.X + p1.X) * second_factor;
-            y += double(p0.Y + p1.Y) * second_factor;
+            x += double(p0.x + p1.x) * second_factor;
+            y += double(p0.y + p1.y) * second_factor;
             p0 = p1;
         }
 
@@ -235,12 +234,12 @@ public:
      */
     bool inside(Point p, bool border_result = false) const
     {
-        int res = ClipperLib::PointInPolygon(p, *path);
-        if (res == -1)
+        Clipper2Lib::PointInPolygonResult res = Clipper2Lib::PointInPolygon(p, *path);
+        if (res == Clipper2Lib::PointInPolygonResult::IsOn)
         {
             return border_result;
         }
-        return res == 1;
+        return res == Clipper2Lib::PointInPolygonResult::IsInside;
     }
 
     /*!
@@ -347,7 +346,7 @@ class PolygonRef : public ConstPolygonRef
 {
     friend class PolygonPointer;
 public:
-    PolygonRef(ClipperLib::Path& polygon)
+    PolygonRef(Clipper2Lib::Path64& polygon)
     : ConstPolygonRef(polygon)
     {}
 
@@ -386,17 +385,17 @@ public:
         return path->at(index);
     }
 
-    ClipperLib::Path::iterator begin()
+    Clipper2Lib::Path64::iterator begin()
     {
         return path->begin();
     }
 
-    ClipperLib::Path::iterator end()
+    Clipper2Lib::Path64::iterator end()
     {
         return path->end();
     }
 
-    ClipperLib::Path::reference back()
+    Clipper2Lib::Path64::reference back()
     {
         return path->back();
     }
@@ -411,7 +410,7 @@ public:
         path->push_back(p);
     }
 
-    ClipperLib::Path& operator*()
+    Clipper2Lib::Path64& operator*()
     {
         return *path;
     }
@@ -435,7 +434,7 @@ public:
 
     void reverse()
     {
-        ClipperLib::ReversePath(*path);
+        std::reverse(path->begin(), path->end());
     }
 
     /*!
@@ -484,7 +483,7 @@ public:
 class ConstPolygonPointer
 {
 protected:
-    const ClipperLib::Path* path;
+    const Clipper2Lib::Path64* path;
 public:
     ConstPolygonPointer()
     : path(nullptr)
@@ -501,7 +500,7 @@ public:
         assert(path);
         return ConstPolygonRef(*path);
     }
-    const ClipperLib::Path* operator->() const
+    const Clipper2Lib::Path64* operator->() const
     {
         assert(path);
         return path;
@@ -521,7 +520,7 @@ public:
 class PolygonPointer
 {
 protected:
-    ClipperLib::Path* path;
+    Clipper2Lib::Path64* path;
 public:
     PolygonPointer()
     : path(nullptr)
@@ -539,7 +538,7 @@ public:
         assert(path);
         return PolygonRef(*path);
     }
-    ClipperLib::Path* operator->()
+    Clipper2Lib::Path64* operator->()
     {
         assert(path);
         return path;
@@ -553,7 +552,7 @@ public:
 
 class Polygon : public PolygonRef
 {
-    ClipperLib::Path poly;
+    Clipper2Lib::Path64 poly;
 public:
     Polygon()
     : PolygonRef(poly)
@@ -604,7 +603,7 @@ class Polygons
     friend class PolygonRef;
     friend class ConstPolygonRef;
 protected:
-    ClipperLib::Paths paths;
+    Clipper2Lib::Paths64 paths;
 public:
     unsigned int size() const
     {
@@ -630,19 +629,19 @@ public:
         POLY_ASSERT(index < size() && index <= static_cast<unsigned int>(std::numeric_limits<int>::max()));
         return paths[index];
     }
-    ClipperLib::Paths::iterator begin()
+    Clipper2Lib::Paths64::iterator begin()
     {
         return paths.begin();
     }
-    ClipperLib::Paths::const_iterator begin() const
+    Clipper2Lib::Paths64::const_iterator begin() const
     {
         return paths.begin();
     }
-    ClipperLib::Paths::iterator end()
+    Clipper2Lib::Paths64::iterator end()
     {
         return paths.end();
     }
-    ClipperLib::Paths::const_iterator end() const
+    Clipper2Lib::Paths64::const_iterator end() const
     {
         return paths.end();
     }
@@ -669,7 +668,7 @@ public:
     /*!
      * Remove a range of polygons
      */
-    void erase(ClipperLib::Paths::iterator start, ClipperLib::Paths::iterator end)
+    void erase(Clipper2Lib::Paths64::iterator start, Clipper2Lib::Paths64::iterator end)
     {
         paths.erase(start, end);
     }
@@ -698,7 +697,7 @@ public:
      */
     void addLine(const Point from, const Point to)
     {
-        paths.emplace_back(ClipperLib::Path{from, to});
+        paths.emplace_back(Clipper2Lib::Path64{from, to});
     }
 
     template<typename... Args>
@@ -734,24 +733,18 @@ public:
      * Convert ClipperLib::PolyTree to a Polygons object,
      * which uses ClipperLib::Paths instead of ClipperLib::PolyTree
      */
-    static Polygons toPolygons(ClipperLib::PolyTree& poly_tree);
+    static Polygons toPolygons(Clipper2Lib::PolyTree64& poly_tree);
 
     Polygons difference(const Polygons& other) const
     {
         Polygons ret;
-        ClipperLib::Clipper clipper(clipper_init);
-        clipper.AddPaths(paths, ClipperLib::ptSubject, true);
-        clipper.AddPaths(other.paths, ClipperLib::ptClip, true);
-        clipper.Execute(ClipperLib::ctDifference, ret.paths);
+        ret.paths = Clipper2Lib::Difference(paths, other.paths, Clipper2Lib::FillRule::NonZero);
         return ret;
     }
-    Polygons unionPolygons(const Polygons& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const
+    Polygons unionPolygons(const Polygons& other, Clipper2Lib::FillRule fill_type = Clipper2Lib::FillRule::NonZero) const
     {
         Polygons ret;
-        ClipperLib::Clipper clipper(clipper_init);
-        clipper.AddPaths(paths, ClipperLib::ptSubject, true);
-        clipper.AddPaths(other.paths, ClipperLib::ptSubject, true);
-        clipper.Execute(ClipperLib::ctUnion, ret.paths, fill_type, fill_type);
+        ret.paths = Clipper2Lib::Union(paths, other.paths, fill_type);
         return ret;
     }
     /*!
@@ -764,10 +757,7 @@ public:
     Polygons intersection(const Polygons& other) const
     {
         Polygons ret;
-        ClipperLib::Clipper clipper(clipper_init);
-        clipper.AddPaths(paths, ClipperLib::ptSubject, true);
-        clipper.AddPaths(other.paths, ClipperLib::ptClip, true);
-        clipper.Execute(ClipperLib::ctIntersection, ret.paths);
+        ret.paths = Clipper2Lib::Intersect(paths, other.paths, Clipper2Lib::FillRule::NonZero);
         return ret;
     }
 
@@ -781,12 +771,14 @@ public:
      * \param other Input line segments to be cropped
      * \param segment_tree the resulting interior line segments
      */
-    void lineSegmentIntersection(const Polygons& other, ClipperLib::PolyTree& segment_tree) const
+    void lineSegmentIntersection(const Polygons& other, Clipper2Lib::Paths64& open_paths) const
     {
-        ClipperLib::Clipper clipper(clipper_init);
-        clipper.AddPaths(paths, ClipperLib::ptClip, true);
-        clipper.AddPaths(other.paths, ClipperLib::ptSubject, false);
-        clipper.Execute(ClipperLib::ctIntersection, segment_tree);
+        Clipper2Lib::Clipper64 clipper;
+        Clipper2Lib::PolyTree64 poly_tree;
+        clipper.AddOpenSubject(other.paths);
+        clipper.AddClip(paths);
+        Clipper2Lib::Paths64 closed_paths;
+        clipper.Execute(Clipper2Lib::ClipType::Intersection, Clipper2Lib::FillRule::EvenOdd, closed_paths, open_paths);
     }
 
     /*!
@@ -798,24 +790,18 @@ public:
     Polygons xorPolygons(const Polygons& other) const
     {
         Polygons ret;
-        ClipperLib::Clipper clipper(clipper_init);
-        clipper.AddPaths(paths, ClipperLib::ptSubject, true);
-        clipper.AddPaths(other.paths, ClipperLib::ptClip, true);
-        clipper.Execute(ClipperLib::ctXor, ret.paths);
+        ret.paths = Clipper2Lib::Xor(paths, other.paths, Clipper2Lib::FillRule::NonZero);
         return ret;
     }
 
-    Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const;
+    Polygons offset(int distance, Clipper2Lib::JoinType joinType = Clipper2Lib::JoinType::Miter, double miter_limit = 1.2) const;
 
-    Polygons offsetPolyLine(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter) const
+    Polygons offsetPolyLine(int distance, Clipper2Lib::JoinType join_type = Clipper2Lib::JoinType::Miter) const
     {
+        const Clipper2Lib::EndType end_type = (join_type == Clipper2Lib::JoinType::Miter)? Clipper2Lib::EndType::Square : Clipper2Lib::EndType::Round;
+        const double miter_limit = 1.2;
         Polygons ret;
-        double miterLimit = 1.2;
-        ClipperLib::EndType end_type = (joinType == ClipperLib::jtMiter)? ClipperLib::etOpenSquare : ClipperLib::etOpenRound;
-        ClipperLib::ClipperOffset clipper(miterLimit, 10.0);
-        clipper.AddPaths(paths, joinType, end_type);
-        clipper.MiterLimit = miterLimit;
-        clipper.Execute(ret.paths, distance);
+        ret.paths = Clipper2Lib::InflatePaths(paths, distance, join_type, end_type, miter_limit);
         return ret;
     }
     
@@ -987,14 +973,14 @@ private:
      * \param remove_holes Whether to remove empty holes or everything but the empty holes
      * \param ret Where to store polygons which are not empty holes
      */
-    void removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const;
-    void splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector<PolygonsPart>& ret) const;
+    void removeEmptyHoles_processPolyTreeNode(const Clipper2Lib::PolyTree64& node, const bool remove_holes, Polygons& ret) const;
+    void splitIntoParts_processPolyTreeNode(Clipper2Lib::PolyTree64* node, std::vector<PolygonsPart>& ret) const;
 
     /*!
      * Convert a node from a ClipperLib::PolyTree and add it to a Polygons object,
      * which uses ClipperLib::Paths instead of ClipperLib::PolyTree
      */
-    void addPolyTreeNodeRecursive(const ClipperLib::PolyNode& node);
+    void addPolyTreeNodeRecursive(const Clipper2Lib::PolyTree64& node);
 public:
     /*!
      * Split up the polygons into groups according to the even-odd rule.
@@ -1004,7 +990,7 @@ public:
      */
     PartsView splitIntoPartsView(bool unionAll = false);
 private:
-    void splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const;
+    void splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, Clipper2Lib::PolyTree64* node) const;
 public:
     /*!
      * Removes polygons with area smaller than \p min_area_size (note that min_area_size is in mm^2, not in micron^2).
@@ -1105,9 +1091,7 @@ public:
     Polygons processEvenOdd() const
     {
         Polygons ret;
-        ClipperLib::Clipper clipper(clipper_init);
-        clipper.AddPaths(paths, ClipperLib::ptSubject, true);
-        clipper.Execute(ClipperLib::ctUnion, ret.paths);
+        ret.paths = Clipper2Lib::Union(paths, ret.paths, Clipper2Lib::FillRule::NonZero);
         return ret;
     }
 
@@ -1132,12 +1116,12 @@ public:
     Point min() const
     {
         Point ret = Point(POINT_MAX, POINT_MAX);
-        for(const ClipperLib::Path& polygon : paths)
+        for(const Clipper2Lib::Path64& polygon : paths)
         {
             for(Point p : polygon)
             {
-                ret.X = std::min(ret.X, p.X);
-                ret.Y = std::min(ret.Y, p.Y);
+                ret.x = std::min(ret.x, p.x);
+                ret.y = std::min(ret.y, p.y);
             }
         }
         return ret;
@@ -1146,12 +1130,12 @@ public:
     Point max() const
     {
         Point ret = Point(POINT_MIN, POINT_MIN);
-        for(const ClipperLib::Path& polygon : paths)
+        for(const Clipper2Lib::Path64& polygon : paths)
         {
             for(Point p : polygon)
             {
-                ret.X = std::max(ret.X, p.X);
-                ret.Y = std::max(ret.Y, p.Y);
+                ret.x = std::max(ret.x, p.x);
+                ret.y = std::max(ret.y, p.y);
             }
         }
         return ret;

smartavionics avatar Oct 23 '22 18:10 smartavionics

I just tried slicing a reasonably complex model and the times reported by the engine were 80 seconds for Clipper2 and 78 seconds for Clipper1. Hardly encouraging. This was using a Cura 4 based slicer, i.e. no Arachne. I'll try some different models and see if I can detect any speed benefit.

smartavionics avatar Oct 23 '22 19:10 smartavionics

Just sliced another complex model and, again, Clipper2 is very slightly slower than Clipper1. So perhaps it's not worth going to the effort of upgrading?

smartavionics avatar Oct 23 '22 19:10 smartavionics

@smartavionics I made a PR today for setting up an automatic benchmark check, might be of interest to you as well. https://github.com/Ultimaker/CuraEngine/pull/1775

jellespijker avatar Nov 16 '22 21:11 jellespijker