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:
parent
03608580c0
commit
a7e17df25f
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -964,21 +964,18 @@ 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.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);
|
||||
}
|
||||
|
||||
ClipperLib::Clipper c;
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user