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 TOLERANCE (1.0e-20)
|
||||||
#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
|
#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)
|
inline IntPoint IntPoint2d(cInt x, cInt y)
|
||||||
@ -1061,8 +1042,7 @@ IntRect ClipperBase::GetBounds()
|
|||||||
Clipper::Clipper(int initOptions) :
|
Clipper::Clipper(int initOptions) :
|
||||||
ClipperBase(),
|
ClipperBase(),
|
||||||
m_OutPtsFree(nullptr),
|
m_OutPtsFree(nullptr),
|
||||||
m_OutPtsChunkSize(32),
|
m_OutPtsChunkLast(m_OutPtsChunkSize),
|
||||||
m_OutPtsChunkLast(32),
|
|
||||||
m_ActiveEdges(nullptr),
|
m_ActiveEdges(nullptr),
|
||||||
m_SortedEdges(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: 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!
|
//FIXME Vojtech: The area is calculated with floats, it may not be numerically stable!
|
||||||
{
|
{
|
||||||
for (OutRec *outRec : m_PolyOuts)
|
for (OutRec &outRec : m_PolyOuts)
|
||||||
if (outRec->Pts && !outRec->IsOpen && (outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0))
|
if (outRec.Pts && !outRec.IsOpen && (outRec.IsHole ^ m_ReverseOutput) == (Area(outRec) > 0))
|
||||||
ReversePolyPtLinks(outRec->Pts);
|
ReversePolyPtLinks(outRec.Pts);
|
||||||
}
|
}
|
||||||
|
|
||||||
JoinCommonEdges();
|
JoinCommonEdges();
|
||||||
|
|
||||||
//unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
|
//unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
|
||||||
{
|
{
|
||||||
for (OutRec *outRec : m_PolyOuts)
|
for (OutRec &outRec : m_PolyOuts)
|
||||||
if (outRec->Pts) {
|
if (outRec.Pts) {
|
||||||
if (outRec->IsOpen)
|
if (outRec.IsOpen)
|
||||||
// Removes duplicate points.
|
// Removes duplicate points.
|
||||||
FixupOutPolyline(*outRec);
|
FixupOutPolyline(outRec);
|
||||||
else
|
else
|
||||||
// Removes duplicate points and simplifies consecutive parallel edges by removing the middle vertex.
|
// 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.
|
// For each polygon, search for exactly duplicate non-successive points.
|
||||||
@ -1194,22 +1174,18 @@ OutPt* Clipper::AllocateOutPt()
|
|||||||
m_OutPtsFree = pt->Next;
|
m_OutPtsFree = pt->Next;
|
||||||
} else if (m_OutPtsChunkLast < m_OutPtsChunkSize) {
|
} else if (m_OutPtsChunkLast < m_OutPtsChunkSize) {
|
||||||
// Get a point from the last chunk.
|
// Get a point from the last chunk.
|
||||||
pt = m_OutPts.back() + (m_OutPtsChunkLast ++);
|
pt = &m_OutPts.back()[m_OutPtsChunkLast ++];
|
||||||
} else {
|
} else {
|
||||||
// The last chunk is full. Allocate a new one.
|
// The last chunk is full. Allocate a new one.
|
||||||
m_OutPts.push_back(new OutPt[m_OutPtsChunkSize]);
|
m_OutPts.push_back({});
|
||||||
m_OutPtsChunkLast = 1;
|
m_OutPtsChunkLast = 1;
|
||||||
pt = m_OutPts.back();
|
pt = &m_OutPts.back().front();
|
||||||
}
|
}
|
||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clipper::DisposeAllOutRecs()
|
void Clipper::DisposeAllOutRecs()
|
||||||
{
|
{
|
||||||
for (OutPt *pts : m_OutPts)
|
|
||||||
delete[] pts;
|
|
||||||
for (OutRec *rec : m_PolyOuts)
|
|
||||||
delete rec;
|
|
||||||
m_OutPts.clear();
|
m_OutPts.clear();
|
||||||
m_OutPtsFree = nullptr;
|
m_OutPtsFree = nullptr;
|
||||||
m_OutPtsChunkLast = m_OutPtsChunkSize;
|
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;
|
bool IsHole = false;
|
||||||
TEdge *e2 = e->PrevInAEL;
|
TEdge *e2 = e->PrevInAEL;
|
||||||
@ -1842,7 +1818,7 @@ void Clipper::SetHoleState(TEdge *e, OutRec *outrec) const
|
|||||||
{
|
{
|
||||||
IsHole = !IsHole;
|
IsHole = !IsHole;
|
||||||
if (! outrec->FirstLeft)
|
if (! outrec->FirstLeft)
|
||||||
outrec->FirstLeft = m_PolyOuts[e2->OutIdx];
|
outrec->FirstLeft = &m_PolyOuts[e2->OutIdx];
|
||||||
}
|
}
|
||||||
e2 = e2->PrevInAEL;
|
e2 = e2->PrevInAEL;
|
||||||
}
|
}
|
||||||
@ -1883,18 +1859,18 @@ bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
|
|||||||
|
|
||||||
OutRec* Clipper::GetOutRec(int Idx)
|
OutRec* Clipper::GetOutRec(int Idx)
|
||||||
{
|
{
|
||||||
OutRec* outrec = m_PolyOuts[Idx];
|
OutRec* outrec = &m_PolyOuts[Idx];
|
||||||
while (outrec != m_PolyOuts[outrec->Idx])
|
while (outrec != &m_PolyOuts[outrec->Idx])
|
||||||
outrec = m_PolyOuts[outrec->Idx];
|
outrec = &m_PolyOuts[outrec->Idx];
|
||||||
return outrec;
|
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 ...
|
//get the start and ends of both output polygons ...
|
||||||
OutRec *outRec1 = m_PolyOuts[e1->OutIdx];
|
OutRec *outRec1 = &m_PolyOuts[e1->OutIdx];
|
||||||
OutRec *outRec2 = m_PolyOuts[e2->OutIdx];
|
OutRec *outRec2 = &m_PolyOuts[e2->OutIdx];
|
||||||
|
|
||||||
OutRec *holeStateRec;
|
OutRec *holeStateRec;
|
||||||
if (Param1RightOfParam2(outRec1, outRec2))
|
if (Param1RightOfParam2(outRec1, outRec2))
|
||||||
@ -1991,16 +1967,16 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) const
|
|||||||
|
|
||||||
OutRec* Clipper::CreateOutRec()
|
OutRec* Clipper::CreateOutRec()
|
||||||
{
|
{
|
||||||
OutRec* result = new OutRec;
|
m_PolyOuts.push_back({});
|
||||||
result->IsHole = false;
|
OutRec &result = m_PolyOuts.back();
|
||||||
result->IsOpen = false;
|
result.IsHole = false;
|
||||||
result->FirstLeft = 0;
|
result.IsOpen = false;
|
||||||
result->Pts = 0;
|
result.FirstLeft = 0;
|
||||||
result->BottomPt = 0;
|
result.Pts = 0;
|
||||||
result->PolyNd = 0;
|
result.BottomPt = 0;
|
||||||
m_PolyOuts.push_back(result);
|
result.PolyNd = 0;
|
||||||
result->Idx = (int)m_PolyOuts.size()-1;
|
result.Idx = (int)m_PolyOuts.size()-1;
|
||||||
return result;
|
return &result;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -2022,7 +1998,7 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
|
|||||||
return newOp;
|
return newOp;
|
||||||
} else
|
} 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'
|
//OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most'
|
||||||
OutPt* op = outRec->Pts;
|
OutPt* op = outRec->Pts;
|
||||||
|
|
||||||
@ -2045,7 +2021,7 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
|
|||||||
|
|
||||||
OutPt* Clipper::GetLastOutPt(TEdge *e)
|
OutPt* Clipper::GetLastOutPt(TEdge *e)
|
||||||
{
|
{
|
||||||
OutRec *outRec = m_PolyOuts[e->OutIdx];
|
OutRec *outRec = &m_PolyOuts[e->OutIdx];
|
||||||
if (e->Side == esLeft)
|
if (e->Side == esLeft)
|
||||||
return outRec->Pts;
|
return outRec->Pts;
|
||||||
else
|
else
|
||||||
@ -2216,7 +2192,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
|
|||||||
{
|
{
|
||||||
Direction dir;
|
Direction dir;
|
||||||
cInt horzLeft, horzRight;
|
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);
|
GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
|
||||||
|
|
||||||
@ -2778,12 +2754,12 @@ int PointCount(OutPt *Pts)
|
|||||||
void Clipper::BuildResult(Paths &polys)
|
void Clipper::BuildResult(Paths &polys)
|
||||||
{
|
{
|
||||||
polys.reserve(m_PolyOuts.size());
|
polys.reserve(m_PolyOuts.size());
|
||||||
for (OutRec* outRec : m_PolyOuts)
|
for (OutRec &outRec : m_PolyOuts)
|
||||||
{
|
{
|
||||||
assert(! outRec->IsOpen);
|
assert(! outRec.IsOpen);
|
||||||
if (!outRec->Pts) continue;
|
if (!outRec.Pts) continue;
|
||||||
Path pg;
|
Path pg;
|
||||||
OutPt* p = outRec->Pts->Prev;
|
OutPt* p = outRec.Pts->Prev;
|
||||||
int cnt = PointCount(p);
|
int cnt = PointCount(p);
|
||||||
if (cnt < 2) continue;
|
if (cnt < 2) continue;
|
||||||
pg.reserve(cnt);
|
pg.reserve(cnt);
|
||||||
@ -2802,31 +2778,31 @@ void Clipper::BuildResult2(PolyTree& polytree)
|
|||||||
polytree.Clear();
|
polytree.Clear();
|
||||||
polytree.AllNodes.reserve(m_PolyOuts.size());
|
polytree.AllNodes.reserve(m_PolyOuts.size());
|
||||||
//add each output polygon/contour to polytree ...
|
//add each output polygon/contour to polytree ...
|
||||||
for (OutRec* outRec : m_PolyOuts)
|
for (OutRec &outRec : m_PolyOuts)
|
||||||
{
|
{
|
||||||
int cnt = PointCount(outRec->Pts);
|
int cnt = PointCount(outRec.Pts);
|
||||||
if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3))
|
if ((outRec.IsOpen && cnt < 2) || (!outRec.IsOpen && cnt < 3))
|
||||||
// Ignore an invalid output loop or a polyline.
|
// Ignore an invalid output loop or a polyline.
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//skip OutRecs that (a) contain outermost polygons or
|
//skip OutRecs that (a) contain outermost polygons or
|
||||||
//(b) already have the correct owner/child linkage ...
|
//(b) already have the correct owner/child linkage ...
|
||||||
if (outRec->FirstLeft &&
|
if (outRec.FirstLeft &&
|
||||||
(outRec->IsHole == outRec->FirstLeft->IsHole || ! outRec->FirstLeft->Pts)) {
|
(outRec.IsHole == outRec.FirstLeft->IsHole || ! outRec.FirstLeft->Pts)) {
|
||||||
OutRec* orfl = outRec->FirstLeft;
|
OutRec* orfl = outRec.FirstLeft;
|
||||||
while (orfl && ((orfl->IsHole == outRec->IsHole) || !orfl->Pts))
|
while (orfl && ((orfl->IsHole == outRec.IsHole) || !orfl->Pts))
|
||||||
orfl = orfl->FirstLeft;
|
orfl = orfl->FirstLeft;
|
||||||
outRec->FirstLeft = orfl;
|
outRec.FirstLeft = orfl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//nb: polytree takes ownership of all the PolyNodes
|
//nb: polytree takes ownership of all the PolyNodes
|
||||||
polytree.AllNodes.emplace_back(PolyNode());
|
polytree.AllNodes.emplace_back(PolyNode());
|
||||||
PolyNode* pn = &polytree.AllNodes.back();
|
PolyNode* pn = &polytree.AllNodes.back();
|
||||||
outRec->PolyNd = pn;
|
outRec.PolyNd = pn;
|
||||||
pn->Parent = 0;
|
pn->Parent = 0;
|
||||||
pn->Index = 0;
|
pn->Index = 0;
|
||||||
pn->Contour.reserve(cnt);
|
pn->Contour.reserve(cnt);
|
||||||
OutPt *op = outRec->Pts->Prev;
|
OutPt *op = outRec.Pts->Prev;
|
||||||
for (int j = 0; j < cnt; j++)
|
for (int j = 0; j < cnt; j++)
|
||||||
{
|
{
|
||||||
pn->Contour.emplace_back(op->Pt);
|
pn->Contour.emplace_back(op->Pt);
|
||||||
@ -2836,18 +2812,18 @@ void Clipper::BuildResult2(PolyTree& polytree)
|
|||||||
|
|
||||||
//fixup PolyNode links etc ...
|
//fixup PolyNode links etc ...
|
||||||
polytree.Childs.reserve(m_PolyOuts.size());
|
polytree.Childs.reserve(m_PolyOuts.size());
|
||||||
for (OutRec* outRec : m_PolyOuts)
|
for (OutRec &outRec : m_PolyOuts)
|
||||||
{
|
{
|
||||||
if (!outRec->PolyNd) continue;
|
if (!outRec.PolyNd) continue;
|
||||||
if (outRec->IsOpen)
|
if (outRec.IsOpen)
|
||||||
{
|
{
|
||||||
outRec->PolyNd->m_IsOpen = true;
|
outRec.PolyNd->m_IsOpen = true;
|
||||||
polytree.AddChild(*outRec->PolyNd);
|
polytree.AddChild(*outRec.PolyNd);
|
||||||
}
|
}
|
||||||
else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd)
|
else if (outRec.FirstLeft && outRec.FirstLeft->PolyNd)
|
||||||
outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd);
|
outRec.FirstLeft->PolyNd->AddChild(*outRec.PolyNd);
|
||||||
else
|
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)!
|
// 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
|
//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;
|
if (!outRec.Pts || !outRec.FirstLeft) continue;
|
||||||
OutRec* firstLeft = outRec->FirstLeft;
|
OutRec* firstLeft = outRec.FirstLeft;
|
||||||
// Skip empty polygons.
|
// Skip empty polygons.
|
||||||
while (firstLeft && !firstLeft->Pts) firstLeft = firstLeft->FirstLeft;
|
while (firstLeft && !firstLeft->Pts) firstLeft = firstLeft->FirstLeft;
|
||||||
if (firstLeft == OldOutRec && Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts))
|
if (firstLeft == OldOutRec && Poly2ContainsPoly1(outRec.Pts, NewOutRec->Pts))
|
||||||
outRec->FirstLeft = NewOutRec;
|
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
|
//reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
|
||||||
for (OutRec *outRec : m_PolyOuts)
|
for (OutRec &outRec : m_PolyOuts)
|
||||||
if (outRec->FirstLeft == OldOutRec) outRec->FirstLeft = NewOutRec;
|
if (outRec.FirstLeft == OldOutRec) outRec.FirstLeft = NewOutRec;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -3253,13 +3229,13 @@ void Clipper::JoinCommonEdges()
|
|||||||
if (m_UsingPolyTree)
|
if (m_UsingPolyTree)
|
||||||
for (size_t j = 0; j < m_PolyOuts.size() - 1; j++)
|
for (size_t j = 0; j < m_PolyOuts.size() - 1; j++)
|
||||||
{
|
{
|
||||||
OutRec* oRec = m_PolyOuts[j];
|
OutRec &oRec = m_PolyOuts[j];
|
||||||
OutRec* firstLeft = oRec->FirstLeft;
|
OutRec* firstLeft = oRec.FirstLeft;
|
||||||
while (firstLeft && !firstLeft->Pts) firstLeft = firstLeft->FirstLeft;
|
while (firstLeft && !firstLeft->Pts) firstLeft = firstLeft->FirstLeft;
|
||||||
if (!oRec->Pts || firstLeft != outRec1 ||
|
if (!oRec.Pts || firstLeft != outRec1 ||
|
||||||
oRec->IsHole == outRec1->IsHole) continue;
|
oRec.IsHole == outRec1->IsHole) continue;
|
||||||
if (Poly2ContainsPoly1(oRec->Pts, join.OutPt2))
|
if (Poly2ContainsPoly1(oRec.Pts, join.OutPt2))
|
||||||
oRec->FirstLeft = outRec2;
|
oRec.FirstLeft = outRec2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts))
|
if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts))
|
||||||
@ -3771,13 +3747,13 @@ void Clipper::DoSimplePolygons()
|
|||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < m_PolyOuts.size())
|
while (i < m_PolyOuts.size())
|
||||||
{
|
{
|
||||||
OutRec* outrec = m_PolyOuts[i++];
|
OutRec &outrec = m_PolyOuts[i++];
|
||||||
OutPt* op = outrec->Pts;
|
OutPt* op = outrec.Pts;
|
||||||
if (!op || outrec->IsOpen) continue;
|
if (!op || outrec.IsOpen) continue;
|
||||||
do //for each Pt in Polygon until duplicate found do ...
|
do //for each Pt in Polygon until duplicate found do ...
|
||||||
{
|
{
|
||||||
OutPt* op2 = op->Next;
|
OutPt* op2 = op->Next;
|
||||||
while (op2 != outrec->Pts)
|
while (op2 != outrec.Pts)
|
||||||
{
|
{
|
||||||
if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op)
|
if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op)
|
||||||
{
|
{
|
||||||
@ -3789,37 +3765,37 @@ void Clipper::DoSimplePolygons()
|
|||||||
op2->Prev = op3;
|
op2->Prev = op3;
|
||||||
op3->Next = op2;
|
op3->Next = op2;
|
||||||
|
|
||||||
outrec->Pts = op;
|
outrec.Pts = op;
|
||||||
OutRec* outrec2 = CreateOutRec();
|
OutRec* outrec2 = CreateOutRec();
|
||||||
outrec2->Pts = op2;
|
outrec2->Pts = op2;
|
||||||
UpdateOutPtIdxs(*outrec2);
|
UpdateOutPtIdxs(*outrec2);
|
||||||
if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts))
|
if (Poly2ContainsPoly1(outrec2->Pts, outrec.Pts))
|
||||||
{
|
{
|
||||||
//OutRec2 is contained by OutRec1 ...
|
//OutRec2 is contained by OutRec1 ...
|
||||||
outrec2->IsHole = !outrec->IsHole;
|
outrec2->IsHole = !outrec.IsHole;
|
||||||
outrec2->FirstLeft = outrec;
|
outrec2->FirstLeft = &outrec;
|
||||||
// For each m_PolyOuts, replace FirstLeft from outRec2 to outrec.
|
// For each m_PolyOuts, replace FirstLeft from outRec2 to outrec.
|
||||||
if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec);
|
if (m_UsingPolyTree) FixupFirstLefts2(outrec2, &outrec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts))
|
if (Poly2ContainsPoly1(outrec.Pts, outrec2->Pts))
|
||||||
{
|
{
|
||||||
//OutRec1 is contained by OutRec2 ...
|
//OutRec1 is contained by OutRec2 ...
|
||||||
outrec2->IsHole = outrec->IsHole;
|
outrec2->IsHole = outrec.IsHole;
|
||||||
outrec->IsHole = !outrec2->IsHole;
|
outrec.IsHole = !outrec2->IsHole;
|
||||||
outrec2->FirstLeft = outrec->FirstLeft;
|
outrec2->FirstLeft = outrec.FirstLeft;
|
||||||
outrec->FirstLeft = outrec2;
|
outrec.FirstLeft = outrec2;
|
||||||
// For each m_PolyOuts, replace FirstLeft from outrec to outrec2.
|
// For each m_PolyOuts, replace FirstLeft from outrec to outrec2.
|
||||||
if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2);
|
if (m_UsingPolyTree) FixupFirstLefts2(&outrec, outrec2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//the 2 polygons are separate ...
|
//the 2 polygons are separate ...
|
||||||
outrec2->IsHole = outrec->IsHole;
|
outrec2->IsHole = outrec.IsHole;
|
||||||
outrec2->FirstLeft = outrec->FirstLeft;
|
outrec2->FirstLeft = outrec.FirstLeft;
|
||||||
// For each polygon of m_PolyOuts, replace FirstLeft from outrec to outrec2 if the polygon is inside outRec2.
|
// 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)!
|
//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
|
op2 = op; //ie get ready for the Next iteration
|
||||||
}
|
}
|
||||||
@ -3827,7 +3803,7 @@ void Clipper::DoSimplePolygons()
|
|||||||
}
|
}
|
||||||
op = op->Next;
|
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;
|
Clipper c;
|
||||||
c.StrictlySimple(true);
|
c.StrictlySimple(strictly_simple);
|
||||||
c.AddPath(in_poly, ptSubject, true);
|
c.AddPath(in_poly, ptSubject, true);
|
||||||
Paths out;
|
Paths out;
|
||||||
c.Execute(ctUnion, out, fillType, fillType);
|
c.Execute(ctUnion, out, fillType, fillType);
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
//use_deprecated: Enables temporary support for the obsolete functions
|
//use_deprecated: Enables temporary support for the obsolete functions
|
||||||
//#define use_deprecated
|
//#define use_deprecated
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@ -199,7 +200,8 @@ double Area(const Path &poly);
|
|||||||
inline bool Orientation(const Path &poly) { return Area(poly) >= 0; }
|
inline bool Orientation(const Path &poly) { return Area(poly) >= 0; }
|
||||||
int PointInPolygon(const IntPoint &pt, const Path &path);
|
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(const Path& in_poly, Path& out_poly, double distance = 1.415);
|
||||||
void CleanPolygon(Path& 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>>;
|
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 {
|
struct Join {
|
||||||
Join(OutPt *OutPt1, OutPt *OutPt2, IntPoint OffPt) :
|
Join(OutPt *OutPt1, OutPt *OutPt2, IntPoint OffPt) :
|
||||||
OutPt1(OutPt1), OutPt2(OutPt2), OffPt(OffPt) {}
|
OutPt1(OutPt1), OutPt2(OutPt2), OffPt(OffPt) {}
|
||||||
@ -432,12 +452,12 @@ protected:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
// Output polygons.
|
// 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.
|
// 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.
|
// List of free output points, to be used before taking a point from m_OutPts or allocating a new chunk.
|
||||||
OutPt *m_OutPtsFree;
|
OutPt *m_OutPtsFree;
|
||||||
size_t m_OutPtsChunkSize;
|
|
||||||
size_t m_OutPtsChunkLast;
|
size_t m_OutPtsChunkLast;
|
||||||
|
|
||||||
std::vector<Join, Allocator<Join>> m_Joins;
|
std::vector<Join, Allocator<Join>> m_Joins;
|
||||||
@ -482,7 +502,7 @@ private:
|
|||||||
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||||
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||||
OutRec* GetOutRec(int idx);
|
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);
|
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
|
||||||
OutRec* CreateOutRec();
|
OutRec* CreateOutRec();
|
||||||
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
|
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
|
||||||
@ -498,7 +518,7 @@ private:
|
|||||||
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
|
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
|
||||||
void BuildResult(Paths& polys);
|
void BuildResult(Paths& polys);
|
||||||
void BuildResult2(PolyTree& polytree);
|
void BuildResult2(PolyTree& polytree);
|
||||||
void SetHoleState(TEdge *e, OutRec *outrec) const;
|
void SetHoleState(TEdge *e, OutRec *outrec);
|
||||||
bool FixupIntersectionOrder();
|
bool FixupIntersectionOrder();
|
||||||
void FixupOutPolygon(OutRec &outrec);
|
void FixupOutPolygon(OutRec &outrec);
|
||||||
void FixupOutPolyline(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);
|
bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, const IntPoint &Pt, bool DiscardLeft);
|
||||||
void JoinCommonEdges();
|
void JoinCommonEdges();
|
||||||
void DoSimplePolygons();
|
void DoSimplePolygons();
|
||||||
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) const;
|
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
|
||||||
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) const;
|
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
|
||||||
#ifdef CLIPPERLIB_USE_XYZ
|
#ifdef CLIPPERLIB_USE_XYZ
|
||||||
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
|
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
|
||||||
#endif
|
#endif
|
||||||
@ -567,10 +587,11 @@ class clipperException : public std::exception
|
|||||||
};
|
};
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Union with "strictly simple" fix enabled.
|
||||||
template<typename PathsProvider>
|
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;
|
Clipper c;
|
||||||
c.StrictlySimple(true);
|
c.StrictlySimple(strictly_simple);
|
||||||
c.AddPaths(std::forward<PathsProvider>(in_polys), ptSubject, true);
|
c.AddPaths(std::forward<PathsProvider>(in_polys), ptSubject, true);
|
||||||
Paths out;
|
Paths out;
|
||||||
c.Execute(ctUnion, out, fillType, fillType);
|
c.Execute(ctUnion, out, fillType, fillType);
|
||||||
|
@ -232,7 +232,7 @@ std::unique_ptr<LocToLineGrid> cre
|
|||||||
void fixSelfIntersections(const coord_t epsilon, Polygons &thiss)
|
void fixSelfIntersections(const coord_t epsilon, Polygons &thiss)
|
||||||
{
|
{
|
||||||
if (epsilon < 1) {
|
if (epsilon < 1) {
|
||||||
ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(thiss));
|
ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(thiss), ClipperLib::pftEvenOdd);
|
||||||
return;
|
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;
|
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);
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
ClipperLib::Paths output;
|
ClipperLib::Paths output;
|
||||||
if (preserve_collinear) {
|
ClipperLib::Clipper c;
|
||||||
ClipperLib::Clipper c;
|
// c.PreserveCollinear(true);
|
||||||
c.PreserveCollinear(true);
|
//FIXME StrictlySimple is very expensive! Is it needed?
|
||||||
c.StrictlySimple(true);
|
c.StrictlySimple(true);
|
||||||
c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true);
|
c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true);
|
||||||
c.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
c.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||||
} else {
|
|
||||||
output = ClipperLib::SimplifyPolygons(ClipperUtils::PolygonsProvider(subject), ClipperLib::pftNonZero);
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert into Slic3r polygons
|
// convert into Slic3r polygons
|
||||||
return to_polygons(std::move(output));
|
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);
|
CLIPPER_UTILS_TIME_LIMIT_MILLIS(CLIPPER_UTILS_TIME_LIMIT_DEFAULT);
|
||||||
|
|
||||||
if (! preserve_collinear)
|
|
||||||
return union_ex(simplify_polygons(subject, false));
|
|
||||||
|
|
||||||
ClipperLib::PolyTree polytree;
|
ClipperLib::PolyTree polytree;
|
||||||
ClipperLib::Clipper c;
|
ClipperLib::Clipper c;
|
||||||
c.PreserveCollinear(true);
|
// c.PreserveCollinear(true);
|
||||||
|
//FIXME StrictlySimple is very expensive! Is it needed?
|
||||||
c.StrictlySimple(true);
|
c.StrictlySimple(true);
|
||||||
c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true);
|
c.AddPaths(ClipperUtils::PolygonsProvider(subject), ClipperLib::ptSubject, true);
|
||||||
c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||||
|
@ -596,8 +596,8 @@ void traverse_pt(const ClipperLib::PolyNodes &nodes, ExOrJustPolygons *retval)
|
|||||||
|
|
||||||
|
|
||||||
/* OTHER */
|
/* OTHER */
|
||||||
Slic3r::Polygons simplify_polygons(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, bool preserve_collinear = false);
|
Slic3r::ExPolygons simplify_polygons_ex(const Slic3r::Polygons &subject);
|
||||||
|
|
||||||
Polygons top_level_islands(const Slic3r::Polygons &polygons);
|
Polygons top_level_islands(const Slic3r::Polygons &polygons);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user