Upgrade Clipper to 6.2.1

This commit is contained in:
Alessandro Ranellucci 2014-11-08 12:05:27 +01:00
parent 67f1cdf76f
commit a78be203aa
2 changed files with 250 additions and 264 deletions

View file

@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.1.5 *
* Date : 22 May 2014 *
* Version : 6.2.1 *
* Date : 31 October 2014 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2014 *
* *
@ -90,11 +90,10 @@ struct IntersectNode {
IntPoint Pt;
};
struct LocalMinima {
struct LocalMinimum {
cInt Y;
TEdge *LeftBound;
TEdge *RightBound;
LocalMinima *Next;
};
struct OutPt;
@ -122,6 +121,14 @@ struct Join {
IntPoint OffPt;
};
struct LocMinSorter
{
inline bool operator()(const LocalMinimum& locMin1, const LocalMinimum& locMin2)
{
return locMin2.Y < locMin1.Y;
}
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
@ -161,7 +168,10 @@ PolyNode* PolyTree::GetFirst() const
int PolyTree::Total() const
{
return (int)AllNodes.size();
int result = (int)AllNodes.size();
//with negative offsets, ignore the hidden outer polygon ...
if (result > 0 && Childs[0] != AllNodes[0]) result--;
return result;
}
//------------------------------------------------------------------------------
@ -320,9 +330,21 @@ class Int128
Int128 operator-() const //unary negation
{
if (lo == 0)
return Int128(-hi,0);
else
return Int128(~hi,~lo +1);
return Int128(-hi, 0);
else
return Int128(~hi, ~lo + 1);
}
operator double() const
{
const double shift64 = 18446744073709551616.0; //2^64
if (hi < 0)
{
if (lo == 0) return (double)hi * shift64;
else return -(double)(~lo + ~hi * shift64);
}
else
return (double)(lo + hi * shift64);
}
};
@ -506,8 +528,9 @@ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
OutPt* op = OutPt1;
do
{
//nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
int res = PointInPolygon(op->Pt, OutPt2);
if (res >= 0) return res != 0;
if (res >= 0) return res > 0;
op = op->Next;
}
while (op != OutPt1);
@ -854,8 +877,7 @@ bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
ClipperBase::ClipperBase() //constructor
{
m_MinimaList = 0;
m_CurrentLM = 0;
m_CurrentLM = m_MinimaList.begin(); //begin() == end() here
m_UseFullRange = false;
}
//------------------------------------------------------------------------------
@ -898,124 +920,129 @@ TEdge* FindNextLocMin(TEdge* E)
}
//------------------------------------------------------------------------------
TEdge* ClipperBase::ProcessBound(TEdge* E, bool IsClockwise)
TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
{
TEdge *EStart = E, *Result = E;
TEdge *Result = E;
TEdge *Horz = 0;
cInt StartX;
if (IsHorizontal(*E))
{
//first we need to be careful here with open paths because this
//may not be a true local minima (ie may be following a skip edge).
//also, watch for adjacent horz edges to start heading left
//before finishing right ...
if (IsClockwise)
{
if (E->Prev->Bot.Y == E->Bot.Y) StartX = E->Prev->Bot.X;
else StartX = E->Prev->Top.X;
}
else
{
if (E->Next->Bot.Y == E->Bot.Y) StartX = E->Next->Bot.X;
else StartX = E->Next->Top.X;
}
if (E->Bot.X != StartX) ReverseHorizontal(*E);
}
if (Result->OutIdx != Skip)
{
if (IsClockwise)
{
while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip)
Result = Result->Next;
if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
{
//nb: at the top of a bound, horizontals are added to the bound
//only when the preceding edge attaches to the horizontal's left vertex
//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)
{
if (!IsClockwise) Result = Horz->Prev;
}
else 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 = E->Next;
}
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)
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)
{
if (!IsClockwise) Result = Horz->Next;
}
else if (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)
ReverseHorizontal(*E);
E = E->Prev;
}
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
}
}
if (Result->OutIdx == Skip)
if (E->OutIdx == Skip)
{
//if edges still remain in the current bound beyond the skip edge then
//create another LocMin and call ProcessBound once more
E = Result;
if (IsClockwise)
if (NextIsForward)
{
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
}
else
{
while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev;
while (E != Result && IsHorizontal(*E)) E = E->Next;
}
if (E == Result)
{
if (IsClockwise) Result = E->Next;
if (NextIsForward) Result = E->Next;
else Result = E->Prev;
} else
}
else
{
//there are more edges in the bound beyond result starting with E
if (IsClockwise)
E = Result->Next;
if (NextIsForward)
E = Result->Next;
else
E = Result->Prev;
LocalMinima* locMin = new LocalMinima;
locMin->Next = 0;
locMin->Y = E->Bot.Y;
locMin->LeftBound = 0;
locMin->RightBound = E;
locMin->RightBound->WindDelta = 0;
Result = ProcessBound(locMin->RightBound, IsClockwise);
InsertLocalMinima(locMin);
MinimaList::value_type locMin;
locMin.Y = E->Bot.Y;
locMin.LeftBound = 0;
locMin.RightBound = E;
E->WindDelta = 0;
Result = ProcessBound(E, NextIsForward);
m_MinimaList.push_back(locMin);
}
return Result;
}
TEdge *EStart;
if (IsHorizontal(*E))
{
//We need to be careful with open paths because this may not be a
//true local minima (ie E may be following a skip edge).
//Also, consecutive horz. edges may start heading left before going right.
if (NextIsForward)
EStart = E->Prev;
else
EStart = E->Next;
if (EStart->OutIdx != Skip)
{
if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge
{
if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X)
ReverseHorizontal(*E);
}
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)
Result = Result->Next;
if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
{
//nb: at the top of a bound, horizontals are added to the bound
//only when the preceding edge attaches to the horizontal's left vertex
//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)
{
if (!NextIsForward) Result = Horz->Prev;
}
else 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 = E->Next;
}
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)
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)
{
if (!NextIsForward) Result = Horz->Next;
}
else if (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)
ReverseHorizontal(*E);
E = E->Prev;
}
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
}
return Result;
}
//------------------------------------------------------------------------------
@ -1129,26 +1156,25 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
}
E->Prev->OutIdx = Skip;
if (E->Prev->Bot.X < E->Prev->Top.X) ReverseHorizontal(*E->Prev);
LocalMinima* locMin = new LocalMinima();
locMin->Next = 0;
locMin->Y = E->Bot.Y;
locMin->LeftBound = 0;
locMin->RightBound = E;
locMin->RightBound->Side = esRight;
locMin->RightBound->WindDelta = 0;
MinimaList::value_type locMin;
locMin.Y = E->Bot.Y;
locMin.LeftBound = 0;
locMin.RightBound = E;
locMin.RightBound->Side = esRight;
locMin.RightBound->WindDelta = 0;
while (E->Next->OutIdx != Skip)
{
E->NextInLML = E->Next;
if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
E = E->Next;
}
InsertLocalMinima(locMin);
m_MinimaList.push_back(locMin);
m_edges.push_back(edges);
return true;
}
m_edges.push_back(edges);
bool clockwise;
bool leftBoundIsForward;
TEdge* EMin = 0;
//workaround to avoid an endless loop in the while loop below when
@ -1163,38 +1189,40 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
//E and E.Prev now share a local minima (left aligned if horizontal).
//Compare their slopes to find which starts which bound ...
LocalMinima* locMin = new LocalMinima;
locMin->Next = 0;
locMin->Y = E->Bot.Y;
MinimaList::value_type locMin;
locMin.Y = E->Bot.Y;
if (E->Dx < E->Prev->Dx)
{
locMin->LeftBound = E->Prev;
locMin->RightBound = E;
clockwise = false; //Q.nextInLML = Q.prev
locMin.LeftBound = E->Prev;
locMin.RightBound = E;
leftBoundIsForward = false; //Q.nextInLML = Q.prev
} else
{
locMin->LeftBound = E;
locMin->RightBound = E->Prev;
clockwise = true; //Q.nextInLML = Q.next
locMin.LeftBound = E;
locMin.RightBound = E->Prev;
leftBoundIsForward = true; //Q.nextInLML = Q.next
}
locMin->LeftBound->Side = esLeft;
locMin->RightBound->Side = esRight;
locMin.LeftBound->Side = esLeft;
locMin.RightBound->Side = esRight;
if (!Closed) locMin->LeftBound->WindDelta = 0;
else if (locMin->LeftBound->Next == locMin->RightBound)
locMin->LeftBound->WindDelta = -1;
else locMin->LeftBound->WindDelta = 1;
locMin->RightBound->WindDelta = -locMin->LeftBound->WindDelta;
if (!Closed) locMin.LeftBound->WindDelta = 0;
else if (locMin.LeftBound->Next == locMin.RightBound)
locMin.LeftBound->WindDelta = -1;
else locMin.LeftBound->WindDelta = 1;
locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta;
E = ProcessBound(locMin->LeftBound, clockwise);
TEdge* E2 = ProcessBound(locMin->RightBound, !clockwise);
E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward);
if (locMin->LeftBound->OutIdx == Skip)
locMin->LeftBound = 0;
else if (locMin->RightBound->OutIdx == Skip)
locMin->RightBound = 0;
InsertLocalMinima(locMin);
if (!clockwise) E = E2;
TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward);
if (locMin.LeftBound->OutIdx == Skip)
locMin.LeftBound = 0;
else if (locMin.RightBound->OutIdx == Skip)
locMin.RightBound = 0;
m_MinimaList.push_back(locMin);
if (!leftBoundIsForward) E = E2;
}
return true;
}
@ -1209,27 +1237,6 @@ bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed)
}
//------------------------------------------------------------------------------
void ClipperBase::InsertLocalMinima(LocalMinima *newLm)
{
if( ! m_MinimaList )
{
m_MinimaList = newLm;
}
else if( newLm->Y >= m_MinimaList->Y )
{
newLm->Next = m_MinimaList;
m_MinimaList = newLm;
} else
{
LocalMinima* tmpLm = m_MinimaList;
while( tmpLm->Next && ( newLm->Y < tmpLm->Next->Y ) )
tmpLm = tmpLm->Next;
newLm->Next = tmpLm->Next;
tmpLm->Next = newLm;
}
}
//------------------------------------------------------------------------------
void ClipperBase::Clear()
{
DisposeLocalMinimaList();
@ -1248,12 +1255,12 @@ void ClipperBase::Clear()
void ClipperBase::Reset()
{
m_CurrentLM = m_MinimaList;
if( !m_CurrentLM ) return; //ie nothing to process
m_CurrentLM = m_MinimaList.begin();
if (m_CurrentLM == m_MinimaList.end()) return; //ie nothing to process
std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter());
//reset all edges ...
LocalMinima* lm = m_MinimaList;
while( lm )
for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm)
{
TEdge* e = lm->LeftBound;
if (e)
@ -1270,35 +1277,29 @@ void ClipperBase::Reset()
e->Side = esRight;
e->OutIdx = Unassigned;
}
lm = lm->Next;
}
}
//------------------------------------------------------------------------------
void ClipperBase::DisposeLocalMinimaList()
{
while( m_MinimaList )
{
LocalMinima* tmpLm = m_MinimaList->Next;
delete m_MinimaList;
m_MinimaList = tmpLm;
}
m_CurrentLM = 0;
m_MinimaList.clear();
m_CurrentLM = m_MinimaList.begin();
}
//------------------------------------------------------------------------------
void ClipperBase::PopLocalMinima()
{
if( ! m_CurrentLM ) return;
m_CurrentLM = m_CurrentLM->Next;
if (m_CurrentLM == m_MinimaList.end()) return;
++m_CurrentLM;
}
//------------------------------------------------------------------------------
IntRect ClipperBase::GetBounds()
{
IntRect result;
LocalMinima* lm = m_MinimaList;
if (!lm)
MinimaList::iterator lm = m_MinimaList.begin();
if (lm == m_MinimaList.end())
{
result.left = result.top = result.right = result.bottom = 0;
return result;
@ -1307,10 +1308,9 @@ IntRect ClipperBase::GetBounds()
result.top = lm->LeftBound->Bot.Y;
result.right = lm->LeftBound->Bot.X;
result.bottom = lm->LeftBound->Bot.Y;
while (lm)
while (lm != m_MinimaList.end())
{
if (lm->LeftBound->Bot.Y > result.bottom)
result.bottom = lm->LeftBound->Bot.Y;
result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y);
TEdge* e = lm->LeftBound;
for (;;) {
TEdge* bottomE = e;
@ -1320,16 +1320,15 @@ IntRect ClipperBase::GetBounds()
if (e->Bot.X > result.right) result.right = e->Bot.X;
e = 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->Top.X < result.left) result.left = e->Top.X;
if (e->Top.X > result.right) result.right = e->Top.X;
if (e->Top.Y < result.top) 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;
}
lm = lm->Next;
++lm;
}
return result;
}
@ -1357,12 +1356,11 @@ Clipper::Clipper(int initOptions) : ClipperBase() //constructor
Clipper::~Clipper() //destructor
{
Clear();
m_Scanbeam.clear();
}
//------------------------------------------------------------------------------
#ifdef use_xyz
void Clipper::ZFillFunction(TZFillCallback zFillFunc)
void Clipper::ZFillFunction(ZFillCallback zFillFunc)
{
m_ZFill = zFillFunc;
}
@ -1372,15 +1370,11 @@ void Clipper::ZFillFunction(TZFillCallback zFillFunc)
void Clipper::Reset()
{
ClipperBase::Reset();
m_Scanbeam.clear();
m_Scanbeam = ScanbeamList();
m_ActiveEdges = 0;
m_SortedEdges = 0;
LocalMinima* lm = m_MinimaList;
while (lm)
{
for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm)
InsertScanbeam(lm->Y);
lm = lm->Next;
}
}
//------------------------------------------------------------------------------
@ -1441,7 +1435,7 @@ bool Clipper::ExecuteInternal()
bool succeeded = true;
try {
Reset();
if (!m_CurrentLM) return false;
if (m_CurrentLM == m_MinimaList.end()) return true;
cInt botY = PopScanbeam();
do {
InsertLocalMinimaIntoAEL(botY);
@ -1449,11 +1443,11 @@ bool Clipper::ExecuteInternal()
ProcessHorizontals(false);
if (m_Scanbeam.empty()) break;
cInt topY = PopScanbeam();
succeeded = ProcessIntersections(botY, topY);
succeeded = ProcessIntersections(topY);
if (!succeeded) break;
ProcessEdgesAtTopOfScanbeam(topY);
botY = topY;
} while (!m_Scanbeam.empty() || m_CurrentLM);
} while (!m_Scanbeam.empty() || m_CurrentLM != m_MinimaList.end());
}
catch(...)
{
@ -1492,14 +1486,16 @@ bool Clipper::ExecuteInternal()
void Clipper::InsertScanbeam(const cInt Y)
{
m_Scanbeam.insert(Y);
//if (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) return;// avoid duplicates.
m_Scanbeam.push(Y);
}
//------------------------------------------------------------------------------
cInt Clipper::PopScanbeam()
{
cInt Y = *m_Scanbeam.begin();
m_Scanbeam.erase(m_Scanbeam.begin());
const cInt Y = m_Scanbeam.top();
m_Scanbeam.pop();
while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates.
return Y;
}
//------------------------------------------------------------------------------
@ -1858,7 +1854,7 @@ void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt)
void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
{
while( m_CurrentLM && ( m_CurrentLM->Y == botY ) )
while (m_CurrentLM != m_MinimaList.end() && (m_CurrentLM->Y == botY))
{
TEdge* lb = m_CurrentLM->LeftBound;
TEdge* rb = m_CurrentLM->RightBound;
@ -2712,11 +2708,11 @@ void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
}
//------------------------------------------------------------------------------
bool Clipper::ProcessIntersections(const cInt botY, const cInt topY)
bool Clipper::ProcessIntersections(const cInt topY)
{
if( !m_ActiveEdges ) return true;
try {
BuildIntersectList(botY, topY);
BuildIntersectList(topY);
size_t IlSize = m_IntersectList.size();
if (IlSize == 0) return true;
if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList();
@ -2741,7 +2737,7 @@ void Clipper::DisposeIntersectNodes()
}
//------------------------------------------------------------------------------
void Clipper::BuildIntersectList(const cInt botY, const cInt topY)
void Clipper::BuildIntersectList(const cInt topY)
{
if ( !m_ActiveEdges ) return;
@ -3466,13 +3462,23 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
}
//----------------------------------------------------------------------
static OutRec* ParseFirstLeft(OutRec* FirstLeft)
{
while (FirstLeft && !FirstLeft->Pts)
FirstLeft = FirstLeft->FirstLeft;
return FirstLeft;
}
//------------------------------------------------------------------------------
void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
{
//tests if NewOutRec contains the polygon before reassigning FirstLeft
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec* outRec = m_PolyOuts[i];
if (outRec->Pts && outRec->FirstLeft == OldOutRec)
if (!outRec->Pts || !outRec->FirstLeft) continue;
OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
if (firstLeft == OldOutRec)
{
if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts))
outRec->FirstLeft = NewOutRec;
@ -3483,6 +3489,7 @@ void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec)
{
//reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec* outRec = m_PolyOuts[i];
@ -3491,14 +3498,6 @@ void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec)
}
//----------------------------------------------------------------------
static OutRec* ParseFirstLeft(OutRec* FirstLeft)
{
while (FirstLeft && !FirstLeft->Pts)
FirstLeft = FirstLeft->FirstLeft;
return FirstLeft;
}
//------------------------------------------------------------------------------
void Clipper::JoinCommonEdges()
{
for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
@ -3782,6 +3781,7 @@ void ClipperOffset::Execute(PolyTree& solution, double delta)
PolyNode* outerNode = solution.Childs[0];
solution.Childs.reserve(outerNode->ChildCount());
solution.Childs[0] = outerNode->Childs[0];
solution.Childs[0]->Parent = outerNode->Parent;
for (int i = 1; i < outerNode->ChildCount(); ++i)
solution.AddChild(*outerNode->Childs[i]);
}
@ -4033,7 +4033,7 @@ 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);
int steps = (int)Round(m_StepsPerRad * std::fabs(a));
int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1);
double X = m_normals[k].X, Y = m_normals[k].Y, X2;
for (int i = 0; i < steps; ++i)
@ -4061,7 +4061,7 @@ void Clipper::DoSimplePolygons()
{
OutRec* outrec = m_PolyOuts[i++];
OutPt* op = outrec->Pts;
if (!op) continue;
if (!op || outrec->IsOpen) continue;
do //for each Pt in Polygon until duplicate found do ...
{
OutPt* op2 = op->Next;
@ -4086,6 +4086,7 @@ void Clipper::DoSimplePolygons()
//OutRec2 is contained by OutRec1 ...
outrec2->IsHole = !outrec->IsHole;
outrec2->FirstLeft = outrec;
if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec);
}
else
if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts))
@ -4095,12 +4096,15 @@ void Clipper::DoSimplePolygons()
outrec->IsHole = !outrec2->IsHole;
outrec2->FirstLeft = outrec->FirstLeft;
outrec->FirstLeft = outrec2;
} else
if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2);
}
else
{
//the 2 polygons are separate ...
outrec2->IsHole = outrec->IsHole;
outrec2->FirstLeft = outrec->FirstLeft;
}
if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2);
}
op2 = op; //ie get ready for the Next iteration
}
op2 = op2->Next;
@ -4180,7 +4184,7 @@ 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 (Abs(pt1.X - pt2.X) > Abs(pt1.Y - pt2.Y))
{
if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
@ -4390,7 +4394,7 @@ void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution)
enum NodeType {ntAny, ntOpen, ntClosed};
void AddPolyNodeToPolygons(const PolyNode& polynode, NodeType nodetype, Paths& paths)
void AddPolyNodeToPaths(const PolyNode& polynode, NodeType nodetype, Paths& paths)
{
bool match = true;
if (nodetype == ntClosed) match = !polynode.IsOpen();
@ -4399,7 +4403,7 @@ void AddPolyNodeToPolygons(const PolyNode& polynode, NodeType nodetype, Paths& p
if (!polynode.Contour.empty() && match)
paths.push_back(polynode.Contour);
for (int i = 0; i < polynode.ChildCount(); ++i)
AddPolyNodeToPolygons(*polynode.Childs[i], nodetype, paths);
AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths);
}
//------------------------------------------------------------------------------
@ -4407,7 +4411,7 @@ void PolyTreeToPaths(const PolyTree& polytree, Paths& paths)
{
paths.resize(0);
paths.reserve(polytree.Total());
AddPolyNodeToPolygons(polytree, ntAny, paths);
AddPolyNodeToPaths(polytree, ntAny, paths);
}
//------------------------------------------------------------------------------
@ -4415,7 +4419,7 @@ void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths)
{
paths.resize(0);
paths.reserve(polytree.Total());
AddPolyNodeToPolygons(polytree, ntClosed, paths);
AddPolyNodeToPaths(polytree, ntClosed, paths);
}
//------------------------------------------------------------------------------
@ -4457,18 +4461,4 @@ std::ostream& operator <<(std::ostream &s, const Paths &p)
}
//------------------------------------------------------------------------------
#ifdef use_deprecated
void OffsetPaths(const Paths &in_polys, Paths &out_polys,
double delta, JoinType jointype, EndType_ endtype, double limit)
{
ClipperOffset co(limit, limit);
co.AddPaths(in_polys, jointype, (EndType)endtype);
co.Execute(out_polys, delta);
}
//------------------------------------------------------------------------------
#endif
} //ClipperLib namespace

