ClipperLib: Further optimization of memory allocation using scalable_allocator.

ClipperLib: SimplifyPolygon() - changed default winding number to positive,
      added strictly_simple parameter.
ClipperUtlis simplify_polygons() - removed "remove_collinear" parameter
This commit is contained in:
Vojtech Bubnik 2023-05-02 12:59:20 +02:00
parent 03608580c0
commit a7e17df25f
5 changed files with 137 additions and 145 deletions

View File

@ -73,25 +73,6 @@ static int const Skip = -2; //edge that would otherwise close a path
#define TOLERANCE (1.0e-20)
#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
// Output polygon.
struct OutRec {
int Idx;
bool IsHole;
bool IsOpen;
//The 'FirstLeft' field points to another OutRec that contains or is the
//'parent' of OutRec. It is 'first left' because the ActiveEdgeList (AEL) is
//parsed left from the current edge (owning OutRec) until the owner OutRec
//is found. This field simplifies sorting the polygons into a tree structure
//which reflects the parent/child relationships of all polygons.
//This field should be renamed Parent, and will be later.
OutRec *FirstLeft;
// Used only by void Clipper::BuildResult2(PolyTree& polytree)
PolyNode *PolyNd;
// Linked list of output points, dynamically allocated.
OutPt *Pts;
OutPt *BottomPt;
};
//------------------------------------------------------------------------------
inline IntPoint IntPoint2d(cInt x, cInt y)
@ -1061,8 +1042,7 @@ IntRect ClipperBase::GetBounds()
Clipper::Clipper(int initOptions) :
ClipperBase(),
m_OutPtsFree(nullptr),
m_OutPtsChunkSize(32),
m_OutPtsChunkLast(32),
m_OutPtsChunkLast(m_OutPtsChunkSize),
m_ActiveEdges(nullptr),
m_SortedEdges(nullptr)
{
@ -1153,23 +1133,23 @@ bool Clipper::ExecuteInternal()
//FIXME Vojtech: Does it not invalidate the loop hierarchy maintained as OutRec::FirstLeft pointers?
//FIXME Vojtech: The area is calculated with floats, it may not be numerically stable!
{
for (OutRec *outRec : m_PolyOuts)
if (outRec->Pts && !outRec->IsOpen && (outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0))
ReversePolyPtLinks(outRec->Pts);
for (OutRec &outRec : m_PolyOuts)
if (outRec.Pts && !outRec.IsOpen && (outRec.IsHole ^ m_ReverseOutput) == (Area(outRec) > 0))
ReversePolyPtLinks(outRec.Pts);
}
JoinCommonEdges();
//unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
{
for (OutRec *outRec : m_PolyOuts)
if (outRec->Pts) {
if (outRec->IsOpen)
for (OutRec &outRec : m_PolyOuts)
if (outRec.Pts) {
if (outRec.IsOpen)
// Removes duplicate points.
FixupOutPolyline(*outRec);
FixupOutPolyline(outRec);
else
// Removes duplicate points and simplifies consecutive parallel edges by removing the middle vertex.
FixupOutPolygon(*outRec);
FixupOutPolygon(outRec);
}
}
// For each polygon, search for exactly duplicate non-successive points.
@ -1194,22 +1174,18 @@ OutPt* Clipper::AllocateOutPt()
m_OutPtsFree = pt->Next;
} else if (m_OutPtsChunkLast < m_OutPtsChunkSize) {
// Get a point from the last chunk.
pt = m_OutPts.back() + (m_OutPtsChunkLast ++);
pt = &m_OutPts.back()[m_OutPtsChunkLast ++];
} else {
// The last chunk is full. Allocate a new one.
m_OutPts.push_back(new OutPt[m_OutPtsChunkSize]);
m_OutPts.push_back({});
m_OutPtsChunkLast = 1;
pt = m_OutPts.back();
pt = &m_OutPts.back().front();
}
return pt;
}
void Clipper::DisposeAllOutRecs()
{
for (OutPt *pts : m_OutPts)
delete[] pts;
for (OutRec *rec : m_PolyOuts)
delete rec;
m_OutPts.clear();
m_OutPtsFree = nullptr;
m_OutPtsChunkLast = m_OutPtsChunkSize;
@ -1832,7 +1808,7 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt)
}
//------------------------------------------------------------------------------
void Clipper::SetHoleState(TEdge *e, OutRec *outrec) const
void Clipper::SetHoleState(TEdge *e, OutRec *outrec)
{
bool IsHole = false;
TEdge *e2 = e->PrevInAEL;
@ -1842,7 +1818,7 @@ void Clipper::SetHoleState(TEdge *e, OutRec *outrec) const
{
IsHole = !IsHole;
if (! outrec->FirstLeft)
outrec->FirstLeft = m_PolyOuts[e2->OutIdx];
outrec->FirstLeft = &m_PolyOuts[e2->OutIdx];
}
e2 = e2->PrevInAEL;
}
@ -1883,18 +1859,18 @@ bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
OutRec* Clipper::GetOutRec(int Idx)
{
OutRec* outrec = m_PolyOuts[Idx];
while (outrec != m_PolyOuts[outrec->Idx])
outrec = m_PolyOuts[outrec->Idx];
OutRec* outrec = &m_PolyOuts[Idx];
while (outrec != &m_PolyOuts[outrec->Idx])
outrec = &m_PolyOuts[outrec->Idx];
return outrec;
}
//------------------------------------------------------------------------------
void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) const
void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
{
//get the start and ends of both output polygons ...
OutRec *outRec1 = m_PolyOuts[e1->OutIdx];
OutRec *outRec2 = m_PolyOuts[e2->OutIdx];
OutRec *outRec1 = &m_PolyOuts[e1->OutIdx];
OutRec *outRec2 = &m_PolyOuts[e2->OutIdx];
OutRec *holeStateRec;
if (Param1RightOfParam2(outRec1, outRec2))
@ -1991,16 +1967,16 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) const
OutRec* Clipper::CreateOutRec()
{
OutRec* result = new OutRec;
result->IsHole = false;
result->IsOpen = false;
result->FirstLeft = 0;
result->Pts = 0;
result->BottomPt = 0;
result->PolyNd = 0;
m_PolyOuts.push_back(result);
result->Idx = (int)m_PolyOuts.size()-1;
return result;
m_PolyOuts.push_back({});
OutRec &result = m_PolyOuts.back();
result.IsHole = false;
result.IsOpen = false;
result.FirstLeft = 0;
result.Pts = 0;
result.BottomPt = 0;
result.PolyNd = 0;
result.Idx = (int)m_PolyOuts.size()-1;
return &result;
}
//------------------------------------------------------------------------------
@ -2022,7 +1998,7 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
return newOp;
} else
{
OutRec *outRec = m_PolyOuts[e->OutIdx];
OutRec *outRec = &m_PolyOuts[e->OutIdx];
//OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most'
OutPt* op = outRec->Pts;
@ -2045,7 +2021,7 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
OutPt* Clipper::GetLastOutPt(TEdge *e)
{
OutRec *outRec = m_PolyOuts[e->OutIdx];
OutRec *outRec = &m_PolyOuts[e->OutIdx];
if (e->Side == esLeft)
return outRec->Pts;
else
@ -2216,7 +2192,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
{
Direction dir;
cInt horzLeft, horzRight;
bool IsOpen = (horzEdge->OutIdx >= 0 && m_PolyOuts[horzEdge->OutIdx]->IsOpen);
bool IsOpen = (horzEdge->OutIdx >= 0 && m_PolyOuts[horzEdge->OutIdx].IsOpen);
GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
@ -2778,12 +2754,12 @@ int PointCount(OutPt *Pts)
void Clipper::BuildResult(Paths &polys)
{
polys.reserve(m_PolyOuts.size());
for (OutRec* outRec : m_PolyOuts)
for (OutRec &outRec : m_PolyOuts)
{
assert(! outRec->IsOpen);
if (!outRec->Pts) continue;
assert(! outRec.IsOpen);
if (!outRec.Pts) continue;
Path pg;
OutPt* p = outRec->Pts->Prev;
OutPt* p = outRec.Pts->Prev;
int cnt = PointCount(p);
if (cnt < 2) continue;
pg.reserve(cnt);
@ -2802,31 +2778,31 @@ void Clipper::BuildResult2(PolyTree& polytree)
polytree.Clear();
polytree.AllNodes.reserve(m_PolyOuts.size());
//add each output polygon/contour to polytree ...
for (OutRec* outRec : m_PolyOuts)
for (OutRec &outRec : m_PolyOuts)
{
int cnt = PointCount(outRec->Pts);
if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3))
int cnt = PointCount(outRec.Pts);
if ((outRec.IsOpen && cnt < 2) || (!outRec.IsOpen && cnt < 3))
// Ignore an invalid output loop or a polyline.
continue;
//skip OutRecs that (a) contain outermost polygons or
//(b) already have the correct owner/child linkage ...
if (outRec->FirstLeft &&
(outRec->IsHole == outRec->FirstLeft->IsHole || ! outRec->FirstLeft->Pts)) {
OutRec* orfl = outRec->FirstLeft;
while (orfl && ((orfl->IsHole == outRec->IsHole) || !orfl->Pts))
if (outRec.FirstLeft &&
(outRec.IsHole == outRec.FirstLeft->IsHole || ! outRec.FirstLeft->Pts)) {
OutRec* orfl = outRec.FirstLeft;
while (orfl && ((orfl->IsHole == outRec.IsHole) || !orfl->Pts))
orfl = orfl->FirstLeft;
outRec->FirstLeft = orfl;
outRec.FirstLeft = orfl;
}
//nb: polytree takes ownership of all the PolyNodes
polytree.AllNodes.emplace_back(PolyNode());
PolyNode* pn = &polytree.AllNodes.back();
outRec->PolyNd = pn;
outRec.PolyNd = pn;
pn->Parent = 0;
pn->Index = 0;
pn->Contour.reserve(cnt);
OutPt *op = outRec->Pts->Prev;
OutPt *op = outRec.Pts->Prev;
for (int j = 0; j < cnt; j++)
{
pn->Contour.emplace_back(op->Pt);
@ -2836,18 +2812,18 @@ void Clipper::BuildResult2(PolyTree& polytree)
//fixup PolyNode links etc ...
polytree.Childs.reserve(m_PolyOuts.size());
for (OutRec* outRec : m_PolyOuts)
for (OutRec &outRec : m_PolyOuts)
{
if (!outRec->PolyNd) continue;
if (outRec->IsOpen)
if (!outRec.PolyNd) continue;
if (outRec.IsOpen)
{
outRec->PolyNd->m_IsOpen = true;
polytree.AddChild(*outRec->PolyNd);
outRec.PolyNd->m_IsOpen = true;
polytree.AddChild(*outRec.PolyNd);
}
else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd)
outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd);
else if (outRec.FirstLeft && outRec.FirstLeft->PolyNd)
outRec.FirstLeft->PolyNd->AddChild(*outRec.PolyNd);
else
polytree.AddChild(*outRec->PolyNd);
polytree.AddChild(*outRec.PolyNd);
}
}
//------------------------------------------------------------------------------
@ -3193,26 +3169,26 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
//----------------------------------------------------------------------
// This is potentially very expensive! O(n^3)!
void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) const
void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
{
//tests if NewOutRec contains the polygon before reassigning FirstLeft
for (OutRec *outRec : m_PolyOuts)
for (OutRec &outRec : m_PolyOuts)
{
if (!outRec->Pts || !outRec->FirstLeft) continue;
OutRec* firstLeft = outRec->FirstLeft;
if (!outRec.Pts || !outRec.FirstLeft) continue;
OutRec* firstLeft = outRec.FirstLeft;
// Skip empty polygons.
while (firstLeft && !firstLeft->Pts) firstLeft = firstLeft->FirstLeft;
if (firstLeft == OldOutRec && Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts))
outRec->FirstLeft = NewOutRec;
if (firstLeft == OldOutRec && Poly2ContainsPoly1(outRec.Pts, NewOutRec->Pts))
outRec.FirstLeft = NewOutRec;
}
}
//----------------------------------------------------------------------
void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) const
void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec)
{
//reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
for (OutRec *outRec : m_PolyOuts)
if (outRec->FirstLeft == OldOutRec) outRec->FirstLeft = NewOutRec;
for (OutRec &outRec : m_PolyOuts)
if (outRec.FirstLeft == OldOutRec) outRec.FirstLeft = NewOutRec;
}
//----------------------------------------------------------------------
@ -3253,13 +3229,13 @@ void Clipper::JoinCommonEdges()
if (m_UsingPolyTree)
for (size_t j = 0; j < m_PolyOuts.size() - 1; j++)
{
OutRec* oRec = m_PolyOuts[j];
OutRec* firstLeft = oRec->FirstLeft;
OutRec &oRec = m_PolyOuts[j];
OutRec* firstLeft = oRec.FirstLeft;
while (firstLeft && !firstLeft->Pts) firstLeft = firstLeft->FirstLeft;
if (!oRec->Pts || firstLeft != outRec1 ||
oRec->IsHole == outRec1->IsHole) continue;
if (Poly2ContainsPoly1(oRec->Pts, join.OutPt2))
oRec->FirstLeft = outRec2;
if (!oRec.Pts || firstLeft != outRec1 ||
oRec.IsHole == outRec1->IsHole) continue;
if (Poly2ContainsPoly1(oRec.Pts, join.OutPt2))
oRec.FirstLeft = outRec2;
}
if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts))
@ -3771,13 +3747,13 @@ void Clipper::DoSimplePolygons()
size_t i = 0;
while (i < m_PolyOuts.size())
{
OutRec* outrec = m_PolyOuts[i++];
OutPt* op = outrec->Pts;
if (!op || outrec->IsOpen) continue;
OutRec &outrec = m_PolyOuts[i++];
OutPt* op = outrec.Pts;
if (!op || outrec.IsOpen) continue;
do //for each Pt in Polygon until duplicate found do ...
{
OutPt* op2 = op->Next;
while (op2 != outrec->Pts)
while (op2 != outrec.Pts)
{
if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op)
{
@ -3789,37 +3765,37 @@ void Clipper::DoSimplePolygons()
op2->Prev = op3;
op3->Next = op2;
outrec->Pts = op;
outrec.Pts = op;
OutRec* outrec2 = CreateOutRec();
outrec2->Pts = op2;
UpdateOutPtIdxs(*outrec2);
if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts))
if (Poly2ContainsPoly1(outrec2->Pts, outrec.Pts))
{
//OutRec2 is contained by OutRec1 ...
outrec2->IsHole = !outrec->IsHole;
outrec2->FirstLeft = outrec;
outrec2->IsHole = !outrec.IsHole;
outrec2->FirstLeft = &outrec;
// For each m_PolyOuts, replace FirstLeft from outRec2 to outrec.
if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec);
if (m_UsingPolyTree) FixupFirstLefts2(outrec2, &outrec);
}
else
if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts))
if (Poly2ContainsPoly1(outrec.Pts, outrec2->Pts))
{
//OutRec1 is contained by OutRec2 ...
outrec2->IsHole = outrec->IsHole;
outrec->IsHole = !outrec2->IsHole;
outrec2->FirstLeft = outrec->FirstLeft;
outrec->FirstLeft = outrec2;
outrec2->IsHole = outrec.IsHole;
outrec.IsHole = !outrec2->IsHole;
outrec2->FirstLeft = outrec.FirstLeft;
outrec.FirstLeft = outrec2;
// For each m_PolyOuts, replace FirstLeft from outrec to outrec2.
if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2);
if (m_UsingPolyTree) FixupFirstLefts2(&outrec, outrec2);
}
else
{
//the 2 polygons are separate ...
outrec2->IsHole = outrec->IsHole;
outrec2->FirstLeft = outrec->FirstLeft;
outrec2->IsHole = outrec.IsHole;
outrec2->FirstLeft = outrec.FirstLeft;
// For each polygon of m_PolyOuts, replace FirstLeft from outrec to outrec2 if the polygon is inside outRec2.
//FIXME This is potentially very expensive! O(n^3)!
if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2);
if (m_UsingPolyTree) FixupFirstLefts1(&outrec, outrec2);
}
op2 = op; //ie get ready for the Next iteration
}
@ -3827,7 +3803,7 @@ void Clipper::DoSimplePolygons()
}
op = op->Next;
}
while (op != outrec->Pts);
while (op != outrec.Pts);
}
}
//------------------------------------------------------------------------------
@ -3845,10 +3821,10 @@ void ReversePaths(Paths& p)
}
//------------------------------------------------------------------------------
Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType)
Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType, bool strictly_simple /* = true */)
{
Clipper c;
c.StrictlySimple(true);
c.StrictlySimple(strictly_simple);
c.AddPath(in_poly, ptSubject, true);
Paths out;
c.Execute(ctUnion, out, fillType, fillType);

View File

@ -52,6 +52,7 @@
//use_deprecated: Enables temporary support for the obsolete functions
//#define use_deprecated
#include <array>
#include <vector>
#include <deque>
#include <stdexcept>
@ -199,7 +200,8 @@ double Area(const Path &poly);
inline bool Orientation(const Path &poly) { return Area(poly) >= 0; }
int PointInPolygon(const IntPoint &pt, const Path &path);
Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType = pftEvenOdd);
// Union with "strictly simple" fix enabled.
Paths SimplifyPolygon(const Path &in_poly, PolyFillType fillType = pftNonZero, bool strictly_simple = true);
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
void CleanPolygon(Path& poly, double distance = 1.415);
@ -284,7 +286,25 @@ enum EdgeSide { esLeft = 1, esRight = 2};
using OutPts = std::vector<OutPt, Allocator<OutPt>>;
struct OutRec;
// Output polygon.
struct OutRec {
int Idx;
bool IsHole;
bool IsOpen;
//The 'FirstLeft' field points to another OutRec that contains or is the
//'parent' of OutRec. It is 'first left' because the ActiveEdgeList (AEL) is
//parsed left from the current edge (owning OutRec) until the owner OutRec
//is found. This field simplifies sorting the polygons into a tree structure
//which reflects the parent/child relationships of all polygons.
//This field should be renamed Parent, and will be later.
OutRec* FirstLeft;
// Used only by void Clipper::BuildResult2(PolyTree& polytree)
PolyNode* PolyNd;
// Linked list of output points, dynamically allocated.
OutPt* Pts;
OutPt* BottomPt;
};
struct Join {
Join(OutPt *OutPt1, OutPt *OutPt2, IntPoint OffPt) :
OutPt1(OutPt1), OutPt2(OutPt2), OffPt(OffPt) {}
@ -432,12 +452,12 @@ protected:
private:
// Output polygons.
std::vector<OutRec*, Allocator<OutRec*>> m_PolyOuts;
std::deque<OutRec, Allocator<OutRec>> m_PolyOuts;
// Output points, allocated by a continuous sets of m_OutPtsChunkSize.
std::vector<OutPt*, Allocator<OutPt*>> m_OutPts;
static constexpr const size_t m_OutPtsChunkSize = 32;
std::deque<std::array<OutPt, m_OutPtsChunkSize>, Allocator<std::array<OutPt, m_OutPtsChunkSize>>> m_OutPts;
// List of free output points, to be used before taking a point from m_OutPts or allocating a new chunk.
OutPt *m_OutPtsFree;
size_t m_OutPtsChunkSize;
size_t m_OutPtsChunkLast;
std::vector<Join, Allocator<Join>> m_Joins;
@ -482,7 +502,7 @@ private:
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2) const;
void AppendPolygon(TEdge *e1, TEdge *e2);
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
OutRec* CreateOutRec();
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
@ -498,7 +518,7 @@ private:
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);
void BuildResult2(PolyTree& polytree);
void SetHoleState(TEdge *e, OutRec *outrec) const;
void SetHoleState(TEdge *e, OutRec *outrec);
bool FixupIntersectionOrder();
void FixupOutPolygon(OutRec &outrec);
void FixupOutPolyline(OutRec &outrec);
@ -508,8 +528,8 @@ private:
bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, const IntPoint &Pt, bool DiscardLeft);
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) const;
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) const;
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef CLIPPERLIB_USE_XYZ
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
#endif
@ -567,10 +587,11 @@ class clipperException : public std::exception
};
//------------------------------------------------------------------------------
// Union with "strictly simple" fix enabled.
template<typename PathsProvider>
inline Paths SimplifyPolygons(PathsProvider &&in_polys, PolyFillType fillType = pftEvenOdd) {
inline Paths SimplifyPolygons(PathsProvider &&in_polys, PolyFillType fillType = pftNonZero, bool strictly_simple = true) {
Clipper c;
c.StrictlySimple(true);
c.StrictlySimple(strictly_simple);
c.AddPaths(std::forward<PathsProvider>(in_polys), ptSubject, true);
Paths out;
c.Execute(ctUnion, out, fillType, fillType);

View File

@ -232,7 +232,7 @@ std::unique_ptr<LocToLineGrid> cre
void fixSelfIntersections(const coord_t epsilon, Polygons &thiss)
{
if (epsilon < 1) {
ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(thiss));
ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(thiss), ClipperLib::pftEvenOdd);
return;
}
@ -273,7 +273,7 @@ void fixSelfIntersections(const coord_t epsilon, Polygons &thiss)
}
}
ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(thiss));
ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(thiss), ClipperLib::pftEvenOdd);
}
/*!

View File

@ -964,20 +964,17 @@ Polygons union_pt_chained_outside_in(const Polygons &subject)
return retval;
}
Polygons simplify_polygons(const Polygons &subject, bool preserve_collinear)
Polygons simplify_polygons(const Polygons &subject)
{
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
ClipperLib::Paths output;
if (preserve_collinear) {
ClipperLib::Clipper c;
c.PreserveCollinear(true);
// c.PreserveCollinear(true);
//FIXME StrictlySimple is very expensive! Is it needed?
c.StrictlySimple(true);
c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true);
c.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
} else {
output = ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(subject), ClipperLib::pftNonZero);
}
// convert into Slic3r polygons
return to_polygons(std::move(output));
@ -987,12 +984,10 @@ ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear
{
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
if (! preserve_collinear)
return union_ex(simplify_polygons(subject, false));
ClipperLib::PolyTree polytree;
ClipperLib::Clipper c;
c.PreserveCollinear(true);
// c.PreserveCollinear(true);
//FIXME StrictlySimple is very expensive! Is it needed?
c.StrictlySimple(true);
c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true);
c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero);

View File

@ -596,8 +596,8 @@ void traverse_pt(const ClipperLib::PolyNodes &nodes, ExOrJustPolygons *retval)
/* OTHER */
Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject, bool preserve_collinear = false);
Slic3r::ExPolygons simplify_polygons_ex(const Slic3r::Polygons &subject, bool preserve_collinear = false);
Slic3r::Polygons simplify_polygons(const Slic3r::Polygons &subject);
Slic3r::ExPolygons simplify_polygons_ex(const Slic3r::Polygons &subject);
Polygons top_level_islands(const Slic3r::Polygons &polygons);