diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9a5fc8387..c6f295150 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -268,8 +268,6 @@ set(LIBDIR_BIN ${CMAKE_CURRENT_BINARY_DIR}/src)
include_directories(${LIBDIR})
# For generated header files
include_directories(${LIBDIR_BIN}/platform)
-# For libslic3r.h
-include_directories(${LIBDIR}/clipper)
if(WIN32)
add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
diff --git a/resources/icons/splashscreen-gcodepreview.jpg b/resources/icons/splashscreen-gcodepreview.jpg
index 3bae38493..481c4a6e1 100644
Binary files a/resources/icons/splashscreen-gcodepreview.jpg and b/resources/icons/splashscreen-gcodepreview.jpg differ
diff --git a/resources/icons/splashscreen.jpg b/resources/icons/splashscreen.jpg
index 754e24588..08236bccc 100644
Binary files a/resources/icons/splashscreen.jpg and b/resources/icons/splashscreen.jpg differ
diff --git a/resources/profiles/PrusaResearch/mk2.svg b/resources/profiles/PrusaResearch/mk2.svg
index b8fa8d0cd..6214a5552 100644
--- a/resources/profiles/PrusaResearch/mk2.svg
+++ b/resources/profiles/PrusaResearch/mk2.svg
@@ -1 +1,885 @@
-
\ No newline at end of file
+
+
diff --git a/resources/profiles/PrusaResearch/mk3.svg b/resources/profiles/PrusaResearch/mk3.svg
index c8f53373b..03b24d572 100644
--- a/resources/profiles/PrusaResearch/mk3.svg
+++ b/resources/profiles/PrusaResearch/mk3.svg
@@ -1 +1,883 @@
-
\ No newline at end of file
+
+
diff --git a/src/clipper/CMakeLists.txt b/src/clipper/CMakeLists.txt
index 8a4e92852..0362a4d84 100644
--- a/src/clipper/CMakeLists.txt
+++ b/src/clipper/CMakeLists.txt
@@ -2,8 +2,9 @@ project(clipper)
cmake_minimum_required(VERSION 2.6)
add_library(clipper STATIC
- clipper.cpp
- clipper.hpp
+# We are using ClipperLib compiled as part of the libslic3r project using Slic3r::Point as its base type.
+# clipper.cpp
+# clipper.hpp
clipper_z.cpp
clipper_z.hpp
)
diff --git a/src/clipper/clipper.cpp b/src/clipper/clipper.cpp
index cbe54a064..06c91bf3a 100644
--- a/src/clipper/clipper.cpp
+++ b/src/clipper/clipper.cpp
@@ -61,11 +61,15 @@
#define CLIPPERLIB_PROFILE_BLOCK(name)
#endif
-#ifdef use_xyz
+#ifdef CLIPPERLIB_NAMESPACE_PREFIX
+namespace CLIPPERLIB_NAMESPACE_PREFIX {
+#endif // CLIPPERLIB_NAMESPACE_PREFIX
+
+#ifdef CLIPPERLIB_USE_XYZ
namespace ClipperLib_Z {
-#else /* use_xyz */
+#else /* CLIPPERLIB_USE_XYZ */
namespace ClipperLib {
-#endif /* use_xyz */
+#endif /* CLIPPERLIB_USE_XYZ */
static double const pi = 3.141592653589793238;
static double const two_pi = pi *2;
@@ -156,7 +160,7 @@ double Area(const Path &poly)
double a = 0;
for (int i = 0, j = size -1; i < size; ++i)
{
- a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y);
+ a += ((double)poly[j].x() + poly[i].x()) * ((double)poly[j].y() - poly[i].y());
j = i;
}
return -a * 0.5;
@@ -169,7 +173,7 @@ double Area(const OutRec &outRec)
if (!op) return 0;
double a = 0;
do {
- a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y);
+ a += (double)(op->Prev->Pt.x() + op->Pt.x()) * (double)(op->Prev->Pt.y() - op->Pt.y());
op = op->Next;
} while (op != outRec.Pts);
return a * 0.5;
@@ -201,26 +205,26 @@ int PointInPolygon(const IntPoint &pt, const Path &path)
for(size_t i = 1; i <= cnt; ++i)
{
IntPoint ipNext = (i == cnt ? path[0] : path[i]);
- if (ipNext.Y == pt.Y && ((ipNext.X == pt.X) || (ip.Y == pt.Y && ((ipNext.X > pt.X) == (ip.X < pt.X)))))
+ if (ipNext.y() == pt.y() && ((ipNext.x() == pt.x()) || (ip.y() == pt.y() && ((ipNext.x() > pt.x()) == (ip.x() < pt.x())))))
return -1;
- if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y))
+ if ((ip.y() < pt.y()) != (ipNext.y() < pt.y()))
{
- if (ip.X >= pt.X)
+ if (ip.x() >= pt.x())
{
- if (ipNext.X > pt.X) result = 1 - result;
+ if (ipNext.x() > pt.x()) result = 1 - result;
else
{
- double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
+ double d = (double)(ip.x() - pt.x()) * (ipNext.y() - pt.y()) - (double)(ipNext.x() - pt.x()) * (ip.y() - pt.y());
if (!d) return -1;
- if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result;
+ if ((d > 0) == (ipNext.y() > ip.y())) result = 1 - result;
}
} else
{
- if (ipNext.X > pt.X)
+ if (ipNext.x() > pt.x())
{
- double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
+ double d = (double)(ip.x() - pt.x()) * (ipNext.y() - pt.y()) - (double)(ipNext.x() - pt.x()) * (ip.y() - pt.y());
if (!d) return -1;
- if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result;
+ if ((d > 0) == (ipNext.y() > ip.y())) result = 1 - result;
}
}
}
@@ -238,29 +242,29 @@ int PointInPolygon (const IntPoint &pt, OutPt *op)
OutPt* startOp = op;
do
{
- if (op->Next->Pt.Y == pt.Y)
+ if (op->Next->Pt.y() == pt.y())
{
- if ((op->Next->Pt.X == pt.X) || (op->Pt.Y == pt.Y &&
- ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X)))) return -1;
+ if ((op->Next->Pt.x() == pt.x()) || (op->Pt.y() == pt.y() &&
+ ((op->Next->Pt.x() > pt.x()) == (op->Pt.x() < pt.x())))) return -1;
}
- if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y))
+ if ((op->Pt.y() < pt.y()) != (op->Next->Pt.y() < pt.y()))
{
- if (op->Pt.X >= pt.X)
+ if (op->Pt.x() >= pt.x())
{
- if (op->Next->Pt.X > pt.X) result = 1 - result;
+ if (op->Next->Pt.x() > pt.x()) result = 1 - result;
else
{
- double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
+ double d = (double)(op->Pt.x() - pt.x()) * (op->Next->Pt.y() - pt.y()) - (double)(op->Next->Pt.x() - pt.x()) * (op->Pt.y() - pt.y());
if (!d) return -1;
- if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result;
+ if ((d > 0) == (op->Next->Pt.y() > op->Pt.y())) result = 1 - result;
}
} else
{
- if (op->Next->Pt.X > pt.X)
+ if (op->Next->Pt.x() > pt.x())
{
- double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
+ double d = (double)(op->Pt.x() - pt.x()) * (op->Next->Pt.y() - pt.y()) - (double)(op->Next->Pt.x() - pt.x()) * (op->Pt.y() - pt.y());
if (!d) return -1;
- if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result;
+ if ((d > 0) == (op->Next->Pt.y() > op->Pt.y())) result = 1 - result;
}
}
}
@@ -304,100 +308,100 @@ inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cI
#endif
inline bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
- { return SlopesEqual(e1.Delta.X, e1.Delta.Y, e2.Delta.X, e2.Delta.Y, UseFullInt64Range); }
+ { return SlopesEqual(e1.Delta.x(), e1.Delta.y(), e2.Delta.x(), e2.Delta.y(), UseFullInt64Range); }
inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3, bool UseFullInt64Range)
- { return SlopesEqual(pt1.X-pt2.X, pt1.Y-pt2.Y, pt2.X-pt3.X, pt2.Y-pt3.Y, UseFullInt64Range); }
+ { return SlopesEqual(pt1.x()-pt2.x(), pt1.y()-pt2.y(), pt2.x()-pt3.x(), pt2.y()-pt3.y(), UseFullInt64Range); }
inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3, const IntPoint &pt4, bool UseFullInt64Range)
- { return SlopesEqual(pt1.X-pt2.X, pt1.Y-pt2.Y, pt3.X-pt4.X, pt3.Y-pt4.Y, UseFullInt64Range); }
+ { return SlopesEqual(pt1.x()-pt2.x(), pt1.y()-pt2.y(), pt3.x()-pt4.x(), pt3.y()-pt4.y(), UseFullInt64Range); }
//------------------------------------------------------------------------------
inline bool IsHorizontal(TEdge &e)
{
- return e.Delta.Y == 0;
+ return e.Delta.y() == 0;
}
//------------------------------------------------------------------------------
inline double GetDx(const IntPoint &pt1, const IntPoint &pt2)
{
- return (pt1.Y == pt2.Y) ?
- HORIZONTAL : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y);
+ return (pt1.y() == pt2.y()) ?
+ HORIZONTAL : (double)(pt2.x() - pt1.x()) / (pt2.y() - pt1.y());
}
//---------------------------------------------------------------------------
inline cInt TopX(TEdge &edge, const cInt currentY)
{
- return (currentY == edge.Top.Y) ?
- edge.Top.X :
- edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y));
+ return (currentY == edge.Top.y()) ?
+ edge.Top.x() :
+ edge.Bot.x() + Round(edge.Dx *(currentY - edge.Bot.y()));
}
//------------------------------------------------------------------------------
void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
{
-#ifdef use_xyz
- ip.Z = 0;
+#ifdef CLIPPERLIB_USE_XYZ
+ ip.z() = 0;
#endif
double b1, b2;
if (Edge1.Dx == Edge2.Dx)
{
- ip.Y = Edge1.Curr.Y;
- ip.X = TopX(Edge1, ip.Y);
+ ip.y() = Edge1.Curr.y();
+ ip.x() = TopX(Edge1, ip.y());
return;
}
- else if (Edge1.Delta.X == 0)
+ else if (Edge1.Delta.x() == 0)
{
- ip.X = Edge1.Bot.X;
+ ip.x() = Edge1.Bot.x();
if (IsHorizontal(Edge2))
- ip.Y = Edge2.Bot.Y;
+ ip.y() = Edge2.Bot.y();
else
{
- b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx);
- ip.Y = Round(ip.X / Edge2.Dx + b2);
+ b2 = Edge2.Bot.y() - (Edge2.Bot.x() / Edge2.Dx);
+ ip.y() = Round(ip.x() / Edge2.Dx + b2);
}
}
- else if (Edge2.Delta.X == 0)
+ else if (Edge2.Delta.x() == 0)
{
- ip.X = Edge2.Bot.X;
+ ip.x() = Edge2.Bot.x();
if (IsHorizontal(Edge1))
- ip.Y = Edge1.Bot.Y;
+ ip.y() = Edge1.Bot.y();
else
{
- b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx);
- ip.Y = Round(ip.X / Edge1.Dx + b1);
+ b1 = Edge1.Bot.y() - (Edge1.Bot.x() / Edge1.Dx);
+ ip.y() = Round(ip.x() / Edge1.Dx + b1);
}
}
else
{
- b1 = double(Edge1.Bot.X) - double(Edge1.Bot.Y) * Edge1.Dx;
- b2 = double(Edge2.Bot.X) - double(Edge2.Bot.Y) * Edge2.Dx;
+ b1 = double(Edge1.Bot.x()) - double(Edge1.Bot.y()) * Edge1.Dx;
+ b2 = double(Edge2.Bot.x()) - double(Edge2.Bot.y()) * Edge2.Dx;
double q = (b2-b1) / (Edge1.Dx - Edge2.Dx);
- ip.Y = Round(q);
- ip.X = (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ?
+ ip.y() = Round(q);
+ ip.x() = (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ?
Round(Edge1.Dx * q + b1) :
Round(Edge2.Dx * q + b2);
}
- if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y)
+ if (ip.y() < Edge1.Top.y() || ip.y() < Edge2.Top.y())
{
- if (Edge1.Top.Y > Edge2.Top.Y)
- ip.Y = Edge1.Top.Y;
+ if (Edge1.Top.y() > Edge2.Top.y())
+ ip.y() = Edge1.Top.y();
else
- ip.Y = Edge2.Top.Y;
+ ip.y() = Edge2.Top.y();
if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx))
- ip.X = TopX(Edge1, ip.Y);
+ ip.x() = TopX(Edge1, ip.y());
else
- ip.X = TopX(Edge2, ip.Y);
+ ip.x() = TopX(Edge2, ip.y());
}
- //finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ...
- if (ip.Y > Edge1.Curr.Y)
+ //finally, don't allow 'ip' to be BELOW curr.y() (ie bottom of scanbeam) ...
+ if (ip.y() > Edge1.Curr.y())
{
- ip.Y = Edge1.Curr.Y;
+ ip.y() = Edge1.Curr.y();
//use the more vertical edge to derive X ...
if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx))
- ip.X = TopX(Edge2, ip.Y); else
- ip.X = TopX(Edge1, ip.Y);
+ ip.x() = TopX(Edge2, ip.y()); else
+ ip.x() = TopX(Edge1, ip.y());
}
}
//------------------------------------------------------------------------------
@@ -429,7 +433,7 @@ inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt)
void InitEdge2(TEdge& e, PolyType Pt)
{
- if (e.Curr.Y >= e.Next->Curr.Y)
+ if (e.Curr.y() >= e.Next->Curr.y())
{
e.Bot = e.Curr;
e.Top = e.Next->Curr;
@@ -439,11 +443,11 @@ void InitEdge2(TEdge& e, PolyType Pt)
e.Bot = e.Next->Curr;
}
- e.Delta.X = (e.Top.X - e.Bot.X);
- e.Delta.Y = (e.Top.Y - e.Bot.Y);
+ e.Delta.x() = (e.Top.x() - e.Bot.x());
+ e.Delta.y() = (e.Top.y() - e.Bot.y());
- if (e.Delta.Y == 0) e.Dx = HORIZONTAL;
- else e.Dx = (double)(e.Delta.X) / e.Delta.Y;
+ if (e.Delta.y() == 0) e.Dx = HORIZONTAL;
+ else e.Dx = (double)(e.Delta.x()) / e.Delta.y();
e.PolyTyp = Pt;
}
@@ -466,9 +470,9 @@ inline void ReverseHorizontal(TEdge &e)
//swap horizontal edges' Top and Bottom x's so they follow the natural
//progression of the bounds - ie so their xbots will align with the
//adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
- std::swap(e.Top.X, e.Bot.X);
-#ifdef use_xyz
- std::swap(e.Top.Z, e.Bot.Z);
+ std::swap(e.Top.x(), e.Bot.x());
+#ifdef CLIPPERLIB_USE_XYZ
+ std::swap(e.Top.z(), e.Bot.z());
#endif
}
//------------------------------------------------------------------------------
@@ -477,20 +481,20 @@ bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a,
IntPoint pt2b, IntPoint &pt1, IntPoint &pt2)
{
//precondition: segments are Collinear.
- if (std::abs(pt1a.X - pt1b.X) > std::abs(pt1a.Y - pt1b.Y))
+ if (std::abs(pt1a.x() - pt1b.x()) > std::abs(pt1a.y() - pt1b.y()))
{
- if (pt1a.X > pt1b.X) std::swap(pt1a, pt1b);
- if (pt2a.X > pt2b.X) std::swap(pt2a, pt2b);
- if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a;
- if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b;
- return pt1.X < pt2.X;
+ if (pt1a.x() > pt1b.x()) std::swap(pt1a, pt1b);
+ if (pt2a.x() > pt2b.x()) std::swap(pt2a, pt2b);
+ if (pt1a.x() > pt2a.x()) pt1 = pt1a; else pt1 = pt2a;
+ if (pt1b.x() < pt2b.x()) pt2 = pt1b; else pt2 = pt2b;
+ return pt1.x() < pt2.x();
} else
{
- if (pt1a.Y < pt1b.Y) std::swap(pt1a, pt1b);
- if (pt2a.Y < pt2b.Y) std::swap(pt2a, pt2b);
- if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a;
- if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b;
- return pt1.Y > pt2.Y;
+ if (pt1a.y() < pt1b.y()) std::swap(pt1a, pt1b);
+ if (pt2a.y() < pt2b.y()) std::swap(pt2a, pt2b);
+ if (pt1a.y() < pt2a.y()) pt1 = pt1a; else pt1 = pt2a;
+ if (pt1b.y() > pt2b.y()) pt2 = pt1b; else pt2 = pt2b;
+ return pt1.y() > pt2.y();
}
}
//------------------------------------------------------------------------------
@@ -521,14 +525,14 @@ OutPt* GetBottomPt(OutPt *pp)
OutPt* p = pp->Next;
while (p != pp)
{
- if (p->Pt.Y > pp->Pt.Y)
+ if (p->Pt.y() > pp->Pt.y())
{
pp = p;
dups = 0;
}
- else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X)
+ else if (p->Pt.y() == pp->Pt.y() && p->Pt.x() <= pp->Pt.x())
{
- if (p->Pt.X < pp->Pt.X)
+ if (p->Pt.x() < pp->Pt.x())
{
dups = 0;
pp = p;
@@ -558,10 +562,10 @@ bool Pt2IsBetweenPt1AndPt3(const IntPoint &pt1,
{
if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2))
return false;
- else if (pt1.X != pt3.X)
- return (pt2.X > pt1.X) == (pt2.X < pt3.X);
+ else if (pt1.x() != pt3.x())
+ return (pt2.x() > pt1.x()) == (pt2.x() < pt3.x());
else
- return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y);
+ return (pt2.y() > pt1.y()) == (pt2.y() < pt3.y());
}
//------------------------------------------------------------------------------
@@ -582,10 +586,10 @@ inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
{
if (useFullRange)
{
- if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange)
+ if (Pt.x() > hiRange || Pt.y() > hiRange || -Pt.x() > hiRange || -Pt.y() > hiRange)
throw clipperException("Coordinate outside allowed range");
}
- else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange)
+ else if (Pt.x() > loRange|| Pt.y() > loRange || -Pt.x() > loRange || -Pt.y() > loRange)
{
useFullRange = true;
RangeTest(Pt, useFullRange);
@@ -605,8 +609,8 @@ inline TEdge* FindNextLocMin(TEdge* E)
while (IsHorizontal(*E->Prev)) E = E->Prev;
TEdge* E2 = E;
while (IsHorizontal(*E)) E = E->Next;
- if (E->Top.Y == E->Prev->Bot.Y) continue; //ie just an intermediate horz.
- if (E2->Prev->Bot.X < E->Bot.X) E = E2;
+ if (E->Top.y() == E->Prev->Bot.y()) continue; //ie just an intermediate horz.
+ if (E2->Prev->Bot.x() < E->Bot.x()) E = E2;
break;
}
return E;
@@ -625,14 +629,14 @@ TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
//create another LocMin and call ProcessBound once more
if (NextIsForward)
{
- while (E->Top.Y == E->Next->Bot.Y) E = E->Next;
+ while (E->Top.y() == E->Next->Bot.y()) E = E->Next;
//don't include top horizontals when parsing a bound a second time,
//they will be contained in the opposite bound ...
while (E != Result && IsHorizontal(*E)) E = E->Prev;
}
else
{
- while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev;
+ while (E->Top.y() == E->Prev->Bot.y()) E = E->Prev;
while (E != Result && IsHorizontal(*E)) E = E->Next;
}
@@ -649,7 +653,7 @@ TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
else
E = Result->Prev;
LocalMinimum locMin;
- locMin.Y = E->Bot.Y;
+ locMin.Y = E->Bot.y();
locMin.LeftBound = 0;
locMin.RightBound = E;
E->WindDelta = 0;
@@ -672,17 +676,17 @@ TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
EStart = E->Next;
if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge
{
- if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X)
+ if (EStart->Bot.x() != E->Bot.x() && EStart->Top.x() != E->Bot.x())
ReverseHorizontal(*E);
}
- else if (EStart->Bot.X != E->Bot.X)
+ else if (EStart->Bot.x() != E->Bot.x())
ReverseHorizontal(*E);
}
EStart = E;
if (NextIsForward)
{
- while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip)
+ while (Result->Top.y() == Result->Next->Bot.y() && Result->Next->OutIdx != Skip)
Result = Result->Next;
if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
{
@@ -691,38 +695,38 @@ TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
//unless a Skip edge is encountered when that becomes the top divide
Horz = Result;
while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev;
- if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev;
+ if (Horz->Prev->Top.x() > Result->Next->Top.x()) Result = Horz->Prev;
}
while (E != Result)
{
E->NextInLML = E->Next;
if (IsHorizontal(*E) && E != EStart &&
- E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
+ E->Bot.x() != E->Prev->Top.x()) ReverseHorizontal(*E);
E = E->Next;
}
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X)
+ if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Prev->Top.x())
ReverseHorizontal(*E);
Result = Result->Next; //move to the edge just beyond current bound
} else
{
- while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip)
+ while (Result->Top.y() == Result->Prev->Bot.y() && Result->Prev->OutIdx != Skip)
Result = Result->Prev;
if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip)
{
Horz = Result;
while (IsHorizontal(*Horz->Next)) Horz = Horz->Next;
- if (Horz->Next->Top.X == Result->Prev->Top.X ||
- Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next;
+ if (Horz->Next->Top.x() == Result->Prev->Top.x() ||
+ Horz->Next->Top.x() > Result->Prev->Top.x()) Result = Horz->Next;
}
while (E != Result)
{
E->NextInLML = E->Prev;
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
+ if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Next->Top.x())
ReverseHorizontal(*E);
E = E->Prev;
}
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
+ if (IsHorizontal(*E) && E != EStart && E->Bot.x() != E->Next->Top.x())
ReverseHorizontal(*E);
Result = Result->Prev; //move to the edge just beyond current bound
}
@@ -887,7 +891,7 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
{
InitEdge2(*E, PolyTyp);
E = E->Next;
- if (IsFlat && E->Curr.Y != eStart->Curr.Y) IsFlat = false;
+ if (IsFlat && E->Curr.y() != eStart->Curr.y()) IsFlat = false;
}
while (E != eStart);
@@ -903,14 +907,14 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
}
E->Prev->OutIdx = Skip;
LocalMinimum locMin;
- locMin.Y = E->Bot.Y;
+ locMin.Y = E->Bot.y();
locMin.LeftBound = 0;
locMin.RightBound = E;
locMin.RightBound->Side = esRight;
locMin.RightBound->WindDelta = 0;
for (;;)
{
- if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
+ if (E->Bot.x() != E->Prev->Top.x()) ReverseHorizontal(*E);
if (E->Next->OutIdx == Skip) break;
E->NextInLML = E->Next;
E = E->Next;
@@ -937,7 +941,7 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
//E and E.Prev now share a local minima (left aligned if horizontal).
//Compare their slopes to find which starts which bound ...
LocalMinimum locMin;
- locMin.Y = E->Bot.Y;
+ locMin.Y = E->Bot.y();
if (E->Dx < E->Prev->Dx)
{
locMin.LeftBound = E->Prev;
@@ -1028,27 +1032,27 @@ IntRect ClipperBase::GetBounds()
result.left = result.top = result.right = result.bottom = 0;
return result;
}
- result.left = lm->LeftBound->Bot.X;
- result.top = lm->LeftBound->Bot.Y;
- result.right = lm->LeftBound->Bot.X;
- result.bottom = lm->LeftBound->Bot.Y;
+ result.left = lm->LeftBound->Bot.x();
+ result.top = lm->LeftBound->Bot.y();
+ result.right = lm->LeftBound->Bot.x();
+ result.bottom = lm->LeftBound->Bot.y();
while (lm != m_MinimaList.end())
{
- result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y);
+ result.bottom = std::max(result.bottom, lm->LeftBound->Bot.y());
TEdge* e = lm->LeftBound;
for (;;) {
TEdge* bottomE = e;
while (e->NextInLML)
{
- if (e->Bot.X < result.left) result.left = e->Bot.X;
- if (e->Bot.X > result.right) result.right = e->Bot.X;
+ if (e->Bot.x() < result.left) result.left = e->Bot.x();
+ if (e->Bot.x() > result.right) result.right = e->Bot.x();
e = e->NextInLML;
}
- result.left = std::min(result.left, e->Bot.X);
- result.right = std::max(result.right, e->Bot.X);
- result.left = std::min(result.left, e->Top.X);
- result.right = std::max(result.right, e->Top.X);
- result.top = std::min(result.top, e->Top.Y);
+ result.left = std::min(result.left, e->Bot.x());
+ result.right = std::max(result.right, e->Bot.x());
+ result.left = std::min(result.left, e->Top.x());
+ result.right = std::max(result.right, e->Top.x());
+ result.top = std::min(result.top, e->Top.y());
if (bottomE == lm->LeftBound) e = lm->RightBound;
else break;
}
@@ -1073,7 +1077,7 @@ Clipper::Clipper(int initOptions) :
m_StrictSimple = ((initOptions & ioStrictlySimple) != 0);
m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0);
m_HasOpenPaths = false;
-#ifdef use_xyz
+#ifdef CLIPPERLIB_USE_XYZ
m_ZFill = 0;
#endif
}
@@ -1454,7 +1458,7 @@ OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
}
if (prevE && prevE->OutIdx >= 0 &&
- (TopX(*prevE, Pt.Y) == TopX(*e, Pt.Y)) &&
+ (TopX(*prevE, Pt.y()) == TopX(*e, Pt.y())) &&
SlopesEqual(*e, *prevE, m_UseFullRange) &&
(e->WindDelta != 0) && (prevE->WindDelta != 0))
{
@@ -1540,7 +1544,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
SetWindingCount(*lb);
if (IsContributing(*lb))
Op1 = AddOutPt(lb, lb->Bot);
- m_Scanbeam.push(lb->Top.Y);
+ m_Scanbeam.push(lb->Top.y());
}
else
{
@@ -1551,13 +1555,13 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
rb->WindCnt2 = lb->WindCnt2;
if (IsContributing(*lb))
Op1 = AddLocalMinPoly(lb, rb, lb->Bot);
- m_Scanbeam.push(lb->Top.Y);
+ m_Scanbeam.push(lb->Top.y());
}
if (rb)
{
if(IsHorizontal(*rb)) AddEdgeToSEL(rb);
- else m_Scanbeam.push(rb->Top.Y);
+ else m_Scanbeam.push(rb->Top.y());
}
if (!lb || !rb) continue;
@@ -1569,12 +1573,12 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
for (Join &jr : m_GhostJoins)
//if the horizontal Rb and a 'ghost' horizontal overlap, then convert
//the 'ghost' join to a real join ready for later ...
- if (HorzSegmentsOverlap(jr.OutPt1->Pt.X, jr.OffPt.X, rb->Bot.X, rb->Top.X))
+ if (HorzSegmentsOverlap(jr.OutPt1->Pt.x(), jr.OffPt.x(), rb->Bot.x(), rb->Top.x()))
m_Joins.emplace_back(Join(jr.OutPt1, Op1, jr.OffPt));
}
if (lb->OutIdx >= 0 && lb->PrevInAEL &&
- lb->PrevInAEL->Curr.X == lb->Bot.X &&
+ lb->PrevInAEL->Curr.x() == lb->Bot.x() &&
lb->PrevInAEL->OutIdx >= 0 &&
SlopesEqual(*lb->PrevInAEL, *lb, m_UseFullRange) &&
(lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0))
@@ -1637,14 +1641,14 @@ void Clipper::DeleteFromSEL(TEdge *e)
}
//------------------------------------------------------------------------------
-#ifdef use_xyz
+#ifdef CLIPPERLIB_USE_XYZ
void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2)
{
- if (pt.Z != 0 || !m_ZFill) return;
- else if (pt == e1.Bot) pt.Z = e1.Bot.Z;
- else if (pt == e1.Top) pt.Z = e1.Top.Z;
- else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
- else if (pt == e2.Top) pt.Z = e2.Top.Z;
+ if (pt.z() != 0 || !m_ZFill) return;
+ else if (pt == e1.Bot) pt.z() = e1.Bot.z();
+ else if (pt == e1.Top) pt.z() = e1.Top.z();
+ else if (pt == e2.Bot) pt.z() = e2.Bot.z();
+ else if (pt == e2.Top) pt.z() = e2.Top.z();
else m_ZFill(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
}
//------------------------------------------------------------------------------
@@ -1655,7 +1659,7 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt)
bool e1Contributing = ( e1->OutIdx >= 0 );
bool e2Contributing = ( e2->OutIdx >= 0 );
-#ifdef use_xyz
+#ifdef CLIPPERLIB_USE_XYZ
SetZ(Pt, *e1, *e2);
#endif
@@ -1872,10 +1876,10 @@ OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
outRec2->BottomPt = GetBottomPt(outRec2->Pts);
OutPt *OutPt1 = outRec1->BottomPt;
OutPt *OutPt2 = outRec2->BottomPt;
- if (OutPt1->Pt.Y > OutPt2->Pt.Y) return outRec1;
- else if (OutPt1->Pt.Y < OutPt2->Pt.Y) return outRec2;
- else if (OutPt1->Pt.X < OutPt2->Pt.X) return outRec1;
- else if (OutPt1->Pt.X > OutPt2->Pt.X) return outRec2;
+ if (OutPt1->Pt.y() > OutPt2->Pt.y()) return outRec1;
+ else if (OutPt1->Pt.y() < OutPt2->Pt.y()) return outRec2;
+ else if (OutPt1->Pt.x() < OutPt2->Pt.x()) return outRec1;
+ else if (OutPt1->Pt.x() > OutPt2->Pt.x()) return outRec2;
else if (OutPt1->Next == OutPt1) return outRec2;
else if (OutPt2->Next == OutPt2) return outRec1;
else if (FirstIsBottomPt(OutPt1, OutPt2)) return outRec1;
@@ -2081,13 +2085,13 @@ void Clipper::ProcessHorizontals()
inline bool IsMaxima(TEdge *e, const cInt Y)
{
- return e && e->Top.Y == Y && !e->NextInLML;
+ return e && e->Top.y() == Y && !e->NextInLML;
}
//------------------------------------------------------------------------------
inline bool IsIntermediate(TEdge *e, const cInt Y)
{
- return e->Top.Y == Y && e->NextInLML;
+ return e->Top.y() == Y && e->NextInLML;
}
//------------------------------------------------------------------------------
@@ -2202,15 +2206,15 @@ void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2)
inline void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right)
{
- if (HorzEdge.Bot.X < HorzEdge.Top.X)
+ if (HorzEdge.Bot.x() < HorzEdge.Top.x())
{
- Left = HorzEdge.Bot.X;
- Right = HorzEdge.Top.X;
+ Left = HorzEdge.Bot.x();
+ Right = HorzEdge.Top.x();
Dir = dLeftToRight;
} else
{
- Left = HorzEdge.Top.X;
- Right = HorzEdge.Bot.X;
+ Left = HorzEdge.Top.x();
+ Right = HorzEdge.Bot.x();
Dir = dRightToLeft;
}
}
@@ -2219,8 +2223,8 @@ inline void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt&
/*******************************************************************************
* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or *
* Bottom of a scanbeam) are processed as if layered. The order in which HEs *
-* are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#] *
-* (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs), *
+* are processed doesn't matter. HEs intersect with other HE Bot.x()s only [#] *
+* (or they could intersect with Top.x()s only, ie EITHER Bot.x()s OR Top.x()s), *
* and with other non-horizontal edges [*]. Once these intersections are *
* processed, intermediate HEs then 'promote' the Edge above (NextInLML) into *
* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. *
@@ -2248,15 +2252,15 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
if (dir == dLeftToRight)
{
maxIt = m_Maxima.begin();
- while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X) ++maxIt;
- if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X)
+ while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.x()) ++maxIt;
+ if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.x())
maxIt = m_Maxima.end();
}
else
{
maxRit = m_Maxima.rbegin();
- while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X) ++maxRit;
- if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X)
+ while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.x()) ++maxRit;
+ if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.x())
maxRit = m_Maxima.rend();
}
}
@@ -2278,30 +2282,30 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
{
if (dir == dLeftToRight)
{
- while (maxIt != m_Maxima.end() && *maxIt < e->Curr.X)
+ while (maxIt != m_Maxima.end() && *maxIt < e->Curr.x())
{
if (horzEdge->OutIdx >= 0 && !IsOpen)
- AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.Y));
+ AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.y()));
++maxIt;
}
}
else
{
- while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.X)
+ while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.x())
{
if (horzEdge->OutIdx >= 0 && !IsOpen)
- AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.Y));
+ AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.y()));
++maxRit;
}
}
};
- if ((dir == dLeftToRight && e->Curr.X > horzRight) ||
- (dir == dRightToLeft && e->Curr.X < horzLeft)) break;
+ if ((dir == dLeftToRight && e->Curr.x() > horzRight) ||
+ (dir == dRightToLeft && e->Curr.x() < horzLeft)) break;
//Also break if we've got to the end of an intermediate horizontal edge ...
//nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
- if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML &&
+ if (e->Curr.x() == horzEdge->Top.x() && horzEdge->NextInLML &&
e->Dx < horzEdge->NextInLML->Dx) break;
if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times
@@ -2311,8 +2315,8 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
while (eNextHorz)
{
if (eNextHorz->OutIdx >= 0 &&
- HorzSegmentsOverlap(horzEdge->Bot.X,
- horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
+ HorzSegmentsOverlap(horzEdge->Bot.x(),
+ horzEdge->Top.x(), eNextHorz->Bot.x(), eNextHorz->Top.x()))
{
OutPt* op2 = GetLastOutPt(eNextHorz);
m_Joins.emplace_back(Join(op2, op1, eNextHorz->Top));
@@ -2335,12 +2339,12 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
if(dir == dLeftToRight)
{
- IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
+ IntPoint Pt = IntPoint(e->Curr.x(), horzEdge->Curr.y());
IntersectEdges(horzEdge, e, Pt);
}
else
{
- IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
+ IntPoint Pt = IntPoint(e->Curr.x(), horzEdge->Curr.y());
IntersectEdges( e, horzEdge, Pt);
}
TEdge* eNext = (dir == dLeftToRight) ? e->NextInAEL : e->PrevInAEL;
@@ -2364,8 +2368,8 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
while (eNextHorz)
{
if (eNextHorz->OutIdx >= 0 &&
- HorzSegmentsOverlap(horzEdge->Bot.X,
- horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
+ HorzSegmentsOverlap(horzEdge->Bot.x(),
+ horzEdge->Top.x(), eNextHorz->Bot.x(), eNextHorz->Top.x()))
{
OutPt* op2 = GetLastOutPt(eNextHorz);
m_Joins.emplace_back(Join(op2, op1, eNextHorz->Top));
@@ -2385,17 +2389,17 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
//nb: HorzEdge is no longer horizontal here
TEdge* ePrev = horzEdge->PrevInAEL;
TEdge* eNext = horzEdge->NextInAEL;
- if (ePrev && ePrev->Curr.X == horzEdge->Bot.X &&
- ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 &&
- (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
+ if (ePrev && ePrev->Curr.x() == horzEdge->Bot.x() &&
+ ePrev->Curr.y() == horzEdge->Bot.y() && ePrev->WindDelta != 0 &&
+ (ePrev->OutIdx >= 0 && ePrev->Curr.y() > ePrev->Top.y() &&
SlopesEqual(*horzEdge, *ePrev, m_UseFullRange)))
{
OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot);
m_Joins.emplace_back(Join(op1, op2, horzEdge->Top));
}
- else if (eNext && eNext->Curr.X == horzEdge->Bot.X &&
- eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 &&
- eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
+ else if (eNext && eNext->Curr.x() == horzEdge->Bot.x() &&
+ eNext->Curr.y() == horzEdge->Bot.y() && eNext->WindDelta != 0 &&
+ eNext->OutIdx >= 0 && eNext->Curr.y() > eNext->Top.y() &&
SlopesEqual(*horzEdge, *eNext, m_UseFullRange))
{
OutPt* op2 = AddOutPt(eNext, horzEdge->Bot);
@@ -2433,7 +2437,7 @@ void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
e->PrevInAEL = AelPrev;
e->NextInAEL = AelNext;
if (!IsHorizontal(*e))
- m_Scanbeam.push(e->Top.Y);
+ m_Scanbeam.push(e->Top.y());
}
//------------------------------------------------------------------------------
@@ -2476,7 +2480,7 @@ void Clipper::BuildIntersectList(const cInt topY)
{
e->PrevInSEL = e->PrevInAEL;
e->NextInSEL = e->NextInAEL;
- e->Curr.X = TopX( *e, topY );
+ e->Curr.x() = TopX( *e, topY );
e = e->NextInAEL;
}
@@ -2490,7 +2494,7 @@ void Clipper::BuildIntersectList(const cInt topY)
{
TEdge *eNext = e->NextInSEL;
IntPoint Pt;
- if(e->Curr.X > eNext->Curr.X)
+ if(e->Curr.x() > eNext->Curr.x())
{
IntersectPoint(*e, *eNext, Pt);
m_IntersectList.emplace_back(IntersectNode(e, eNext, Pt));
@@ -2522,7 +2526,7 @@ bool Clipper::FixupIntersectionOrder()
//Now it's crucial that intersections are made only between adjacent edges,
//so to ensure this the order of intersections may need adjusting ...
CopyAELToSEL();
- std::sort(m_IntersectList.begin(), m_IntersectList.end(), [](const IntersectNode &node1, const IntersectNode &node2) { return node2.Pt.Y < node1.Pt.Y; });
+ std::sort(m_IntersectList.begin(), m_IntersectList.end(), [](const IntersectNode &node1, const IntersectNode &node2) { return node2.Pt.y() < node1.Pt.y(); });
size_t cnt = m_IntersectList.size();
for (size_t i = 0; i < cnt; ++i)
@@ -2610,7 +2614,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
if(IsMaximaEdge)
{
- if (m_StrictSimple) m_Maxima.push_back(e->Top.X);
+ if (m_StrictSimple) m_Maxima.push_back(e->Top.x());
TEdge* ePrev = e->PrevInAEL;
DoMaxima(e);
if( !ePrev ) e = m_ActiveEdges;
@@ -2618,7 +2622,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
}
else
{
- //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ...
+ //2. promote horizontal edges, otherwise update Curr.x() and Curr.y() ...
if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML))
{
UpdateEdgeIntoAEL(e);
@@ -2628,8 +2632,8 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
}
else
{
- e->Curr.X = TopX( *e, topY );
- e->Curr.Y = topY;
+ e->Curr.x() = TopX( *e, topY );
+ e->Curr.y() = topY;
}
//When StrictlySimple and 'e' is being touched by another edge, then
@@ -2638,10 +2642,10 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
{
TEdge* ePrev = e->PrevInAEL;
if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) &&
- (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0))
+ (ePrev->Curr.x() == e->Curr.x()) && (ePrev->WindDelta != 0))
{
IntPoint pt = e->Curr;
-#ifdef use_xyz
+#ifdef CLIPPERLIB_USE_XYZ
SetZ(pt, *ePrev, *e);
#endif
OutPt* op = AddOutPt(ePrev, pt);
@@ -2673,18 +2677,18 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
//if output polygons share an edge, they'll need joining later ...
TEdge* ePrev = e->PrevInAEL;
TEdge* eNext = e->NextInAEL;
- if (ePrev && ePrev->Curr.X == e->Bot.X &&
- ePrev->Curr.Y == e->Bot.Y && op &&
- ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
+ if (ePrev && ePrev->Curr.x() == e->Bot.x() &&
+ ePrev->Curr.y() == e->Bot.y() && op &&
+ ePrev->OutIdx >= 0 && ePrev->Curr.y() > ePrev->Top.y() &&
SlopesEqual(*e, *ePrev, m_UseFullRange) &&
(e->WindDelta != 0) && (ePrev->WindDelta != 0))
{
OutPt* op2 = AddOutPt(ePrev, e->Bot);
m_Joins.emplace_back(Join(op, op2, e->Top));
}
- else if (eNext && eNext->Curr.X == e->Bot.X &&
- eNext->Curr.Y == e->Bot.Y && op &&
- eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
+ else if (eNext && eNext->Curr.x() == e->Bot.x() &&
+ eNext->Curr.y() == e->Bot.y() && op &&
+ eNext->OutIdx >= 0 && eNext->Curr.y() > eNext->Top.y() &&
SlopesEqual(*e, *eNext, m_UseFullRange) &&
(e->WindDelta != 0) && (eNext->WindDelta != 0))
{
@@ -2861,13 +2865,13 @@ void Clipper::BuildResult2(PolyTree& polytree)
inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
{
- if (e2.Curr.X == e1.Curr.X)
+ if (e2.Curr.x() == e1.Curr.x())
{
- if (e2.Top.Y > e1.Top.Y)
- return e2.Top.X < TopX(e1, e2.Top.Y);
- else return e1.Top.X > TopX(e2, e1.Top.Y);
+ if (e2.Top.y() > e1.Top.y())
+ return e2.Top.x() < TopX(e1, e2.Top.y());
+ else return e1.Top.x() > TopX(e2, e1.Top.y());
}
- else return e2.Curr.X < e1.Curr.X;
+ else return e2.Curr.x() < e1.Curr.x();
}
//------------------------------------------------------------------------------
@@ -2956,8 +2960,8 @@ OutPt* Clipper::DupOutPt(OutPt* outPt, bool InsertAfter)
bool Clipper::JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b,
const IntPoint &Pt, bool DiscardLeft)
{
- Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight);
- Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight);
+ Direction Dir1 = (op1->Pt.x() > op1b->Pt.x() ? dRightToLeft : dLeftToRight);
+ Direction Dir2 = (op2->Pt.x() > op2b->Pt.x() ? dRightToLeft : dLeftToRight);
if (Dir1 == Dir2) return false;
//When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we
@@ -2967,10 +2971,10 @@ bool Clipper::JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b,
//otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.)
if (Dir1 == dLeftToRight)
{
- while (op1->Next->Pt.X <= Pt.X &&
- op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y)
+ while (op1->Next->Pt.x() <= Pt.x() &&
+ op1->Next->Pt.x() >= op1->Pt.x() && op1->Next->Pt.y() == Pt.y())
op1 = op1->Next;
- if (DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next;
+ if (DiscardLeft && (op1->Pt.x() != Pt.x())) op1 = op1->Next;
op1b = this->DupOutPt(op1, !DiscardLeft);
if (op1b->Pt != Pt)
{
@@ -2981,10 +2985,10 @@ bool Clipper::JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b,
}
else
{
- while (op1->Next->Pt.X >= Pt.X &&
- op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y)
+ while (op1->Next->Pt.x() >= Pt.x() &&
+ op1->Next->Pt.x() <= op1->Pt.x() && op1->Next->Pt.y() == Pt.y())
op1 = op1->Next;
- if (!DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next;
+ if (!DiscardLeft && (op1->Pt.x() != Pt.x())) op1 = op1->Next;
op1b = this->DupOutPt(op1, DiscardLeft);
if (op1b->Pt != Pt)
{
@@ -2996,10 +3000,10 @@ bool Clipper::JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b,
if (Dir2 == dLeftToRight)
{
- while (op2->Next->Pt.X <= Pt.X &&
- op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y)
+ while (op2->Next->Pt.x() <= Pt.x() &&
+ op2->Next->Pt.x() >= op2->Pt.x() && op2->Next->Pt.y() == Pt.y())
op2 = op2->Next;
- if (DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next;
+ if (DiscardLeft && (op2->Pt.x() != Pt.x())) op2 = op2->Next;
op2b = this->DupOutPt(op2, !DiscardLeft);
if (op2b->Pt != Pt)
{
@@ -3009,10 +3013,10 @@ bool Clipper::JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b,
};
} else
{
- while (op2->Next->Pt.X >= Pt.X &&
- op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y)
+ while (op2->Next->Pt.x() >= Pt.x() &&
+ op2->Next->Pt.x() <= op2->Pt.x() && op2->Next->Pt.y() == Pt.y())
op2 = op2->Next;
- if (!DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next;
+ if (!DiscardLeft && (op2->Pt.x() != Pt.x())) op2 = op2->Next;
op2b = this->DupOutPt(op2, DiscardLeft);
if (op2b->Pt != Pt)
{
@@ -3052,7 +3056,7 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
//location at the Bottom of the overlapping segment (& Join.OffPt is above).
//3. StrictSimple joins where edges touch but are not collinear and where
//Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point.
- bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y);
+ bool isHorizontal = (j->OutPt1->Pt.y() == j->OffPt.y());
if (isHorizontal && (j->OffPt == j->OutPt1->Pt) &&
(j->OffPt == j->OutPt2->Pt))
@@ -3062,11 +3066,11 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
op1b = j->OutPt1->Next;
while (op1b != op1 && (op1b->Pt == j->OffPt))
op1b = op1b->Next;
- bool reverse1 = (op1b->Pt.Y > j->OffPt.Y);
+ bool reverse1 = (op1b->Pt.y() > j->OffPt.y());
op2b = j->OutPt2->Next;
while (op2b != op2 && (op2b->Pt == j->OffPt))
op2b = op2b->Next;
- bool reverse2 = (op2b->Pt.Y > j->OffPt.Y);
+ bool reverse2 = (op2b->Pt.y() > j->OffPt.y());
if (reverse1 == reverse2) return false;
if (reverse1)
{
@@ -3098,22 +3102,22 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
//them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt
//may be anywhere along the horizontal edge.
op1b = op1;
- while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2)
+ while (op1->Prev->Pt.y() == op1->Pt.y() && op1->Prev != op1b && op1->Prev != op2)
op1 = op1->Prev;
- while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2)
+ while (op1b->Next->Pt.y() == op1b->Pt.y() && op1b->Next != op1 && op1b->Next != op2)
op1b = op1b->Next;
if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon'
op2b = op2;
- while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b)
+ while (op2->Prev->Pt.y() == op2->Pt.y() && op2->Prev != op2b && op2->Prev != op1b)
op2 = op2->Prev;
- while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1)
+ while (op2b->Next->Pt.y() == op2b->Pt.y() && op2b->Next != op2 && op2b->Next != op1)
op2b = op2b->Next;
if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon'
cInt Left, Right;
//Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges
- if (!GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right))
+ if (!GetOverlap(op1->Pt.x(), op1b->Pt.x(), op2->Pt.x(), op2b->Pt.x(), Left, Right))
return false;
//DiscardLeftSide: when overlapping edges are joined, a spike will created
@@ -3121,51 +3125,51 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
//on the discard Side as either may still be needed for other joins ...
IntPoint Pt;
bool DiscardLeftSide;
- if (op1->Pt.X >= Left && op1->Pt.X <= Right)
+ if (op1->Pt.x() >= Left && op1->Pt.x() <= Right)
{
- Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X);
+ Pt = op1->Pt; DiscardLeftSide = (op1->Pt.x() > op1b->Pt.x());
}
- else if (op2->Pt.X >= Left&& op2->Pt.X <= Right)
+ else if (op2->Pt.x() >= Left&& op2->Pt.x() <= Right)
{
- Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X);
+ Pt = op2->Pt; DiscardLeftSide = (op2->Pt.x() > op2b->Pt.x());
}
- else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right)
+ else if (op1b->Pt.x() >= Left && op1b->Pt.x() <= Right)
{
- Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X;
+ Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.x() > op1->Pt.x();
}
else
{
- Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X);
+ Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.x() > op2->Pt.x());
}
j->OutPt1 = op1; j->OutPt2 = op2;
return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide);
} else
{
//nb: For non-horizontal joins ...
- // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y
- // 2. Jr.OutPt1.Pt > Jr.OffPt.Y
+ // 1. Jr.OutPt1.Pt.y() == Jr.OutPt2.Pt.y()
+ // 2. Jr.OutPt1.Pt > Jr.OffPt.y()
//make sure the polygons are correctly oriented ...
op1b = op1->Next;
while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next;
- bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) ||
+ bool Reverse1 = ((op1b->Pt.y() > op1->Pt.y()) ||
!SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange));
if (Reverse1)
{
op1b = op1->Prev;
while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev;
- if ((op1b->Pt.Y > op1->Pt.Y) ||
+ if ((op1b->Pt.y() > op1->Pt.y()) ||
!SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false;
};
op2b = op2->Next;
while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next;
- bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) ||
+ bool Reverse2 = ((op2b->Pt.y() > op2->Pt.y()) ||
!SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange));
if (Reverse2)
{
op2b = op2->Prev;
while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev;
- if ((op2b->Pt.Y > op2->Pt.Y) ||
+ if ((op2b->Pt.y() > op2->Pt.y()) ||
!SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false;
}
@@ -3334,11 +3338,11 @@ void Clipper::JoinCommonEdges()
DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
{
- if(pt2.X == pt1.X && pt2.Y == pt1.Y)
+ if(pt2.x() == pt1.x() && pt2.y() == pt1.y())
return DoublePoint(0, 0);
- double Dx = double(pt2.X - pt1.X);
- double dy = double(pt2.Y - pt1.Y);
+ double Dx = double(pt2.x() - pt1.x());
+ double dy = double(pt2.y() - pt1.y());
double f = 1.0 / std::sqrt( Dx*Dx + dy*dy );
Dx *= f;
dy *= f;
@@ -3354,7 +3358,7 @@ void ClipperOffset::Clear()
for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
delete m_polyNodes.Childs[i];
m_polyNodes.Childs.clear();
- m_lowest.X = -1;
+ m_lowest.x() = -1;
}
//------------------------------------------------------------------------------
@@ -3373,8 +3377,8 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
for (; highI > 0; -- highI) {
bool same = false;
if (has_shortest_edge_length) {
- double dx = double(path[highI].X - path[0].X);
- double dy = double(path[highI].Y - path[0].Y);
+ double dx = double(path[highI].x() - path[0].x());
+ double dy = double(path[highI].y() - path[0].y());
same = dx*dx + dy*dy < shortest_edge_length2;
} else
same = path[0] == path[highI];
@@ -3387,8 +3391,8 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
for (int i = 1; i <= highI; i++) {
bool same = false;
if (has_shortest_edge_length) {
- double dx = double(path[i].X - newNode->Contour[j].X);
- double dy = double(path[i].Y - newNode->Contour[j].Y);
+ double dx = double(path[i].x() - newNode->Contour[j].x());
+ double dy = double(path[i].y() - newNode->Contour[j].y());
same = dx*dx + dy*dy < shortest_edge_length2;
} else
same = newNode->Contour[j] == path[i];
@@ -3396,9 +3400,9 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
continue;
j++;
newNode->Contour.push_back(path[i]);
- if (path[i].Y > newNode->Contour[k].Y ||
- (path[i].Y == newNode->Contour[k].Y &&
- path[i].X < newNode->Contour[k].X)) k = j;
+ if (path[i].y() > newNode->Contour[k].y() ||
+ (path[i].y() == newNode->Contour[k].y() &&
+ path[i].x() < newNode->Contour[k].x())) k = j;
}
if (endType == etClosedPolygon && j < 2)
{
@@ -3409,14 +3413,14 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
//if this path's lowest pt is lower than all the others then update m_lowest
if (endType != etClosedPolygon) return;
- if (m_lowest.X < 0)
+ if (m_lowest.x() < 0)
m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
else
{
- IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y];
- if (newNode->Contour[k].Y > ip.Y ||
- (newNode->Contour[k].Y == ip.Y &&
- newNode->Contour[k].X < ip.X))
+ IntPoint ip = m_polyNodes.Childs[(int)m_lowest.x()]->Contour[(int)m_lowest.y()];
+ if (newNode->Contour[k].y() > ip.y() ||
+ (newNode->Contour[k].y() == ip.y() &&
+ newNode->Contour[k].x() < ip.x()))
m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
}
}
@@ -3433,8 +3437,8 @@ void ClipperOffset::FixOrientations()
{
//fixup orientations of all closed paths if the orientation of the
//closed path with the lowermost vertex is wrong ...
- if (m_lowest.X >= 0 &&
- !Orientation(m_polyNodes.Childs[(int)m_lowest.X]->Contour))
+ if (m_lowest.x() >= 0 &&
+ !Orientation(m_polyNodes.Childs[(int)m_lowest.x()]->Contour))
{
for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
{
@@ -3582,8 +3586,8 @@ void ClipperOffset::DoOffset(double delta)
for (cInt j = 1; j <= steps; j++)
{
m_destPoly.push_back(IntPoint(
- Round(m_srcPoly[0].X + X * delta),
- Round(m_srcPoly[0].Y + Y * delta)));
+ Round(m_srcPoly[0].x() + X * delta),
+ Round(m_srcPoly[0].y() + Y * delta)));
double X2 = X;
X = X * m_cos - m_sin * Y;
Y = X2 * m_sin + Y * m_cos;
@@ -3595,8 +3599,8 @@ void ClipperOffset::DoOffset(double delta)
for (int j = 0; j < 4; ++j)
{
m_destPoly.push_back(IntPoint(
- Round(m_srcPoly[0].X + X * delta),
- Round(m_srcPoly[0].Y + Y * delta)));
+ Round(m_srcPoly[0].x() + X * delta),
+ Round(m_srcPoly[0].y() + Y * delta)));
if (X < 0) X = 1;
else if (Y < 0) Y = 1;
else X = -1;
@@ -3632,8 +3636,8 @@ void ClipperOffset::DoOffset(double delta)
//re-build m_normals ...
DoublePoint n = m_normals[len -1];
for (int j = len - 1; j > 0; j--)
- m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y);
- m_normals[0] = DoublePoint(-n.X, -n.Y);
+ m_normals[j] = DoublePoint(-m_normals[j - 1].x(), -m_normals[j - 1].y());
+ m_normals[0] = DoublePoint(-n.x(), -n.y());
k = 0;
for (int j = len - 1; j >= 0; j--)
OffsetPoint(j, k, node.m_jointype);
@@ -3649,9 +3653,9 @@ void ClipperOffset::DoOffset(double delta)
if (node.m_endtype == etOpenButt)
{
int j = len - 1;
- pt1 = IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * delta), Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
+ pt1 = IntPoint(Round(m_srcPoly[j].x() + m_normals[j].x() * delta), Round(m_srcPoly[j].y() + m_normals[j].y() * delta));
m_destPoly.push_back(pt1);
- pt1 = IntPoint(Round(m_srcPoly[j].X - m_normals[j].X * delta), Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
+ pt1 = IntPoint(Round(m_srcPoly[j].x() - m_normals[j].x() * delta), Round(m_srcPoly[j].y() - m_normals[j].y() * delta));
m_destPoly.push_back(pt1);
}
else
@@ -3659,7 +3663,7 @@ void ClipperOffset::DoOffset(double delta)
int j = len - 1;
k = len - 2;
m_sinA = 0;
- m_normals[j] = DoublePoint(-m_normals[j].X, -m_normals[j].Y);
+ m_normals[j] = DoublePoint(-m_normals[j].x(), -m_normals[j].y());
if (node.m_endtype == etOpenSquare)
DoSquare(j, k);
else
@@ -3668,17 +3672,17 @@ void ClipperOffset::DoOffset(double delta)
//re-build m_normals ...
for (int j = len - 1; j > 0; j--)
- m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y);
- m_normals[0] = DoublePoint(-m_normals[1].X, -m_normals[1].Y);
+ m_normals[j] = DoublePoint(-m_normals[j - 1].x(), -m_normals[j - 1].y());
+ m_normals[0] = DoublePoint(-m_normals[1].x(), -m_normals[1].y());
k = len - 1;
for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype);
if (node.m_endtype == etOpenButt)
{
- pt1 = IntPoint(Round(m_srcPoly[0].X - m_normals[0].X * delta), Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
+ pt1 = IntPoint(Round(m_srcPoly[0].x() - m_normals[0].x() * delta), Round(m_srcPoly[0].y() - m_normals[0].y() * delta));
m_destPoly.push_back(pt1);
- pt1 = IntPoint(Round(m_srcPoly[0].X + m_normals[0].X * delta), Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
+ pt1 = IntPoint(Round(m_srcPoly[0].x() + m_normals[0].x() * delta), Round(m_srcPoly[0].y() + m_normals[0].y() * delta));
m_destPoly.push_back(pt1);
}
else
@@ -3699,15 +3703,15 @@ void ClipperOffset::DoOffset(double delta)
void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype)
{
//cross product ...
- m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y);
+ m_sinA = (m_normals[k].x() * m_normals[j].y() - m_normals[j].x() * m_normals[k].y());
if (std::fabs(m_sinA * m_delta) < 1.0)
{
//dot product ...
- double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y );
+ double cosA = (m_normals[k].x() * m_normals[j].x() + m_normals[j].y() * m_normals[k].y() );
if (cosA > 0) // angle => 0 degrees
{
- m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
- Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
+ m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].x() + m_normals[k].x() * m_delta),
+ Round(m_srcPoly[j].y() + m_normals[k].y() * m_delta)));
return;
}
//else angle => 180 degrees
@@ -3717,19 +3721,19 @@ void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype)
if (m_sinA * m_delta < 0)
{
- m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
- Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
+ m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].x() + m_normals[k].x() * m_delta),
+ Round(m_srcPoly[j].y() + m_normals[k].y() * m_delta)));
m_destPoly.push_back(m_srcPoly[j]);
- m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta),
- Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta)));
+ m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].x() + m_normals[j].x() * m_delta),
+ Round(m_srcPoly[j].y() + m_normals[j].y() * m_delta)));
}
else
switch (jointype)
{
case jtMiter:
{
- double r = 1 + (m_normals[j].X * m_normals[k].X +
- m_normals[j].Y * m_normals[k].Y);
+ double r = 1 + (m_normals[j].x() * m_normals[k].x() +
+ m_normals[j].y() * m_normals[k].y());
if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k);
break;
}
@@ -3743,43 +3747,43 @@ void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype)
void ClipperOffset::DoSquare(int j, int k)
{
double dx = std::tan(std::atan2(m_sinA,
- m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4);
+ m_normals[k].x() * m_normals[j].x() + m_normals[k].y() * m_normals[j].y()) / 4);
m_destPoly.push_back(IntPoint(
- Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)),
- Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx))));
+ Round(m_srcPoly[j].x() + m_delta * (m_normals[k].x() - m_normals[k].y() * dx)),
+ Round(m_srcPoly[j].y() + m_delta * (m_normals[k].y() + m_normals[k].x() * dx))));
m_destPoly.push_back(IntPoint(
- Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)),
- Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx))));
+ Round(m_srcPoly[j].x() + m_delta * (m_normals[j].x() + m_normals[j].y() * dx)),
+ Round(m_srcPoly[j].y() + m_delta * (m_normals[j].y() - m_normals[j].x() * dx))));
}
//------------------------------------------------------------------------------
void ClipperOffset::DoMiter(int j, int k, double r)
{
double q = m_delta / r;
- m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q),
- Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q)));
+ m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].x() + (m_normals[k].x() + m_normals[j].x()) * q),
+ Round(m_srcPoly[j].y() + (m_normals[k].y() + m_normals[j].y()) * q)));
}
//------------------------------------------------------------------------------
void ClipperOffset::DoRound(int j, int k)
{
double a = std::atan2(m_sinA,
- m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y);
+ m_normals[k].x() * m_normals[j].x() + m_normals[k].y() * m_normals[j].y());
auto steps = std::max(Round(m_StepsPerRad * std::fabs(a)), 1);
- double X = m_normals[k].X, Y = m_normals[k].Y, X2;
+ double X = m_normals[k].x(), Y = m_normals[k].y(), X2;
for (int i = 0; i < steps; ++i)
{
m_destPoly.push_back(IntPoint(
- Round(m_srcPoly[j].X + X * m_delta),
- Round(m_srcPoly[j].Y + Y * m_delta)));
+ Round(m_srcPoly[j].x() + X * m_delta),
+ Round(m_srcPoly[j].y() + Y * m_delta)));
X2 = X;
X = X * m_cos - m_sin * Y;
Y = X2 * m_sin + Y * m_cos;
}
m_destPoly.push_back(IntPoint(
- Round(m_srcPoly[j].X + m_normals[j].X * m_delta),
- Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta)));
+ Round(m_srcPoly[j].x() + m_normals[j].x() * m_delta),
+ Round(m_srcPoly[j].y() + m_normals[j].y() * m_delta)));
}
//------------------------------------------------------------------------------
@@ -3897,8 +3901,8 @@ void SimplifyPolygons(Paths &polys, PolyFillType fillType)
inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2)
{
- auto Dx = double(pt1.X - pt2.X);
- auto dy = double(pt1.Y - pt2.Y);
+ auto Dx = double(pt1.x() - pt2.x());
+ auto dy = double(pt1.y() - pt2.y());
return (Dx*Dx + dy*dy);
}
//------------------------------------------------------------------------------
@@ -3912,10 +3916,10 @@ double DistanceFromLineSqrd(
//A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹
//perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
//see http://en.wikipedia.org/wiki/Perpendicular_distance
- double A = double(ln1.Y - ln2.Y);
- double B = double(ln2.X - ln1.X);
- double C = A * ln1.X + B * ln1.Y;
- C = A * pt.X + B * pt.Y - C;
+ double A = double(ln1.y() - ln2.y());
+ double B = double(ln2.x() - ln1.x());
+ double C = A * ln1.x() + B * ln1.y();
+ C = A * pt.x() + B * pt.y() - C;
return (C * C) / (A * A + B * B);
}
//---------------------------------------------------------------------------
@@ -3926,20 +3930,20 @@ bool SlopesNearCollinear(const IntPoint& pt1,
//this function is more accurate when the point that's geometrically
//between the other 2 points is the one that's tested for distance.
//ie makes it more likely to pick up 'spikes' ...
- if (std::abs(pt1.X - pt2.X) > std::abs(pt1.Y - pt2.Y))
+ if (std::abs(pt1.x() - pt2.x()) > std::abs(pt1.y() - pt2.y()))
{
- if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
+ if ((pt1.x() > pt2.x()) == (pt1.x() < pt3.x()))
return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
- else if ((pt2.X > pt1.X) == (pt2.X < pt3.X))
+ else if ((pt2.x() > pt1.x()) == (pt2.x() < pt3.x()))
return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
else
return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
}
else
{
- if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y))
+ if ((pt1.y() > pt2.y()) == (pt1.y() < pt3.y()))
return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
- else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y))
+ else if ((pt2.y() > pt1.y()) == (pt2.y() < pt3.y()))
return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
else
return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
@@ -3949,8 +3953,8 @@ bool SlopesNearCollinear(const IntPoint& pt1,
bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
{
- auto Dx = double(pt1.X - pt2.X);
- auto dy = double(pt1.Y - pt2.Y);
+ auto Dx = double(pt1.x() - pt2.x());
+ auto dy = double(pt1.y() - pt2.y());
return ((Dx * Dx) + (dy * dy) <= distSqrd);
}
//------------------------------------------------------------------------------
@@ -4058,7 +4062,7 @@ void Minkowski(const Path& poly, const Path& path,
Path p;
p.reserve(polyCnt);
for (size_t j = 0; j < poly.size(); ++j)
- p.push_back(IntPoint(path[i].X + poly[j].X, path[i].Y + poly[j].Y));
+ p.push_back(IntPoint(path[i].x() + poly[j].x(), path[i].y() + poly[j].y()));
pp.push_back(p);
}
else
@@ -4067,7 +4071,7 @@ void Minkowski(const Path& poly, const Path& path,
Path p;
p.reserve(polyCnt);
for (size_t j = 0; j < poly.size(); ++j)
- p.push_back(IntPoint(path[i].X - poly[j].X, path[i].Y - poly[j].Y));
+ p.push_back(IntPoint(path[i].x() - poly[j].x(), path[i].y() - poly[j].y()));
pp.push_back(p);
}
@@ -4102,7 +4106,7 @@ void TranslatePath(const Path& input, Path& output, const IntPoint& delta)
//precondition: input != output
output.resize(input.size());
for (size_t i = 0; i < input.size(); ++i)
- output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y);
+ output[i] = IntPoint(input[i].x() + delta.x(), input[i].y() + delta.y());
}
//------------------------------------------------------------------------------
@@ -4178,7 +4182,7 @@ void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths)
std::ostream& operator <<(std::ostream &s, const IntPoint &p)
{
- s << "(" << p.X << "," << p.Y << ")";
+ s << "(" << p.x() << "," << p.y() << ")";
return s;
}
//------------------------------------------------------------------------------
@@ -4188,8 +4192,8 @@ std::ostream& operator <<(std::ostream &s, const Path &p)
if (p.empty()) return s;
Path::size_type last = p.size() -1;
for (Path::size_type i = 0; i < last; i++)
- s << "(" << p[i].X << "," << p[i].Y << "), ";
- s << "(" << p[last].X << "," << p[last].Y << ")\n";
+ s << "(" << p[i].x() << "," << p[i].y() << "), ";
+ s << "(" << p[last].x() << "," << p[last].y() << ")\n";
return s;
}
//------------------------------------------------------------------------------
@@ -4204,3 +4208,7 @@ std::ostream& operator <<(std::ostream &s, const Paths &p)
//------------------------------------------------------------------------------
} //ClipperLib namespace
+
+#ifdef CLIPPERLIB_NAMESPACE_PREFIX
+} // namespace CLIPPERLIB_NAMESPACE_PREFIX
+#endif // CLIPPERLIB_NAMESPACE_PREFIX
diff --git a/src/clipper/clipper.hpp b/src/clipper/clipper.hpp
index 48e83d046..c32bcf87b 100644
--- a/src/clipper/clipper.hpp
+++ b/src/clipper/clipper.hpp
@@ -37,10 +37,12 @@
#include
#include
+#include
+
#define CLIPPER_VERSION "6.2.6"
-//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
-//#define use_xyz
+//CLIPPERLIB_USE_XYZ: adds a Z member to IntPoint. Adds a minor cost to perfomance.
+//#define CLIPPERLIB_USE_XYZ
//use_lines: Enables line clipping. Adds a very minor cost to performance.
#define use_lines
@@ -57,11 +59,15 @@
#include
#include
-#ifdef use_xyz
-namespace ClipperLib_Z {
-#else /* use_xyz */
-namespace ClipperLib {
-#endif /* use_xyz */
+#ifdef CLIPPERLIB_NAMESPACE_PREFIX
+ namespace CLIPPERLIB_NAMESPACE_PREFIX {
+#endif // CLIPPERLIB_NAMESPACE_PREFIX
+
+#ifdef CLIPPERLIB_USE_XYZ
+ namespace ClipperLib_Z {
+#else
+ namespace ClipperLib {
+#endif
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
enum PolyType { ptSubject, ptClip };
@@ -88,29 +94,24 @@ enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
static constexpr cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
#endif // CLIPPERLIB_INT32
-struct IntPoint {
- cInt X;
- cInt Y;
-#ifdef use_xyz
- cInt Z;
- IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
-#else
- IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
-#endif
+#ifdef CLIPPERLIB_INTPOINT_TYPE
+using IntPoint = CLIPPERLIB_INTPOINT_TYPE;
+#else // CLIPPERLIB_INTPOINT_TYPE
+using IntPoint = Eigen::Matrix;
+#endif // CLIPPERLIB_INTPOINT_TYPE
+
+using DoublePoint = Eigen::Matrix;
- friend inline bool operator== (const IntPoint& a, const IntPoint& b)
- {
- return a.X == b.X && a.Y == b.Y;
- }
- friend inline bool operator!= (const IntPoint& a, const IntPoint& b)
- {
- return a.X != b.X || a.Y != b.Y;
- }
-};
//------------------------------------------------------------------------------
-typedef std::vector< IntPoint > Path;
-typedef std::vector< Path > Paths;
+typedef std::vector Path;
+typedef std::vector Paths;
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
@@ -119,16 +120,9 @@ std::ostream& operator <<(std::ostream &s, const IntPoint &p);
std::ostream& operator <<(std::ostream &s, const Path &p);
std::ostream& operator <<(std::ostream &s, const Paths &p);
-struct DoublePoint
-{
- double X;
- double Y;
- DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
- DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
-};
//------------------------------------------------------------------------------
-#ifdef use_xyz
+#ifdef CLIPPERLIB_USE_XYZ
typedef std::function ZFillCallback;
#endif
@@ -269,11 +263,11 @@ enum EdgeSide { esLeft = 1, esRight = 2};
};
// Point of an output polygon.
- // 36B on 64bit system without use_xyz.
+ // 36B on 64bit system without CLIPPERLIB_USE_XYZ.
struct OutPt {
// 4B
int Idx;
- // 16B without use_xyz / 24B with use_xyz
+ // 16B without CLIPPERLIB_USE_XYZ / 24B with CLIPPERLIB_USE_XYZ
IntPoint Pt;
// 4B on 32bit system, 8B on 64bit system
OutPt *Next;
@@ -368,7 +362,7 @@ public:
bool StrictlySimple() const {return m_StrictSimple;};
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
-#ifdef use_xyz
+#ifdef CLIPPERLIB_USE_XYZ
void ZFillFunction(ZFillCallback zFillFunc) { m_ZFill = zFillFunc; }
#endif
protected:
@@ -401,7 +395,7 @@ private:
// Does the result go to a PolyTree or Paths?
bool m_UsingPolyTree;
bool m_StrictSimple;
-#ifdef use_xyz
+#ifdef CLIPPERLIB_USE_XYZ
ZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge) const;
@@ -454,7 +448,7 @@ private:
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) const;
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) const;
-#ifdef use_xyz
+#ifdef CLIPPERLIB_USE_XYZ
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
#endif
};
@@ -506,6 +500,8 @@ class clipperException : public std::exception
} //ClipperLib namespace
+#ifdef CLIPPERLIB_NAMESPACE_PREFIX
+} // namespace CLIPPERLIB_NAMESPACE_PREFIX
+#endif // CLIPPERLIB_NAMESPACE_PREFIX
+
#endif //clipper_hpp
-
-
diff --git a/src/clipper/clipper_z.cpp b/src/clipper/clipper_z.cpp
index 4a54ef346..f26be7089 100644
--- a/src/clipper/clipper_z.cpp
+++ b/src/clipper/clipper_z.cpp
@@ -1,7 +1,7 @@
// Hackish wrapper around the ClipperLib library to compile the Clipper library with the Z support.
// Enable the Z coordinate support.
-#define use_xyz
+#define CLIPPERLIB_USE_XYZ
// and let it compile
#include "clipper.cpp"
diff --git a/src/clipper/clipper_z.hpp b/src/clipper/clipper_z.hpp
index e5e7d48ce..20596d8e1 100644
--- a/src/clipper/clipper_z.hpp
+++ b/src/clipper/clipper_z.hpp
@@ -2,17 +2,17 @@
#ifndef clipper_z_hpp
#ifdef clipper_hpp
-#error "You should include the clipper_z.hpp first"
+#error "You should include clipper_z.hpp before clipper.hpp"
#endif
#define clipper_z_hpp
// Enable the Z coordinate support.
-#define use_xyz
+#define CLIPPERLIB_USE_XYZ
#include "clipper.hpp"
#undef clipper_hpp
-#undef use_xyz
+#undef CLIPPERLIB_USE_XYZ
#endif // clipper_z_hpp
diff --git a/src/libnest2d/CMakeLists.txt b/src/libnest2d/CMakeLists.txt
index 3892ed30b..c18dc31cb 100644
--- a/src/libnest2d/CMakeLists.txt
+++ b/src/libnest2d/CMakeLists.txt
@@ -12,11 +12,8 @@ set(LIBNEST2D_SRCFILES
include/libnest2d/placers/bottomleftplacer.hpp
include/libnest2d/placers/nfpplacer.hpp
include/libnest2d/selections/selection_boilerplate.hpp
- #include/libnest2d/selections/filler.hpp
include/libnest2d/selections/firstfit.hpp
- #include/libnest2d/selections/djd_heuristic.hpp
- include/libnest2d/backends/clipper/geometries.hpp
- include/libnest2d/backends/clipper/clipper_polygon.hpp
+ include/libnest2d/backends/libslic3r/geometries.hpp
include/libnest2d/optimizers/nlopt/nlopt_boilerplate.hpp
include/libnest2d/optimizers/nlopt/simplex.hpp
include/libnest2d/optimizers/nlopt/subplex.hpp
@@ -27,5 +24,5 @@ set(LIBNEST2D_SRCFILES
add_library(libnest2d STATIC ${LIBNEST2D_SRCFILES})
target_include_directories(libnest2d PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
-target_link_libraries(libnest2d PUBLIC clipper NLopt::nlopt TBB::tbb Boost::boost)
-target_compile_definitions(libnest2d PUBLIC LIBNEST2D_THREADING_tbb LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_clipper)
+target_link_libraries(libnest2d PUBLIC NLopt::nlopt TBB::tbb Boost::boost libslic3r)
+target_compile_definitions(libnest2d PUBLIC LIBNEST2D_THREADING_tbb LIBNEST2D_STATIC LIBNEST2D_OPTIMIZER_nlopt LIBNEST2D_GEOMETRIES_libslic3r)
diff --git a/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp b/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp
deleted file mode 100644
index 6511fbb72..000000000
--- a/src/libnest2d/include/libnest2d/backends/clipper/clipper_polygon.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef CLIPPER_POLYGON_HPP
-#define CLIPPER_POLYGON_HPP
-
-#include
-
-namespace ClipperLib {
-
-struct Polygon {
- Path Contour;
- Paths Holes;
-
- inline Polygon() = default;
-
- inline explicit Polygon(const Path& cont): Contour(cont) {}
-// inline explicit Polygon(const Paths& holes):
-// Holes(holes) {}
- inline Polygon(const Path& cont, const Paths& holes):
- Contour(cont), Holes(holes) {}
-
- inline explicit Polygon(Path&& cont): Contour(std::move(cont)) {}
-// inline explicit Polygon(Paths&& holes): Holes(std::move(holes)) {}
- inline Polygon(Path&& cont, Paths&& holes):
- Contour(std::move(cont)), Holes(std::move(holes)) {}
-};
-
-inline IntPoint& operator +=(IntPoint& p, const IntPoint& pa ) {
- // This could be done with SIMD
- p.X += pa.X;
- p.Y += pa.Y;
- return p;
-}
-
-inline IntPoint operator+(const IntPoint& p1, const IntPoint& p2) {
- IntPoint ret = p1;
- ret += p2;
- return ret;
-}
-
-inline IntPoint& operator -=(IntPoint& p, const IntPoint& pa ) {
- p.X -= pa.X;
- p.Y -= pa.Y;
- return p;
-}
-
-inline IntPoint operator -(const IntPoint& p ) {
- IntPoint ret = p;
- ret.X = -ret.X;
- ret.Y = -ret.Y;
- return ret;
-}
-
-inline IntPoint operator-(const IntPoint& p1, const IntPoint& p2) {
- IntPoint ret = p1;
- ret -= p2;
- return ret;
-}
-
-inline IntPoint& operator *=(IntPoint& p, const IntPoint& pa ) {
- p.X *= pa.X;
- p.Y *= pa.Y;
- return p;
-}
-
-inline IntPoint operator*(const IntPoint& p1, const IntPoint& p2) {
- IntPoint ret = p1;
- ret *= p2;
- return ret;
-}
-
-}
-
-#endif // CLIPPER_POLYGON_HPP
diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp
deleted file mode 100644
index 9586db35c..000000000
--- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp
+++ /dev/null
@@ -1,356 +0,0 @@
-#ifndef CLIPPER_BACKEND_HPP
-#define CLIPPER_BACKEND_HPP
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "clipper_polygon.hpp"
-
-namespace libnest2d {
-
-// Aliases for convinience
-using PointImpl = ClipperLib::IntPoint;
-using PathImpl = ClipperLib::Path;
-using HoleStore = ClipperLib::Paths;
-using PolygonImpl = ClipperLib::Polygon;
-
-template<> struct ShapeTag { using Type = PolygonTag; };
-template<> struct ShapeTag { using Type = PathTag; };
-template<> struct ShapeTag { using Type = PointTag; };
-
-// Type of coordinate units used by Clipper. Enough to specialize for point,
-// the rest of the types will work (Path, Polygon)
-template<> struct CoordType {
- using Type = ClipperLib::cInt;
- static const constexpr ClipperLib::cInt MM_IN_COORDS = 1000000;
-};
-
-// Enough to specialize for path, it will work for multishape and Polygon
-template<> struct PointType { using Type = PointImpl; };
-
-// This is crucial. CountourType refers to itself by default, so we don't have
-// to secialize for clipper Path. ContourType::Type is PathImpl.
-template<> struct ContourType { using Type = PathImpl; };
-
-// The holes are contained in Clipper::Paths
-template<> struct HolesContainer { using Type = ClipperLib::Paths; };
-
-namespace pointlike {
-
-// Tell libnest2d how to extract the X coord from a ClipperPoint object
-template<> inline ClipperLib::cInt x(const PointImpl& p)
-{
- return p.X;
-}
-
-// Tell libnest2d how to extract the Y coord from a ClipperPoint object
-template<> inline ClipperLib::cInt y(const PointImpl& p)
-{
- return p.Y;
-}
-
-// Tell libnest2d how to extract the X coord from a ClipperPoint object
-template<> inline ClipperLib::cInt& x(PointImpl& p)
-{
- return p.X;
-}
-
-// Tell libnest2d how to extract the Y coord from a ClipperPoint object
-template<> inline ClipperLib::cInt& y(PointImpl& p)
-{
- return p.Y;
-}
-
-}
-
-// Using the libnest2d default area implementation
-#define DISABLE_BOOST_AREA
-
-namespace shapelike {
-
-template<>
-inline void offset(PolygonImpl& sh, TCoord distance, const PolygonTag&)
-{
- #define DISABLE_BOOST_OFFSET
-
- using ClipperLib::ClipperOffset;
- using ClipperLib::jtSquare;
- using ClipperLib::etClosedPolygon;
- using ClipperLib::Paths;
-
- Paths result;
-
- try {
- ClipperOffset offs;
- offs.AddPath(sh.Contour, jtSquare, etClosedPolygon);
- offs.AddPaths(sh.Holes, jtSquare, etClosedPolygon);
- offs.Execute(result, static_cast(distance));
- } catch (ClipperLib::clipperException &) {
- throw GeometryException(GeomErr::OFFSET);
- }
-
- // Offsetting reverts the orientation and also removes the last vertex
- // so boost will not have a closed polygon.
-
- // we plan to replace contours
- sh.Holes.clear();
-
- bool found_the_contour = false;
- for(auto& r : result) {
- if(ClipperLib::Orientation(r)) {
- // We don't like if the offsetting generates more than one contour
- // but throwing would be an overkill. Instead, we should warn the
- // caller about the inability to create correct geometries
- if(!found_the_contour) {
- sh.Contour = std::move(r);
- ClipperLib::ReversePath(sh.Contour);
- auto front_p = sh.Contour.front();
- sh.Contour.emplace_back(std::move(front_p));
- found_the_contour = true;
- } else {
- dout() << "Warning: offsetting result is invalid!";
- /* TODO warning */
- }
- } else {
- // TODO If there are multiple contours we can't be sure which hole
- // belongs to the first contour. (But in this case the situation is
- // bad enough to let it go...)
- sh.Holes.emplace_back(std::move(r));
- ClipperLib::ReversePath(sh.Holes.back());
- auto front_p = sh.Holes.back().front();
- sh.Holes.back().emplace_back(std::move(front_p));
- }
- }
-}
-
-template<>
-inline void offset(PathImpl& sh, TCoord distance, const PathTag&)
-{
- PolygonImpl p(std::move(sh));
- offset(p, distance, PolygonTag());
- sh = p.Contour;
-}
-
-// Tell libnest2d how to make string out of a ClipperPolygon object
-template<> inline std::string toString(const PolygonImpl& sh)
-{
- std::stringstream ss;
-
- ss << "Contour {\n";
- for(auto p : sh.Contour) {
- ss << "\t" << p.X << " " << p.Y << "\n";
- }
- ss << "}\n";
-
- for(auto& h : sh.Holes) {
- ss << "Holes {\n";
- for(auto p : h) {
- ss << "\t{\n";
- ss << "\t\t" << p.X << " " << p.Y << "\n";
- ss << "\t}\n";
- }
- ss << "}\n";
- }
-
- return ss.str();
-}
-
-template<>
-inline PolygonImpl create(const PathImpl& path, const HoleStore& holes)
-{
- PolygonImpl p;
- p.Contour = path;
- p.Holes = holes;
-
- return p;
-}
-
-template<> inline PolygonImpl create( PathImpl&& path, HoleStore&& holes) {
- PolygonImpl p;
- p.Contour.swap(path);
- p.Holes.swap(holes);
-
- return p;
-}
-
-template<>
-inline const THolesContainer& holes(const PolygonImpl& sh)
-{
- return sh.Holes;
-}
-
-template<> inline THolesContainer& holes(PolygonImpl& sh)
-{
- return sh.Holes;
-}
-
-template<>
-inline TContour& hole(PolygonImpl& sh, unsigned long idx)
-{
- return sh.Holes[idx];
-}
-
-template<>
-inline const TContour& hole(const PolygonImpl& sh,
- unsigned long idx)
-{
- return sh.Holes[idx];
-}
-
-template<> inline size_t holeCount(const PolygonImpl& sh)
-{
- return sh.Holes.size();
-}
-
-template<> inline PathImpl& contour(PolygonImpl& sh)
-{
- return sh.Contour;
-}
-
-template<>
-inline const PathImpl& contour(const PolygonImpl& sh)
-{
- return sh.Contour;
-}
-
-#define DISABLE_BOOST_TRANSLATE
-template<>
-inline void translate(PolygonImpl& sh, const PointImpl& offs)
-{
- for(auto& p : sh.Contour) { p += offs; }
- for(auto& hole : sh.Holes) for(auto& p : hole) { p += offs; }
-}
-
-#define DISABLE_BOOST_ROTATE
-template<>
-inline void rotate(PolygonImpl& sh, const Radians& rads)
-{
- using Coord = TCoord;
-
- auto cosa = rads.cos();
- auto sina = rads.sin();
-
- for(auto& p : sh.Contour) {
- p = {
- static_cast(p.X * cosa - p.Y * sina),
- static_cast(p.X * sina + p.Y * cosa)
- };
- }
- for(auto& hole : sh.Holes) for(auto& p : hole) {
- p = {
- static_cast(p.X * cosa - p.Y * sina),
- static_cast(p.X * sina + p.Y * cosa)
- };
- }
-}
-
-} // namespace shapelike
-
-#define DISABLE_BOOST_NFP_MERGE
-inline TMultiShape clipper_execute(
- ClipperLib::Clipper& clipper,
- ClipperLib::ClipType clipType,
- ClipperLib::PolyFillType subjFillType = ClipperLib::pftEvenOdd,
- ClipperLib::PolyFillType clipFillType = ClipperLib::pftEvenOdd)
-{
- TMultiShape retv;
-
- ClipperLib::PolyTree result;
- clipper.Execute(clipType, result, subjFillType, clipFillType);
-
- retv.reserve(static_cast(result.Total()));
-
- std::function processHole;
-
- auto processPoly = [&retv, &processHole](ClipperLib::PolyNode *pptr) {
- PolygonImpl poly;
- poly.Contour.swap(pptr->Contour);
-
- assert(!pptr->IsHole());
-
- if(!poly.Contour.empty() ) {
- auto front_p = poly.Contour.front();
- auto &back_p = poly.Contour.back();
- if(front_p.X != back_p.X || front_p.Y != back_p.X)
- poly.Contour.emplace_back(front_p);
- }
-
- for(auto h : pptr->Childs) { processHole(h, poly); }
- retv.push_back(poly);
- };
-
- processHole = [&processPoly](ClipperLib::PolyNode *pptr, PolygonImpl& poly)
- {
- poly.Holes.emplace_back(std::move(pptr->Contour));
-
- assert(pptr->IsHole());
-
- if(!poly.Contour.empty() ) {
- auto front_p = poly.Contour.front();
- auto &back_p = poly.Contour.back();
- if(front_p.X != back_p.X || front_p.Y != back_p.X)
- poly.Contour.emplace_back(front_p);
- }
-
- for(auto c : pptr->Childs) processPoly(c);
- };
-
- auto traverse = [&processPoly] (ClipperLib::PolyNode *node)
- {
- for(auto ch : node->Childs) processPoly(ch);
- };
-
- traverse(&result);
-
- return retv;
-}
-
-namespace nfp {
-
-template<> inline TMultiShape
-merge(const TMultiShape& shapes)
-{
- ClipperLib::Clipper clipper(ClipperLib::ioReverseSolution);
-
- bool closed = true;
- bool valid = true;
-
- for(auto& path : shapes) {
- valid &= clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed);
-
- for(auto& h : path.Holes)
- valid &= clipper.AddPath(h, ClipperLib::ptSubject, closed);
- }
-
- if(!valid) throw GeometryException(GeomErr::MERGE);
-
- return clipper_execute(clipper, ClipperLib::ctUnion, ClipperLib::pftNegative);
-}
-
-}
-
-}
-
-#define DISABLE_BOOST_CONVEX_HULL
-
-//#define DISABLE_BOOST_SERIALIZE
-//#define DISABLE_BOOST_UNSERIALIZE
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4244)
-#pragma warning(disable: 4267)
-#endif
-// All other operators and algorithms are implemented with boost
-#include
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#endif // CLIPPER_BACKEND_HPP
diff --git a/src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp b/src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp
new file mode 100644
index 000000000..14b075b19
--- /dev/null
+++ b/src/libnest2d/include/libnest2d/backends/libslic3r/geometries.hpp
@@ -0,0 +1,283 @@
+#ifndef CLIPPER_BACKEND_HPP
+#define CLIPPER_BACKEND_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+namespace Slic3r {
+
+template struct IsVec_ : public std::false_type {};
+
+template struct IsVec_< Vec<2, T> >: public std::true_type {};
+
+template
+static constexpr const bool IsVec = IsVec_>::value;
+
+template using VecOnly = std::enable_if_t, O>;
+
+inline Point operator+(const Point& p1, const Point& p2) {
+ Point ret = p1;
+ ret += p2;
+ return ret;
+}
+
+inline Point operator -(const Point& p ) {
+ Point ret = p;
+ ret.x() = -ret.x();
+ ret.y() = -ret.y();
+ return ret;
+}
+
+inline Point operator-(const Point& p1, const Point& p2) {
+ Point ret = p1;
+ ret -= p2;
+ return ret;
+}
+
+inline Point& operator *=(Point& p, const Point& pa ) {
+ p.x() *= pa.x();
+ p.y() *= pa.y();
+ return p;
+}
+
+inline Point operator*(const Point& p1, const Point& p2) {
+ Point ret = p1;
+ ret *= p2;
+ return ret;
+}
+
+} // namespace Slic3r
+
+namespace libnest2d {
+
+template using Vec = Slic3r::Vec<2, T>;
+
+// Aliases for convinience
+using PointImpl = Slic3r::Point;
+using PathImpl = Slic3r::Polygon;
+using HoleStore = Slic3r::Polygons;
+using PolygonImpl = Slic3r::ExPolygon;
+
+template<> struct ShapeTag { using Type = PointTag; };
+template<> struct ShapeTag { using Type = PointTag; };
+
+template<> struct ShapeTag> { using Type = PathTag; };
+template<> struct ShapeTag { using Type = PathTag; };
+template<> struct ShapeTag { using Type = PathTag; };
+template<> struct ShapeTag { using Type = PolygonTag; };
+template<> struct ShapeTag { using Type = MultiPolygonTag; };
+
+// Type of coordinate units used by Clipper. Enough to specialize for point,
+// the rest of the types will work (Path, Polygon)
+template<> struct CoordType {
+ using Type = coord_t;
+ static const constexpr coord_t MM_IN_COORDS = 1000000;
+};
+
+template<> struct CoordType {
+ using Type = coord_t;
+ static const constexpr coord_t MM_IN_COORDS = 1000000;
+};
+
+// Enough to specialize for path, it will work for multishape and Polygon
+template<> struct PointType> { using Type = Slic3r::Vec2crd; };
+template<> struct PointType { using Type = Slic3r::Point; };
+template<> struct PointType { using Type = Slic3r::Point; };
+
+// This is crucial. CountourType refers to itself by default, so we don't have
+// to secialize for clipper Path. ContourType::Type is PathImpl.
+template<> struct ContourType { using Type = Slic3r::Polygon; };
+
+// The holes are contained in Clipper::Paths
+template<> struct HolesContainer { using Type = Slic3r::Polygons; };
+
+template<>
+struct OrientationType {
+ static const constexpr Orientation Value = Orientation::COUNTER_CLOCKWISE;
+};
+
+template<>
+struct OrientationType {
+ static const constexpr Orientation Value = Orientation::COUNTER_CLOCKWISE;
+};
+
+template<>
+struct ClosureType {
+ static const constexpr Closure Value = Closure::OPEN;
+};
+
+template<>
+struct ClosureType {
+ static const constexpr Closure Value = Closure::OPEN;
+};
+
+template<> struct MultiShape { using Type = Slic3r::ExPolygons; };
+template<> struct ContourType { using Type = Slic3r::Polygon; };
+
+// Using the libnest2d default area implementation
+#define DISABLE_BOOST_AREA
+
+namespace shapelike {
+
+template<>
+inline void offset(Slic3r::ExPolygon& sh, coord_t distance, const PolygonTag&)
+{
+#define DISABLE_BOOST_OFFSET
+ auto res = Slic3r::offset_ex(sh, distance, Slic3r::ClipperLib::jtSquare);
+ if (!res.empty()) sh = res.front();
+}
+
+template<>
+inline void offset(Slic3r::Polygon& sh, coord_t distance, const PathTag&)
+{
+ auto res = Slic3r::offset(sh, distance, Slic3r::ClipperLib::jtSquare);
+ if (!res.empty()) sh = res.front();
+}
+
+// Tell libnest2d how to make string out of a ClipperPolygon object
+template<> inline std::string toString(const Slic3r::ExPolygon& sh)
+{
+ std::stringstream ss;
+
+ ss << "Contour {\n";
+ for(auto &p : sh.contour.points) {
+ ss << "\t" << p.x() << " " << p.y() << "\n";
+ }
+ ss << "}\n";
+
+ for(auto& h : sh.holes) {
+ ss << "Holes {\n";
+ for(auto p : h.points) {
+ ss << "\t{\n";
+ ss << "\t\t" << p.x() << " " << p.y() << "\n";
+ ss << "\t}\n";
+ }
+ ss << "}\n";
+ }
+
+ return ss.str();
+}
+
+template<>
+inline Slic3r::ExPolygon create(const Slic3r::Polygon& path, const Slic3r::Polygons& holes)
+{
+ Slic3r::ExPolygon p;
+ p.contour = path;
+ p.holes = holes;
+
+ return p;
+}
+
+template<> inline Slic3r::ExPolygon create(Slic3r::Polygon&& path, Slic3r::Polygons&& holes) {
+ Slic3r::ExPolygon p;
+ p.contour.points.swap(path.points);
+ p.holes.swap(holes);
+
+ return p;
+}
+
+template<>
+inline const THolesContainer& holes(const Slic3r::ExPolygon& sh)
+{
+ return sh.holes;
+}
+
+template<> inline THolesContainer& holes(Slic3r::ExPolygon& sh)
+{
+ return sh.holes;
+}
+
+template<>
+inline Slic3r::Polygon& hole(Slic3r::ExPolygon& sh, unsigned long idx)
+{
+ return sh.holes[idx];
+}
+
+template<>
+inline const Slic3r::Polygon& hole(const Slic3r::ExPolygon& sh, unsigned long idx)
+{
+ return sh.holes[idx];
+}
+
+template<> inline size_t holeCount(const Slic3r::ExPolygon& sh)
+{
+ return sh.holes.size();
+}
+
+template<> inline Slic3r::Polygon& contour(Slic3r::ExPolygon& sh)
+{
+ return sh.contour;
+}
+
+template<>
+inline const Slic3r::Polygon& contour(const Slic3r::ExPolygon& sh)
+{
+ return sh.contour;
+}
+
+template<>
+inline void reserve(Slic3r::Polygon& p, size_t vertex_capacity, const PathTag&)
+{
+ p.points.reserve(vertex_capacity);
+}
+
+template<>
+inline void addVertex(Slic3r::Polygon& sh, const PathTag&, const Slic3r::Point &p)
+{
+ sh.points.emplace_back(p);
+}
+
+#define DISABLE_BOOST_TRANSLATE
+template<>
+inline void translate(Slic3r::ExPolygon& sh, const Slic3r::Point& offs)
+{
+ sh.translate(offs);
+}
+
+#define DISABLE_BOOST_ROTATE
+template<>
+inline void rotate(Slic3r::ExPolygon& sh, const Radians& rads)
+{
+ sh.rotate(rads);
+}
+
+} // namespace shapelike
+
+namespace nfp {
+
+#define DISABLE_BOOST_NFP_MERGE
+template<>
+inline TMultiShape merge(const TMultiShape& shapes)
+{
+ return Slic3r::union_ex(shapes);
+}
+
+} // namespace nfp
+} // namespace libnest2d
+
+#define DISABLE_BOOST_CONVEX_HULL
+
+//#define DISABLE_BOOST_SERIALIZE
+//#define DISABLE_BOOST_UNSERIALIZE
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4244)
+#pragma warning(disable: 4267)
+#endif
+// All other operators and algorithms are implemented with boost
+#include
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif // CLIPPER_BACKEND_HPP
diff --git a/src/libnest2d/include/libnest2d/geometry_traits.hpp b/src/libnest2d/include/libnest2d/geometry_traits.hpp
index 3095c717d..7ea437339 100644
--- a/src/libnest2d/include/libnest2d/geometry_traits.hpp
+++ b/src/libnest2d/include/libnest2d/geometry_traits.hpp
@@ -128,22 +128,32 @@ template struct ContourType> {
using Type = typename ContourType::Type;
};
-enum class Orientation {
- CLOCKWISE,
- COUNTER_CLOCKWISE
-};
+enum class Orientation { CLOCKWISE, COUNTER_CLOCKWISE };
template
struct OrientationType {
// Default Polygon orientation that the library expects
- static const Orientation Value = Orientation::CLOCKWISE;
+ static const constexpr Orientation Value = Orientation::CLOCKWISE;
};
-template inline /*constexpr*/ bool is_clockwise() {
+template inline constexpr bool is_clockwise() {
return OrientationType>::Value == Orientation::CLOCKWISE;
}
+template
+inline const constexpr Orientation OrientationTypeV =
+ OrientationType>::Value;
+
+enum class Closure { OPEN, CLOSED };
+
+template struct ClosureType {
+ static const constexpr Closure Value = Closure::CLOSED;
+};
+
+template
+inline const constexpr Closure ClosureTypeV =
+ ClosureType>::Value;
/**
* \brief A point pair base class for other point pairs (segment, box, ...).
@@ -587,9 +597,9 @@ inline void reserve(RawPath& p, size_t vertex_capacity, const PathTag&)
}
template
-inline void addVertex(S& sh, const PathTag&, Args...args)
+inline void addVertex(S& sh, const PathTag&, const TPoint &p)
{
- sh.emplace_back(std::forward(args)...);
+ sh.emplace_back(p);
}
template
@@ -841,9 +851,9 @@ template auto rbegin(P& p) -> decltype(_backward(end(p)))
return _backward(end(p));
}
-template auto rcbegin(const P& p) -> decltype(_backward(end(p)))
+template auto rcbegin(const P& p) -> decltype(_backward(cend(p)))
{
- return _backward(end(p));
+ return _backward(cend(p));
}
template auto rend(P& p) -> decltype(_backward(begin(p)))
@@ -873,16 +883,16 @@ inline void reserve(T& sh, size_t vertex_capacity) {
reserve(sh, vertex_capacity, Tag());
}
-template
-inline void addVertex(S& sh, const PolygonTag&, Args...args)
+template
+inline void addVertex(S& sh, const PolygonTag&, const TPoint &p)
{
- addVertex(contour(sh), PathTag(), std::forward(args)...);
+ addVertex(contour(sh), PathTag(), p);
}
-template // Tag dispatcher
-inline void addVertex(S& sh, Args...args)
+template // Tag dispatcher
+inline void addVertex(S& sh, const TPoint &p)
{
- addVertex(sh, Tag(), std::forward(args)...);
+ addVertex(sh, Tag(), p);
}
template
diff --git a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
index 6b3ff60c1..d9f947802 100644
--- a/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
+++ b/src/libnest2d/include/libnest2d/geometry_traits_nfp.hpp
@@ -28,7 +28,7 @@ inline void buildPolygon(const EdgeList& edgelist,
auto& rsh = sl::contour(rpoly);
- sl::reserve(rsh, 2*edgelist.size());
+ sl::reserve(rsh, 2 * edgelist.size());
// Add the two vertices from the first edge into the final polygon.
sl::addVertex(rsh, edgelist.front().first());
@@ -57,7 +57,6 @@ inline void buildPolygon(const EdgeList& edgelist,
tmp = std::next(tmp);
}
-
}
template
@@ -214,17 +213,24 @@ inline NfpResult nfpConvexOnly(const RawShape& sh,
// Reserve the needed memory
edgelist.reserve(cap);
sl::reserve(rsh, static_cast(cap));
+ auto add_edge = [&edgelist](const Vertex &v1, const Vertex &v2) {
+ Edge e{v1, v2};
+ if (e.sqlength() > 0)
+ edgelist.emplace_back(e);
+ };
{ // place all edges from sh into edgelist
auto first = sl::cbegin(sh);
auto next = std::next(first);
while(next != sl::cend(sh)) {
- if (pl::magnsq(*next - *first) > 0)
- edgelist.emplace_back(*(first), *(next));
+ add_edge(*(first), *(next));
++first; ++next;
}
+
+ if constexpr (ClosureTypeV == Closure::OPEN)
+ add_edge(*sl::rcbegin(sh), *sl::cbegin(sh));
}
{ // place all edges from other into edgelist
@@ -232,17 +238,19 @@ inline NfpResult nfpConvexOnly(const RawShape& sh,
auto next = std::next(first);
while(next != sl::cend(other)) {
- if (pl::magnsq(*next - *first) > 0)
- edgelist.emplace_back(*(next), *(first));
+ add_edge(*(next), *(first));
++first; ++next;
}
+
+ if constexpr (ClosureTypeV == Closure::OPEN)
+ add_edge(*sl::cbegin(other), *sl::rcbegin(other));
}
- std::sort(edgelist.begin(), edgelist.end(),
- [](const Edge& e1, const Edge& e2)
+ std::sort(edgelist.begin(), edgelist.end(),
+ [](const Edge& e1, const Edge& e2)
{
- Vertex ax(1, 0); // Unit vector for the X axis
+ const Vertex ax(1, 0); // Unit vector for the X axis
// get cectors from the edges
Vertex p1 = e1.second() - e1.first();
@@ -288,12 +296,18 @@ inline NfpResult nfpConvexOnly(const RawShape& sh,
// If Ratio is an actual rational type, there is no precision loss
auto pcos1 = Ratio(lcos[0]) / lsq1 * sign * lcos[0];
auto pcos2 = Ratio(lcos[1]) / lsq2 * sign * lcos[1];
-
- return q[0] < 2 ? pcos1 < pcos2 : pcos1 > pcos2;
+
+ if constexpr (is_clockwise())
+ return q[0] < 2 ? pcos1 < pcos2 : pcos1 > pcos2;
+ else
+ return q[0] < 2 ? pcos1 > pcos2 : pcos1 < pcos2;
}
// If in different quadrants, compare the quadrant indices only.
- return q[0] > q[1];
+ if constexpr (is_clockwise())
+ return q[0] > q[1];
+ else
+ return q[0] < q[1];
});
__nfp::buildPolygon(edgelist, rsh, top_nfp);
diff --git a/src/libnest2d/include/libnest2d/libnest2d.hpp b/src/libnest2d/include/libnest2d/libnest2d.hpp
index 9d24a2569..a4cf7dc56 100644
--- a/src/libnest2d/include/libnest2d/libnest2d.hpp
+++ b/src/libnest2d/include/libnest2d/libnest2d.hpp
@@ -7,6 +7,10 @@
#include
#endif
+#ifdef LIBNEST2D_GEOMETRIES_libslic3r
+#include
+#endif
+
#ifdef LIBNEST2D_OPTIMIZER_nlopt
// We include the stock optimizers for local and global optimization
#include // Local subplex for NfpPlacer
diff --git a/src/libnest2d/include/libnest2d/nester.hpp b/src/libnest2d/include/libnest2d/nester.hpp
index 20da9b9a1..52c738a4c 100644
--- a/src/libnest2d/include/libnest2d/nester.hpp
+++ b/src/libnest2d/include/libnest2d/nester.hpp
@@ -96,7 +96,7 @@ public:
* @return The orientation type identifier for the _Item type.
*/
static BP2D_CONSTEXPR Orientation orientation() {
- return OrientationType::Value;
+ return OrientationType>::Value;
}
/**
@@ -446,44 +446,32 @@ private:
}
};
+template Sh create_rect(TCoord width, TCoord height)
+{
+ auto sh = sl::create(
+ {{0, 0}, {0, height}, {width, height}, {width, 0}});
+
+ if constexpr (ClosureTypeV == Closure::CLOSED)
+ sl::addVertex(sh, {0, 0});
+
+ if constexpr (OrientationTypeV == Orientation::COUNTER_CLOCKWISE)
+ std::reverse(sl::begin(sh), sl::end(sh));
+
+ return sh;
+}
+
/**
* \brief Subclass of _Item for regular rectangle items.
*/
-template
-class _Rectangle: public _Item {
- using _Item::vertex;
+template
+class _Rectangle: public _Item {
+ using _Item::vertex;
using TO = Orientation;
public:
- using Unit = TCoord>;
+ using Unit = TCoord;
- template::Value>
- inline _Rectangle(Unit width, Unit height,
- // disable this ctor if o != CLOCKWISE
- enable_if_t< o == TO::CLOCKWISE, int> = 0 ):
- _Item( sl::create( {
- {0, 0},
- {0, height},
- {width, height},
- {width, 0},
- {0, 0}
- } ))
- {
- }
-
- template::Value>
- inline _Rectangle(Unit width, Unit height,
- // disable this ctor if o != COUNTER_CLOCKWISE
- enable_if_t< o == TO::COUNTER_CLOCKWISE, int> = 0 ):
- _Item( sl::create( {
- {0, 0},
- {width, 0},
- {width, height},
- {0, height},
- {0, 0}
- } ))
- {
- }
+ inline _Rectangle(Unit w, Unit h): _Item{create_rect(w, h)} {}
inline Unit width() const BP2D_NOEXCEPT {
return getX(vertex(2));
diff --git a/src/libnest2d/include/libnest2d/placers/bottomleftplacer.hpp b/src/libnest2d/include/libnest2d/placers/bottomleftplacer.hpp
index e1a4ffbd9..a067194dc 100644
--- a/src/libnest2d/include/libnest2d/placers/bottomleftplacer.hpp
+++ b/src/libnest2d/include/libnest2d/placers/bottomleftplacer.hpp
@@ -365,44 +365,50 @@ protected:
// the additional vertices for maintaning min object distance
sl::reserve(rsh, finish-start+4);
- /*auto addOthers = [&rsh, finish, start, &item](){
+ auto addOthers_ = [&rsh, finish, start, &item](){
for(size_t i = start+1; i < finish; i++)
sl::addVertex(rsh, item.vertex(i));
- };*/
+ };
- auto reverseAddOthers = [&rsh, finish, start, &item](){
+ auto reverseAddOthers_ = [&rsh, finish, start, &item](){
for(auto i = finish-1; i > start; i--)
- sl::addVertex(rsh, item.vertex(
- static_cast(i)));
+ sl::addVertex(rsh, item.vertex(static_cast(i)));
+ };
+
+ auto addOthers = [&addOthers_, &reverseAddOthers_]() {
+ if constexpr (!is_clockwise())
+ addOthers_();
+ else
+ reverseAddOthers_();
};
// Final polygon construction...
- static_assert(OrientationType::Value ==
- Orientation::CLOCKWISE,
- "Counter clockwise toWallPoly() Unimplemented!");
-
// Clockwise polygon construction
sl::addVertex(rsh, topleft_vertex);
- if(dir == Dir::LEFT) reverseAddOthers();
+ if(dir == Dir::LEFT) addOthers();
else {
- sl::addVertex(rsh, getX(topleft_vertex), 0);
- sl::addVertex(rsh, getX(bottomleft_vertex), 0);
+ sl::addVertex(rsh, {getX(topleft_vertex), 0});
+ sl::addVertex(rsh, {getX(bottomleft_vertex), 0});
}
sl::addVertex(rsh, bottomleft_vertex);
if(dir == Dir::LEFT) {
- sl::addVertex(rsh, 0, getY(bottomleft_vertex));
- sl::addVertex(rsh, 0, getY(topleft_vertex));
+ sl::addVertex(rsh, {0, getY(bottomleft_vertex)});
+ sl::addVertex(rsh, {0, getY(topleft_vertex)});
}
- else reverseAddOthers();
+ else addOthers();
// Close the polygon
- sl::addVertex(rsh, topleft_vertex);
+ if constexpr (ClosureTypeV == Closure::CLOSED)
+ sl::addVertex(rsh, topleft_vertex);
+
+ if constexpr (!is_clockwise())
+ std::reverse(rsh.begin(), rsh.end());
return ret;
}
diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
index bd9c60355..47ba7bbdc 100644
--- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
+++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
@@ -250,8 +250,8 @@ template class EdgeCache {
Vertex ret = edge.first();
// Get the point on the edge which lies in ed distance from the start
- ret += { static_cast(std::round(ed*std::cos(angle))),
- static_cast(std::round(ed*std::sin(angle))) };
+ ret += Vertex(static_cast(std::round(ed*std::cos(angle))),
+ static_cast(std::round(ed*std::sin(angle))));
return ret;
}
@@ -724,8 +724,7 @@ private:
auto rawobjfunc = [_objfunc, iv, startpos]
(Vertex v, Item& itm)
{
- auto d = v - iv;
- d += startpos;
+ auto d = (v - iv) + startpos;
itm.translation(d);
return _objfunc(itm);
};
@@ -742,8 +741,7 @@ private:
&item, &bin, &iv, &startpos] (const Optimum& o)
{
auto v = getNfpPoint(o);
- auto d = v - iv;
- d += startpos;
+ auto d = (v - iv) + startpos;
item.translation(d);
merged_pile.emplace_back(item.transformedShape());
@@ -877,8 +875,7 @@ private:
}
if( best_score < global_score ) {
- auto d = getNfpPoint(optimum) - iv;
- d += startpos;
+ auto d = (getNfpPoint(optimum) - iv) + startpos;
final_tr = d;
final_rot = initial_rot + rot;
can_pack = true;
diff --git a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp
index 16dee513b..d6213d0ed 100644
--- a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp
+++ b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp
@@ -19,7 +19,7 @@
#pragma warning(pop)
#endif
// this should be removed to not confuse the compiler
-// #include
+// #include "../libnest2d.hpp"
namespace bp2d {
@@ -30,6 +30,10 @@ using libnest2d::PolygonImpl;
using libnest2d::PathImpl;
using libnest2d::Orientation;
using libnest2d::OrientationType;
+using libnest2d::OrientationTypeV;
+using libnest2d::ClosureType;
+using libnest2d::Closure;
+using libnest2d::ClosureTypeV;
using libnest2d::getX;
using libnest2d::getY;
using libnest2d::setX;
@@ -213,8 +217,15 @@ struct ToBoostOrienation {
static const order_selector Value = counterclockwise;
};
-static const bp2d::Orientation RealOrientation =
- bp2d::OrientationType::Value;
+template struct ToBoostClosure {};
+
+template<> struct ToBoostClosure {
+ static const constexpr closure_selector Value = closure_selector::open;
+};
+
+template<> struct ToBoostClosure {
+ static const constexpr closure_selector Value = closure_selector::closed;
+};
// Ring implementation /////////////////////////////////////////////////////////
@@ -225,12 +236,13 @@ template<> struct tag {
template<> struct point_order {
static const order_selector value =
- ToBoostOrienation::Value;
+ ToBoostOrienation>::Value;
};
// All our Paths should be closed for the bin packing application
template<> struct closure {
- static const closure_selector value = closed;
+ static const constexpr closure_selector value =
+ ToBoostClosure< bp2d::ClosureTypeV >::Value;
};
// Polygon implementation //////////////////////////////////////////////////////
diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp
index 3800d49e3..61a32678b 100644
--- a/src/libslic3r/Arrange.cpp
+++ b/src/libslic3r/Arrange.cpp
@@ -3,7 +3,7 @@
#include "BoundingBox.hpp"
-#include
+#include
#include
#include
#include
@@ -54,23 +54,22 @@ namespace Slic3r {
template, int...EigenArgs>
inline constexpr Eigen::Matrix unscaled(
- const ClipperLib::IntPoint &v) noexcept
+ const Slic3r::ClipperLib::IntPoint &v) noexcept
{
- return Eigen::Matrix{unscaled(v.X),
- unscaled(v.Y)};
+ return Eigen::Matrix{unscaled(v.x()),
+ unscaled(v.y())};
}
namespace arrangement {
using namespace libnest2d;
-namespace clppr = ClipperLib;
// Get the libnest2d types for clipper backend
-using Item = _Item;
-using Box = _Box;
-using Circle = _Circle;
-using Segment = _Segment;
-using MultiPolygon = TMultiShape;
+using Item = _Item;
+using Box = _Box;
+using Circle = _Circle;
+using Segment = _Segment;
+using MultiPolygon = ExPolygons;
// Summon the spatial indexing facilities from boost
namespace bgi = boost::geometry::index;
@@ -127,8 +126,8 @@ template
class AutoArranger {
public:
// Useful type shortcuts...
- using Placer = typename placers::_NofitPolyPlacer;
- using Selector = selections::_FirstFitSelection;
+ using Placer = typename placers::_NofitPolyPlacer;
+ using Selector = selections::_FirstFitSelection;
using Packer = _Nester;
using PConfig = typename Packer::PlacementConfig;
using Distance = TCoord;
@@ -168,7 +167,7 @@ protected:
// as it possibly can be but at the same time, it has to provide
// reasonable results.
std::tuple
- objfunc(const Item &item, const clppr::IntPoint &bincenter)
+ objfunc(const Item &item, const Point &bincenter)
{
const double bin_area = m_bin_area;
const SpatIndex& spatindex = m_rtree;
@@ -220,12 +219,12 @@ protected:
switch (compute_case) {
case BIG_ITEM: {
- const clppr::IntPoint& minc = ibb.minCorner(); // bottom left corner
- const clppr::IntPoint& maxc = ibb.maxCorner(); // top right corner
+ const Point& minc = ibb.minCorner(); // bottom left corner
+ const Point& maxc = ibb.maxCorner(); // top right corner
// top left and bottom right corners
- clppr::IntPoint top_left{getX(minc), getY(maxc)};
- clppr::IntPoint bottom_right{getX(maxc), getY(minc)};
+ Point top_left{getX(minc), getY(maxc)};
+ Point bottom_right{getX(maxc), getY(minc)};
// Now the distance of the gravity center will be calculated to the
// five anchor points and the smallest will be chosen.
@@ -452,7 +451,7 @@ template<> std::function AutoArranger::get_objfn()
// Specialization for a generalized polygon.
// Warning: this is unfinished business. It may or may not work.
template<>
-std::function AutoArranger::get_objfn()
+std::function AutoArranger::get_objfn()
{
auto bincenter = sl::boundingBox(m_bin).center();
return [this, bincenter](const Item &item) {
@@ -521,7 +520,7 @@ void _arrange(
inline Box to_nestbin(const BoundingBox &bb) { return Box{{bb.min(X), bb.min(Y)}, {bb.max(X), bb.max(Y)}};}
inline Circle to_nestbin(const CircleBed &c) { return Circle({c.center()(0), c.center()(1)}, c.radius()); }
-inline clppr::Polygon to_nestbin(const Polygon &p) { return sl::create(Slic3rMultiPoint_to_ClipperPath(p)); }
+inline ExPolygon to_nestbin(const Polygon &p) { return ExPolygon{p}; }
inline Box to_nestbin(const InfiniteBed &bed) { return Box::infinite({bed.center.x(), bed.center.y()}); }
inline coord_t width(const BoundingBox& box) { return box.max.x() - box.min.x(); }
@@ -568,19 +567,12 @@ static void process_arrangeable(const ArrangePolygon &arrpoly,
const Vec2crd &offs = arrpoly.translation;
double rotation = arrpoly.rotation;
- if (p.is_counter_clockwise()) p.reverse();
-
- clppr::Polygon clpath(Slic3rMultiPoint_to_ClipperPath(p));
-
// This fixes:
// https://github.com/prusa3d/PrusaSlicer/issues/2209
- if (clpath.Contour.size() < 3)
+ if (p.points.size() < 3)
return;
- auto firstp = clpath.Contour.front();
- clpath.Contour.emplace_back(firstp);
-
- outp.emplace_back(std::move(clpath));
+ outp.emplace_back(std::move(p));
outp.back().rotation(rotation);
outp.back().translation({offs.x(), offs.y()});
outp.back().binId(arrpoly.bed_idx);
@@ -624,7 +616,7 @@ void arrange(ArrangePolygons & arrangables,
const BedT & bed,
const ArrangeParams & params)
{
- namespace clppr = ClipperLib;
+ namespace clppr = Slic3r::ClipperLib;
std::vector- items, fixeditems;
items.reserve(arrangables.size());
@@ -643,8 +635,8 @@ void arrange(ArrangePolygons & arrangables,
_arrange(items, fixeditems, to_nestbin(bed), params, pri, cfn);
for(size_t i = 0; i < items.size(); ++i) {
- clppr::IntPoint tr = items[i].translation();
- arrangables[i].translation = {coord_t(tr.X), coord_t(tr.Y)};
+ Point tr = items[i].translation();
+ arrangables[i].translation = {coord_t(tr.x()), coord_t(tr.y())};
arrangables[i].rotation = items[i].rotation();
arrangables[i].bed_idx = items[i].binId();
}
diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp
index 08bedc5c0..19f5ae82e 100644
--- a/src/libslic3r/Brim.cpp
+++ b/src/libslic3r/Brim.cpp
@@ -78,7 +78,7 @@ static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print)
// Assign the maximum Z from four points. This values is valid index of the island
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot,
const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
- pt.Z = std::max(std::max(e1bot.Z, e1top.Z), std::max(e2bot.Z, e2top.Z));
+ pt.z() = std::max(std::max(e1bot.z(), e1top.z()), std::max(e2bot.z(), e2top.z()));
});
// Add islands
clipper.AddPaths(islands_clip, ClipperLib_Z::ptSubject, true);
@@ -90,9 +90,9 @@ static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print)
ConstPrintObjectPtrs top_level_objects_with_brim;
for (int i = 0; i < islands_polytree.ChildCount(); ++i) {
for (const ClipperLib_Z::IntPoint &point : islands_polytree.Childs[i]->Contour) {
- if (point.Z != 0 && processed_objects_idx.find(island_to_object[point.Z - 1]->id().id) == processed_objects_idx.end()) {
- top_level_objects_with_brim.emplace_back(island_to_object[point.Z - 1]);
- processed_objects_idx.insert(island_to_object[point.Z - 1]->id().id);
+ if (point.z() != 0 && processed_objects_idx.find(island_to_object[point.z() - 1]->id().id) == processed_objects_idx.end()) {
+ top_level_objects_with_brim.emplace_back(island_to_object[point.z() - 1]);
+ processed_objects_idx.insert(island_to_object[point.z() - 1]->id().id);
}
}
}
@@ -456,7 +456,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint& e1bot, const ClipperLib_Z::IntPoint& e1top, const ClipperLib_Z::IntPoint& e2bot, const ClipperLib_Z::IntPoint& e2top, ClipperLib_Z::IntPoint& pt) {
// Assign a valid input loop identifier. Such an identifier is strictly positive, the next line is safe even in case one side of a segment
// hat the Z coordinate not set to the contour coordinate.
- pt.Z = std::max(std::max(e1bot.Z, e1top.Z), std::max(e2bot.Z, e2top.Z));
+ pt.z() = std::max(std::max(e1bot.z(), e1top.z()), std::max(e2bot.z(), e2top.z()));
});
// add polygons
clipper.AddPaths(input_clip, ClipperLib_Z::ptSubject, false);
@@ -474,8 +474,8 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
for (const ClipperLib_Z::Path &path : loops_trimmed) {
size_t input_idx = 0;
for (const ClipperLib_Z::IntPoint &pt : path)
- if (pt.Z > 0) {
- input_idx = (size_t)pt.Z;
+ if (pt.z() > 0) {
+ input_idx = (size_t)pt.z();
break;
}
assert(input_idx != 0);
@@ -492,14 +492,14 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
size_t j = i + 1;
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].second == loops_trimmed_order[j].second; ++ j) ;
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
- if (i + 1 == j && first_path.size() > 3 && first_path.front().X == first_path.back().X && first_path.front().Y == first_path.back().Y) {
+ if (i + 1 == j && first_path.size() > 3 && first_path.front().x() == first_path.back().x() && first_path.front().y() == first_path.back().y()) {
auto *loop = new ExtrusionLoop();
brim.entities.emplace_back(loop);
loop->paths.emplace_back(erSkirt, float(flow.mm3_per_mm()), float(flow.width()), float(print.skirt_first_layer_height()));
Points &points = loop->paths.front().polyline.points;
points.reserve(first_path.size());
for (const ClipperLib_Z::IntPoint &pt : first_path)
- points.emplace_back(coord_t(pt.X), coord_t(pt.Y));
+ points.emplace_back(coord_t(pt.x()), coord_t(pt.y()));
i = j;
} else {
//FIXME The path chaining here may not be optimal.
@@ -511,7 +511,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance
Points &points = static_cast(this_loop_trimmed.entities.back())->polyline.points;
points.reserve(path.size());
for (const ClipperLib_Z::IntPoint &pt : path)
- points.emplace_back(coord_t(pt.X), coord_t(pt.Y));
+ points.emplace_back(coord_t(pt.x()), coord_t(pt.y()));
}
chain_and_reorder_extrusion_entities(this_loop_trimmed.entities, &last_pt);
brim.entities.reserve(brim.entities.size() + this_loop_trimmed.entities.size());
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 2abe94656..16299f442 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -23,6 +23,8 @@ add_library(libslic3r STATIC
BridgeDetector.hpp
Brim.cpp
Brim.hpp
+ clipper.cpp
+ clipper.hpp
ClipperUtils.cpp
ClipperUtils.hpp
Config.cpp
diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp
index cd243dfb1..477dbf6f1 100644
--- a/src/libslic3r/ClipperUtils.cpp
+++ b/src/libslic3r/ClipperUtils.cpp
@@ -131,7 +131,7 @@ Slic3r::Polygon ClipperPath_to_Slic3rPolygon(const ClipperLib::Path &input)
{
Polygon retval;
for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit)
- retval.points.emplace_back(pit->X, pit->Y);
+ retval.points.emplace_back(pit->x(), pit->y());
return retval;
}
@@ -139,7 +139,7 @@ Slic3r::Polyline ClipperPath_to_Slic3rPolyline(const ClipperLib::Path &input)
{
Polyline retval;
for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit)
- retval.points.emplace_back(pit->X, pit->Y);
+ retval.points.emplace_back(pit->x(), pit->y());
return retval;
}
@@ -752,7 +752,7 @@ ClipperLib::PolyNodes order_nodes(const ClipperLib::PolyNodes &nodes)
for (const ClipperLib::PolyNode *node : nodes)
ordering_points.emplace_back(
- Point(node->Contour.front().X, node->Contour.front().Y));
+ Point(node->Contour.front().x(), node->Contour.front().y()));
// perform the ordering
ClipperLib::PolyNodes ordered_nodes =
@@ -777,7 +777,7 @@ static void traverse_pt_outside_in(const ClipperLib::PolyNodes &nodes, Polygons
Points ordering_points;
ordering_points.reserve(nodes.size());
for (const ClipperLib::PolyNode *node : nodes)
- ordering_points.emplace_back(node->Contour.front().X, node->Contour.front().Y);
+ ordering_points.emplace_back(node->Contour.front().x(), node->Contour.front().y());
// Perform the ordering, push results recursively.
//FIXME pass the last point to chain_clipper_polynodes?
diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp
index 6668a9ae9..0a34fc93b 100644
--- a/src/libslic3r/ClipperUtils.hpp
+++ b/src/libslic3r/ClipperUtils.hpp
@@ -8,9 +8,9 @@
#include "Surface.hpp"
// import these wherever we're included
-using ClipperLib::jtMiter;
-using ClipperLib::jtRound;
-using ClipperLib::jtSquare;
+using Slic3r::ClipperLib::jtMiter;
+using Slic3r::ClipperLib::jtRound;
+using Slic3r::ClipperLib::jtSquare;
#define CLIPPERUTILS_UNSAFE_OFFSET
diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp
index 6755a6378..5db1d8179 100644
--- a/src/libslic3r/Config.cpp
+++ b/src/libslic3r/Config.cpp
@@ -471,8 +471,8 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src,
{
t_config_option_key opt_key = opt_key_src;
std::string value = value_src;
- // Both opt_key and value may be modified by _handle_legacy().
- // If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by _handle_legacy().
+ // Both opt_key and value may be modified by handle_legacy().
+ // If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by handle_legacy().
this->handle_legacy(opt_key, value);
if (opt_key.empty())
// Ignore the option.
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index 9aab435ed..c49c492a3 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -18,11 +18,53 @@
#include
#include
+#include
#include
#include
#include
+namespace Slic3r {
+ struct FloatOrPercent
+ {
+ double value;
+ bool percent;
+
+ private:
+ friend class cereal::access;
+ template void serialize(Archive& ar) { ar(this->value); ar(this->percent); }
+ };
+
+ inline bool operator==(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return l.value == r.value && l.percent == r.percent; }
+ inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r) throw() { return !(l == r); }
+}
+
+namespace std {
+ template<> struct hash {
+ std::size_t operator()(const Slic3r::FloatOrPercent& v) const noexcept {
+ std::size_t seed = std::hash{}(v.value);
+ return v.percent ? seed ^ 0x9e3779b9 : seed;
+ }
+ };
+
+ template<> struct hash {
+ std::size_t operator()(const Slic3r::Vec2d& v) const noexcept {
+ std::size_t seed = std::hash{}(v.x());
+ boost::hash_combine(seed, std::hash{}(v.y()));
+ return seed;
+ }
+ };
+
+ template<> struct hash {
+ std::size_t operator()(const Slic3r::Vec3d& v) const noexcept {
+ std::size_t seed = std::hash{}(v.x());
+ boost::hash_combine(seed, std::hash{}(v.y()));
+ boost::hash_combine(seed, std::hash{}(v.z()));
+ return seed;
+ }
+ };
+}
+
namespace Slic3r {
// Name of the configuration option.
@@ -137,6 +179,7 @@ public:
virtual void setInt(int /* val */) { throw BadOptionTypeException("Calling ConfigOption::setInt on a non-int ConfigOption"); }
virtual bool operator==(const ConfigOption &rhs) const = 0;
bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); }
+ virtual size_t hash() const throw() = 0;
bool is_scalar() const { return (int(this->type()) & int(coVectorType)) == 0; }
bool is_vector() const { return ! this->is_scalar(); }
// If this option is nullable, then it may have its value or values set to nil.
@@ -185,8 +228,10 @@ public:
return this->value == static_cast*>(&rhs)->value;
}
- bool operator==(const T &rhs) const { return this->value == rhs; }
- bool operator!=(const T &rhs) const { return this->value != rhs; }
+ bool operator==(const T &rhs) const throw() { return this->value == rhs; }
+ bool operator!=(const T &rhs) const throw() { return this->value != rhs; }
+
+ size_t hash() const throw() override { return std::hash{}(this->value); }
private:
friend class cereal::access;
@@ -339,8 +384,16 @@ public:
return this->values == static_cast*>(&rhs)->values;
}
- bool operator==(const std::vector &rhs) const { return this->values == rhs; }
- bool operator!=(const std::vector &rhs) const { return this->values != rhs; }
+ bool operator==(const std::vector &rhs) const throw() { return this->values == rhs; }
+ bool operator!=(const std::vector &rhs) const throw() { return this->values != rhs; }
+
+ size_t hash() const throw() override {
+ std::hash hasher;
+ size_t seed = 0;
+ for (const auto &v : this->values)
+ boost::hash_combine(seed, hasher(v));
+ return seed;
+ }
// Is this option overridden by another option?
// An option overrides another option if it is not nil and not equal.
@@ -413,7 +466,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
double getFloat() const override { return this->value; }
ConfigOption* clone() const override { return new ConfigOptionFloat(*this); }
- bool operator==(const ConfigOptionFloat &rhs) const { return this->value == rhs.value; }
+ bool operator==(const ConfigOptionFloat &rhs) const throw() { return this->value == rhs.value; }
std::string serialize() const override
{
@@ -454,7 +507,7 @@ public:
static ConfigOptionType static_type() { return coFloats; }
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionFloatsTempl(*this); }
- bool operator==(const ConfigOptionFloatsTempl &rhs) const { return vectors_equal(this->values, rhs.values); }
+ bool operator==(const ConfigOptionFloatsTempl &rhs) const throw() { return vectors_equal(this->values, rhs.values); }
bool operator==(const ConfigOption &rhs) const override {
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionFloatsTempl: Comparing incompatible types");
@@ -566,7 +619,7 @@ public:
int getInt() const override { return this->value; }
void setInt(int val) override { this->value = val; }
ConfigOption* clone() const override { return new ConfigOptionInt(*this); }
- bool operator==(const ConfigOptionInt &rhs) const { return this->value == rhs.value; }
+ bool operator==(const ConfigOptionInt &rhs) const throw() { return this->value == rhs.value; }
std::string serialize() const override
{
@@ -606,7 +659,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionIntsTempl(*this); }
ConfigOptionIntsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionIntsTempl &rhs) const { return this->values == rhs.values; }
+ bool operator==(const ConfigOptionIntsTempl &rhs) const throw() { return this->values == rhs.values; }
// Could a special "nil" value be stored inside the vector, indicating undefined value?
bool nullable() const override { return NULLABLE; }
// Special "nil" value to be stored into the vector if this->supports_nil().
@@ -689,7 +742,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionString(*this); }
ConfigOptionString& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionString &rhs) const { return this->value == rhs.value; }
+ bool operator==(const ConfigOptionString &rhs) const throw() { return this->value == rhs.value; }
bool empty() const { return this->value.empty(); }
std::string serialize() const override
@@ -722,7 +775,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionStrings(*this); }
ConfigOptionStrings& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionStrings &rhs) const { return this->values == rhs.values; }
+ bool operator==(const ConfigOptionStrings &rhs) const throw() { return this->values == rhs.values; }
bool is_nil(size_t) const override { return false; }
std::string serialize() const override
@@ -757,7 +810,8 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionPercent(*this); }
ConfigOptionPercent& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionPercent &rhs) const { return this->value == rhs.value; }
+ bool operator==(const ConfigOptionPercent &rhs) const throw() { return this->value == rhs.value; }
+
double get_abs_value(double ratio_over) const { return ratio_over * this->value / 100; }
std::string serialize() const override
@@ -796,8 +850,8 @@ public:
static ConfigOptionType static_type() { return coPercents; }
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionPercentsTempl(*this); }
- ConfigOptionPercentsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionPercentsTempl &rhs) const { return this->values == rhs.values; }
+ ConfigOptionPercentsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
+ bool operator==(const ConfigOptionPercentsTempl &rhs) const throw() { return this->values == rhs.values; }
std::string serialize() const override
{
@@ -856,8 +910,12 @@ public:
assert(dynamic_cast(&rhs));
return *this == *static_cast(&rhs);
}
- bool operator==(const ConfigOptionFloatOrPercent &rhs) const
+ bool operator==(const ConfigOptionFloatOrPercent &rhs) const throw()
{ return this->value == rhs.value && this->percent == rhs.percent; }
+ size_t hash() const throw() override {
+ size_t seed = std::hash{}(this->value);
+ return this->percent ? seed ^ 0x9e3779b9 : seed;
+ }
double get_abs_value(double ratio_over) const
{ return this->percent ? (ratio_over * this->value / 100) : this->value; }
@@ -891,27 +949,6 @@ private:
template void serialize(Archive &ar) { ar(cereal::base_class(this), percent); }
};
-
-struct FloatOrPercent
-{
- double value;
- bool percent;
-
-private:
- friend class cereal::access;
- template void serialize(Archive & ar) { ar(this->value); ar(this->percent); }
-};
-
-inline bool operator==(const FloatOrPercent &l, const FloatOrPercent &r)
-{
- return l.value == r.value && l.percent == r.percent;
-}
-
-inline bool operator!=(const FloatOrPercent& l, const FloatOrPercent& r)
-{
- return !(l == r);
-}
-
template
class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector
{
@@ -925,13 +962,14 @@ public:
static ConfigOptionType static_type() { return coFloatsOrPercents; }
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionFloatsOrPercentsTempl(*this); }
- bool operator==(const ConfigOptionFloatsOrPercentsTempl &rhs) const { return vectors_equal(this->values, rhs.values); }
+ bool operator==(const ConfigOptionFloatsOrPercentsTempl &rhs) const throw() { return vectors_equal(this->values, rhs.values); }
bool operator==(const ConfigOption &rhs) const override {
if (rhs.type() != this->type())
throw Slic3r::RuntimeError("ConfigOptionFloatsOrPercentsTempl: Comparing incompatible types");
assert(dynamic_cast*>(&rhs));
return vectors_equal(this->values, static_cast*>(&rhs)->values);
}
+
// Could a special "nil" value be stored inside the vector, indicating undefined value?
bool nullable() const override { return NULLABLE; }
// Special "nil" value to be stored into the vector if this->supports_nil().
@@ -1038,7 +1076,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionPoint(*this); }
ConfigOptionPoint& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionPoint &rhs) const { return this->value == rhs.value; }
+ bool operator==(const ConfigOptionPoint &rhs) const throw() { return this->value == rhs.value; }
std::string serialize() const override
{
@@ -1074,7 +1112,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionPoints(*this); }
ConfigOptionPoints& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionPoints &rhs) const { return this->values == rhs.values; }
+ bool operator==(const ConfigOptionPoints &rhs) const throw() { return this->values == rhs.values; }
bool is_nil(size_t) const override { return false; }
std::string serialize() const override
@@ -1146,7 +1184,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionPoint3(*this); }
ConfigOptionPoint3& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionPoint3 &rhs) const { return this->value == rhs.value; }
+ bool operator==(const ConfigOptionPoint3 &rhs) const throw() { return this->value == rhs.value; }
std::string serialize() const override
{
@@ -1183,7 +1221,7 @@ public:
bool getBool() const override { return this->value; }
ConfigOption* clone() const override { return new ConfigOptionBool(*this); }
ConfigOptionBool& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionBool &rhs) const { return this->value == rhs.value; }
+ bool operator==(const ConfigOptionBool &rhs) const throw() { return this->value == rhs.value; }
std::string serialize() const override
{
@@ -1217,7 +1255,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionBoolsTempl(*this); }
ConfigOptionBoolsTempl& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionBoolsTempl &rhs) const { return this->values == rhs.values; }
+ bool operator==(const ConfigOptionBoolsTempl &rhs) const throw() { return this->values == rhs.values; }
// Could a special "nil" value be stored inside the vector, indicating undefined value?
bool nullable() const override { return NULLABLE; }
// Special "nil" value to be stored into the vector if this->supports_nil().
@@ -1311,7 +1349,7 @@ public:
ConfigOptionType type() const override { return static_type(); }
ConfigOption* clone() const override { return new ConfigOptionEnum(*this); }
ConfigOptionEnum& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
- bool operator==(const ConfigOptionEnum &rhs) const { return this->value == rhs.value; }
+ bool operator==(const ConfigOptionEnum