View file

@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.1.5 *
* Date : 22 May 2014 *
* Version : 6.2.1 *
* Date : 31 October 2014 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2014 *
* *
@ -34,7 +34,7 @@
#ifndef clipper_hpp
#define clipper_hpp
#define CLIPPER_VERSION "6.1.5"
#define CLIPPER_VERSION "6.2.0"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
@ -46,8 +46,7 @@
//use_lines: Enables line clipping. Adds a very minor cost to performance.
#define use_lines
//use_deprecated: Enables support for the obsolete OffsetPaths() function
//which has been replace with the ClipperOffset class.
//use_deprecated: Enables temporary support for the obsolete functions
//#define use_deprecated
#include <vector>
@ -57,6 +56,7 @@
#include <cstdlib>
#include <ostream>
#include <functional>
#include <queue>
namespace ClipperLib {
@ -70,14 +70,15 @@ enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
#ifdef use_int32
typedef int cInt;
static cInt const loRange = 46340;
static cInt const hiRange = 46340;
static cInt const loRange = 0x7FFF;
static cInt const hiRange = 0x7FFF;
#else
typedef signed long long cInt;
typedef signed long long long64; //used by Int128 class
typedef unsigned long long ulong64;
static cInt const loRange = 0x3FFFFFFF;
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
typedef signed long long long64; //used by Int128 class
typedef unsigned long long ulong64;
#endif
struct IntPoint {
@ -121,15 +122,12 @@ struct DoublePoint
//------------------------------------------------------------------------------
#ifdef use_xyz
typedef void (*TZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
#endif
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
enum JoinType {jtSquare, jtRound, jtMiter};
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
#ifdef use_deprecated
enum EndType_ {etClosed, etButt = 2, etSquare, etRound};
#endif
class PolyNode;
typedef std::vector< PolyNode* > PolyNodes;
@ -138,6 +136,7 @@ class PolyNode
{
public:
PolyNode();
virtual ~PolyNode(){};
Path Contour;
PolyNodes Childs;
PolyNode* Parent;
@ -172,11 +171,6 @@ bool Orientation(const Path &poly);
double Area(const Path &poly);
int PointInPolygon(const IntPoint &pt, const Path &path);
#ifdef use_deprecated
void OffsetPaths(const Paths &in_polys, Paths &out_polys,
double delta, JoinType jointype, EndType_ endtype, double limit = 0);
#endif
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
@ -205,7 +199,7 @@ enum EdgeSide { esLeft = 1, esRight = 2};
//forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
struct LocalMinima;
struct LocalMinimum;
struct Scanbeam;
struct OutPt;
struct OutRec;
@ -216,7 +210,6 @@ typedef std::vector < TEdge* > EdgeList;
typedef std::vector < Join* > JoinList;
typedef std::vector < IntersectNode* > IntersectList;
//------------------------------------------------------------------------------
//ClipperBase is the ancestor to the Clipper class. It should not be
@ -239,12 +232,14 @@ protected:
void PopLocalMinima();
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
void InsertLocalMinima(LocalMinima *newLm);
void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed);
TEdge* DescendToMin(TEdge *&E);
void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
LocalMinima *m_CurrentLM;
LocalMinima *m_MinimaList;
typedef std::vector<LocalMinimum> MinimaList;
MinimaList::iterator m_CurrentLM;
MinimaList m_MinimaList;
bool m_UseFullRange;
EdgeList m_edges;
bool m_PreserveCollinear;
@ -271,7 +266,7 @@ public:
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
void ZFillFunction(TZFillCallback zFillFunc);
void ZFillFunction(ZFillCallback zFillFunc);
#endif
protected:
void Reset();
@ -282,7 +277,8 @@ private:
JoinList m_GhostJoins;
IntersectList m_IntersectList;
ClipType m_ClipType;
std::set< cInt, std::greater<cInt> > m_Scanbeam;
typedef std::priority_queue<cInt> ScanbeamList;
ScanbeamList m_Scanbeam;
TEdge *m_ActiveEdges;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
@ -292,7 +288,7 @@ private:
bool m_UsingPolyTree;
bool m_StrictSimple;
#ifdef use_xyz
TZFillCallback m_ZFill; //custom callback
ZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
@ -322,8 +318,8 @@ private:
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
void DisposeAllOutRecs();
void DisposeOutRec(PolyOutList::size_type index);
bool ProcessIntersections(const cInt botY, const cInt topY);
void BuildIntersectList(const cInt botY, const cInt topY);
bool ProcessIntersections(const cInt topY);
void BuildIntersectList(const cInt topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);