This commit is contained in:
Eric Fischer 2016-02-17 13:10:13 -08:00
parent 51fffb7710
commit 0f5a32b442
2 changed files with 327 additions and 275 deletions

View File

@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.2.9 *
* Date : 16 February 2015 *
* Version : 6.4.0 *
* Date : 2 July 2015 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2015 *
* *
@ -66,12 +66,11 @@ static int const Skip = -2; //edge that would otherwise close a path
struct TEdge {
IntPoint Bot;
IntPoint Curr;
IntPoint Curr; //current (updated for every new scanbeam)
IntPoint Top;
IntPoint Delta;
double Dx;
PolyType PolyTyp;
EdgeSide Side;
EdgeSide Side; //side only refers to current side of solution poly
int WindDelta; //1 or -1 depending on winding direction
int WindCnt;
int WindCnt2; //winding count of the opposite polytype
@ -99,6 +98,8 @@ struct LocalMinimum {
struct OutPt;
//OutRec: contains a path in the clipping solution. Edges in the AEL will
//carry a pointer to an OutRec when they are part of the clipping solution.
struct OutRec {
int Idx;
bool IsHole;
@ -403,19 +404,25 @@ double Area(const Path &poly)
}
//------------------------------------------------------------------------------
double Area(const OutRec &outRec)
double Area(const OutPt *op)
{
OutPt *op = outRec.Pts;
const OutPt *startOp = op;
if (!op) return 0;
double a = 0;
do {
a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y);
op = op->Next;
} while (op != outRec.Pts);
} while (op != startOp);
return a * 0.5;
}
//------------------------------------------------------------------------------
double Area(const OutRec &outRec)
{
return Area(outRec.Pts);
}
//------------------------------------------------------------------------------
bool PointIsVertex(const IntPoint &Pt, OutPt *pp)
{
OutPt *pp2 = pp;
@ -536,10 +543,12 @@ bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
{
#ifndef use_int32
if (UseFullInt64Range)
return Int128Mul(e1.Delta.Y, e2.Delta.X) == Int128Mul(e1.Delta.X, e2.Delta.Y);
return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) ==
Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y);
else
#endif
return e1.Delta.Y * e2.Delta.X == e1.Delta.X * e2.Delta.Y;
return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) ==
(e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y);
}
//------------------------------------------------------------------------------
@ -569,7 +578,7 @@ bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
inline bool IsHorizontal(TEdge &e)
{
return e.Delta.Y == 0;
return e.Dx == HORIZONTAL;
}
//------------------------------------------------------------------------------
@ -582,11 +591,9 @@ inline double GetDx(const IntPoint pt1, const IntPoint pt2)
inline void SetDx(TEdge &e)
{
e.Delta.X = (e.Top.X - e.Bot.X);
e.Delta.Y = (e.Top.Y - e.Bot.Y);
if (e.Delta.Y == 0) e.Dx = HORIZONTAL;
else e.Dx = (double)(e.Delta.X) / e.Delta.Y;
cInt dy = (e.Top.Y - e.Bot.Y);
if (dy == 0) e.Dx = HORIZONTAL;
else e.Dx = (double)(e.Top.X - e.Bot.X) / dy;
}
//---------------------------------------------------------------------------
@ -626,7 +633,7 @@ void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
ip.X = TopX(Edge1, ip.Y);
return;
}
else if (Edge1.Delta.X == 0)
else if (Edge1.Dx == 0)
{
ip.X = Edge1.Bot.X;
if (IsHorizontal(Edge2))
@ -637,7 +644,7 @@ void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
ip.Y = Round(ip.X / Edge2.Dx + b2);
}
}
else if (Edge2.Delta.X == 0)
else if (Edge2.Dx == 0)
{
ip.X = Edge2.Bot.X;
if (IsHorizontal(Edge1))
@ -804,7 +811,12 @@ bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2)
p = btmPt2->Next;
while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next;
double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt));
return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) &&
std::min(dx1p, dx1n) == std::min(dx2p, dx2n))
return Area(btmPt1) > 0; //if otherwise identical use orientation
else
return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
}
//------------------------------------------------------------------------------
@ -1191,8 +1203,6 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
locMin.RightBound = E->Prev;
leftBoundIsForward = true; //Q.nextInLML = Q.next
}
locMin.LeftBound->Side = esLeft;
locMin.RightBound->Side = esRight;
if (!Closed) locMin.LeftBound->WindDelta = 0;
else if (locMin.LeftBound->Next == locMin.RightBound)
@ -1231,8 +1241,6 @@ void ClipperBase::Clear()
DisposeLocalMinimaList();
for (EdgeList::size_type i = 0; i < m_edges.size(); ++i)
{
//for each edge array in turn, find the first used edge and
//check for and remove any hiddenPts in each edge in the array.
TEdge* edges = m_edges[i];
delete [] edges;
}
@ -1248,9 +1256,11 @@ void ClipperBase::Reset()
if (m_CurrentLM == m_MinimaList.end()) return; //ie nothing to process
std::stable_sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter());
m_Scanbeam = ScanbeamList(); //clears/resets priority_queue
//reset all edges ...
for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm)
{
InsertScanbeam(lm->Y);
TEdge* e = lm->LeftBound;
if (e)
{
@ -1267,6 +1277,8 @@ void ClipperBase::Reset()
e->OutIdx = Unassigned;
}
}
m_ActiveEdges = 0;
m_CurrentLM = m_MinimaList.begin();
}
//------------------------------------------------------------------------------
@ -1277,10 +1289,12 @@ void ClipperBase::DisposeLocalMinimaList()
}
//------------------------------------------------------------------------------
void ClipperBase::PopLocalMinima()
bool ClipperBase::PopLocalMinima(cInt Y, const LocalMinimum *&locMin)
{
if (m_CurrentLM == m_MinimaList.end()) return;
if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y) return false;
locMin = &(*m_CurrentLM);
++m_CurrentLM;
return true;
}
//------------------------------------------------------------------------------
@ -1299,6 +1313,7 @@ IntRect ClipperBase::GetBounds()
result.bottom = lm->LeftBound->Bot.Y;
while (lm != m_MinimaList.end())
{
//todo - needs fixing for open paths
result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y);
TEdge* e = lm->LeftBound;
for (;;) {
@ -1321,6 +1336,142 @@ IntRect ClipperBase::GetBounds()
}
return result;
}
//------------------------------------------------------------------------------
void ClipperBase::InsertScanbeam(const cInt Y)
{
m_Scanbeam.push(Y);
}
//------------------------------------------------------------------------------
bool ClipperBase::PopScanbeam(cInt &Y)
{
if (m_Scanbeam.empty()) return false;
Y = m_Scanbeam.top();
m_Scanbeam.pop();
while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates.
return true;
}
//------------------------------------------------------------------------------
void ClipperBase::DisposeAllOutRecs(){
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
DisposeOutRec(i);
m_PolyOuts.clear();
}
//------------------------------------------------------------------------------
void ClipperBase::DisposeOutRec(PolyOutList::size_type index)
{
OutRec *outRec = m_PolyOuts[index];
if (outRec->Pts) DisposeOutPts(outRec->Pts);
delete outRec;
m_PolyOuts[index] = 0;
}
//------------------------------------------------------------------------------
void ClipperBase::DeleteFromAEL(TEdge *e)
{
TEdge* AelPrev = e->PrevInAEL;
TEdge* AelNext = e->NextInAEL;
if (!AelPrev && !AelNext && (e != m_ActiveEdges)) return; //already deleted
if (AelPrev) AelPrev->NextInAEL = AelNext;
else m_ActiveEdges = AelNext;
if (AelNext) AelNext->PrevInAEL = AelPrev;
e->NextInAEL = 0;
e->PrevInAEL = 0;
}
//------------------------------------------------------------------------------
OutRec* ClipperBase::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;
}
//------------------------------------------------------------------------------
void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2)
{
//check that one or other edge hasn't already been removed from AEL ...
if (Edge1->NextInAEL == Edge1->PrevInAEL ||
Edge2->NextInAEL == Edge2->PrevInAEL) return;
if (Edge1->NextInAEL == Edge2)
{
TEdge* Next = Edge2->NextInAEL;
if (Next) Next->PrevInAEL = Edge1;
TEdge* Prev = Edge1->PrevInAEL;
if (Prev) Prev->NextInAEL = Edge2;
Edge2->PrevInAEL = Prev;
Edge2->NextInAEL = Edge1;
Edge1->PrevInAEL = Edge2;
Edge1->NextInAEL = Next;
}
else if (Edge2->NextInAEL == Edge1)
{
TEdge* Next = Edge1->NextInAEL;
if (Next) Next->PrevInAEL = Edge2;
TEdge* Prev = Edge2->PrevInAEL;
if (Prev) Prev->NextInAEL = Edge1;
Edge1->PrevInAEL = Prev;
Edge1->NextInAEL = Edge2;
Edge2->PrevInAEL = Edge1;
Edge2->NextInAEL = Next;
}
else
{
TEdge* Next = Edge1->NextInAEL;
TEdge* Prev = Edge1->PrevInAEL;
Edge1->NextInAEL = Edge2->NextInAEL;
if (Edge1->NextInAEL) Edge1->NextInAEL->PrevInAEL = Edge1;
Edge1->PrevInAEL = Edge2->PrevInAEL;
if (Edge1->PrevInAEL) Edge1->PrevInAEL->NextInAEL = Edge1;
Edge2->NextInAEL = Next;
if (Edge2->NextInAEL) Edge2->NextInAEL->PrevInAEL = Edge2;
Edge2->PrevInAEL = Prev;
if (Edge2->PrevInAEL) Edge2->PrevInAEL->NextInAEL = Edge2;
}
if (!Edge1->PrevInAEL) m_ActiveEdges = Edge1;
else if (!Edge2->PrevInAEL) m_ActiveEdges = Edge2;
}
//------------------------------------------------------------------------------
void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e)
{
if (!e->NextInLML)
throw clipperException("UpdateEdgeIntoAEL: invalid call");
e->NextInLML->OutIdx = e->OutIdx;
TEdge* AelPrev = e->PrevInAEL;
TEdge* AelNext = e->NextInAEL;
if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
else m_ActiveEdges = e->NextInLML;
if (AelNext) AelNext->PrevInAEL = e->NextInLML;
e->NextInLML->Side = e->Side;
e->NextInLML->WindDelta = e->WindDelta;
e->NextInLML->WindCnt = e->WindCnt;
e->NextInLML->WindCnt2 = e->WindCnt2;
e = e->NextInLML;
e->Curr = e->Bot;
e->PrevInAEL = AelPrev;
e->NextInAEL = AelNext;
if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y);
}
//------------------------------------------------------------------------------
bool ClipperBase::LocalMinimaPending()
{
return (m_CurrentLM != m_MinimaList.end());
}
//------------------------------------------------------------------------------
// TClipper methods ...
@ -1328,8 +1479,6 @@ IntRect ClipperBase::GetBounds()
Clipper::Clipper(int initOptions) : ClipperBase() //constructor
{
m_ActiveEdges = 0;
m_SortedEdges = 0;
m_ExecuteLocked = false;
m_UseFullRange = false;
m_ReverseOutput = ((initOptions & ioReverseSolution) != 0);
@ -1342,12 +1491,6 @@ Clipper::Clipper(int initOptions) : ClipperBase() //constructor
}
//------------------------------------------------------------------------------
Clipper::~Clipper() //destructor
{
Clear();
}
//------------------------------------------------------------------------------
#ifdef use_xyz
void Clipper::ZFillFunction(ZFillCallback zFillFunc)
{
@ -1356,18 +1499,6 @@ void Clipper::ZFillFunction(ZFillCallback zFillFunc)
//------------------------------------------------------------------------------
#endif
void Clipper::Reset()
{
ClipperBase::Reset();
m_Scanbeam = ScanbeamList();
m_Maxima = MaximaList();
m_ActiveEdges = 0;
m_SortedEdges = 0;
for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm)
InsertScanbeam(lm->Y);
}
//------------------------------------------------------------------------------
bool Clipper::Execute(ClipType clipType, Paths &solution, PolyFillType fillType)
{
return Execute(clipType, solution, fillType, fillType);
@ -1437,19 +1568,26 @@ bool Clipper::ExecuteInternal()
bool succeeded = true;
try {
Reset();
if (m_CurrentLM == m_MinimaList.end()) return true;
cInt botY = PopScanbeam();
do {
InsertLocalMinimaIntoAEL(botY);
m_Maxima = MaximaList();
m_SortedEdges = 0;
succeeded = true;
cInt botY, topY;
if (!PopScanbeam(botY)) return false;
InsertLocalMinimaIntoAEL(botY);
while (PopScanbeam(topY) || LocalMinimaPending())
{
ProcessHorizontals();
ClearGhostJoins();
if (m_Scanbeam.empty()) break;
cInt topY = PopScanbeam();
succeeded = ProcessIntersections(topY);
if (!succeeded) break;
ClearGhostJoins();
if (!ProcessIntersections(topY))
{
succeeded = false;
break;
}
ProcessEdgesAtTopOfScanbeam(topY);
botY = topY;
} while (!m_Scanbeam.empty() || m_CurrentLM != m_MinimaList.end());
InsertLocalMinimaIntoAEL(botY);
}
}
catch(std::exception const&)
{
@ -1489,37 +1627,6 @@ bool Clipper::ExecuteInternal()
}
//------------------------------------------------------------------------------
void Clipper::InsertScanbeam(const cInt Y)
{
m_Scanbeam.push(Y);
}
//------------------------------------------------------------------------------
cInt Clipper::PopScanbeam()
{
const cInt Y = m_Scanbeam.top();
m_Scanbeam.pop();
while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates.
return Y;
}
//------------------------------------------------------------------------------
void Clipper::DisposeAllOutRecs(){
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
DisposeOutRec(i);
m_PolyOuts.clear();
}
//------------------------------------------------------------------------------
void Clipper::DisposeOutRec(PolyOutList::size_type index)
{
OutRec *outRec = m_PolyOuts[index];
if (outRec->Pts) DisposeOutPts(outRec->Pts);
delete outRec;
m_PolyOuts[index] = 0;
}
//------------------------------------------------------------------------------
void Clipper::SetWindingCount(TEdge &edge)
{
TEdge *e = edge.PrevInAEL;
@ -1527,7 +1634,13 @@ void Clipper::SetWindingCount(TEdge &edge)
while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL;
if (!e)
{
edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
if (edge.WindDelta == 0)
{
PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType);
edge.WindCnt = (pft == pftNegative ? -1 : 1);
}
else
edge.WindCnt = edge.WindDelta;
edge.WindCnt2 = 0;
e = m_ActiveEdges; //ie get ready to calc WindCnt2
}
@ -1759,13 +1872,16 @@ OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
prevE = e->PrevInAEL;
}
if (prevE && prevE->OutIdx >= 0 &&
(TopX(*prevE, Pt.Y) == TopX(*e, Pt.Y)) &&
SlopesEqual(*e, *prevE, m_UseFullRange) &&
(e->WindDelta != 0) && (prevE->WindDelta != 0))
if (prevE && prevE->OutIdx >= 0)
{
OutPt* outPt = AddOutPt(prevE, Pt);
AddJoin(result, outPt, e->Top);
cInt xPrev = TopX(*prevE, Pt.Y);
cInt xE = TopX(*e, Pt.Y);
if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) &&
SlopesEqual(IntPoint(xPrev, Pt.Y), prevE->Top, IntPoint(xE, Pt.Y), e->Top, m_UseFullRange))
{
OutPt* outPt = AddOutPt(prevE, Pt);
AddJoin(result, outPt, e->Top);
}
}
return result;
}
@ -1807,6 +1923,15 @@ void Clipper::AddEdgeToSEL(TEdge *edge)
}
//------------------------------------------------------------------------------
bool Clipper::PopEdgeFromSEL(TEdge *&edge)
{
if (!m_SortedEdges) return false;
edge = m_SortedEdges;
DeleteFromSEL(m_SortedEdges);
return true;
}
//------------------------------------------------------------------------------
void Clipper::CopyAELToSEL()
{
TEdge* e = m_ActiveEdges;
@ -1858,11 +1983,12 @@ void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt)
void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
{
while (m_CurrentLM != m_MinimaList.end() && (m_CurrentLM->Y == botY))
const LocalMinimum *lm;
while (PopLocalMinima(botY, lm))
{
TEdge* lb = m_CurrentLM->LeftBound;
TEdge* rb = m_CurrentLM->RightBound;
PopLocalMinima();
TEdge* lb = lm->LeftBound;
TEdge* rb = lm->RightBound;
OutPt *Op1 = 0;
if (!lb)
{
@ -1894,8 +2020,13 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
if (rb)
{
if(IsHorizontal(*rb)) AddEdgeToSEL(rb);
else InsertScanbeam( rb->Top.Y );
if (IsHorizontal(*rb))
{
AddEdgeToSEL(rb);
if (rb->NextInLML)
InsertScanbeam(rb->NextInLML->Top.Y);
}
else InsertScanbeam( rb->Top.Y );
}
if (!lb || !rb) continue;
@ -1917,7 +2048,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
if (lb->OutIdx >= 0 && lb->PrevInAEL &&
lb->PrevInAEL->Curr.X == lb->Bot.X &&
lb->PrevInAEL->OutIdx >= 0 &&
SlopesEqual(*lb->PrevInAEL, *lb, m_UseFullRange) &&
SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top, m_UseFullRange) &&
(lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0))
{
OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot);
@ -1928,7 +2059,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
{
if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 &&
SlopesEqual(*rb->PrevInAEL, *rb, m_UseFullRange) &&
SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top, m_UseFullRange) &&
(rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0))
{
OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot);
@ -1952,19 +2083,6 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
}
//------------------------------------------------------------------------------
void Clipper::DeleteFromAEL(TEdge *e)
{
TEdge* AelPrev = e->PrevInAEL;
TEdge* AelNext = e->NextInAEL;
if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted
if( AelPrev ) AelPrev->NextInAEL = AelNext;
else m_ActiveEdges = AelNext;
if( AelNext ) AelNext->PrevInAEL = AelPrev;
e->NextInAEL = 0;
e->PrevInAEL = 0;
}
//------------------------------------------------------------------------------
void Clipper::DeleteFromSEL(TEdge *e)
{
TEdge* SelPrev = e->PrevInSEL;
@ -2188,19 +2306,27 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt)
void Clipper::SetHoleState(TEdge *e, OutRec *outrec)
{
bool IsHole = false;
TEdge *e2 = e->PrevInAEL;
TEdge *eTmp = 0;
while (e2)
{
if (e2->OutIdx >= 0 && e2->WindDelta != 0)
{
IsHole = !IsHole;
if (! outrec->FirstLeft)
outrec->FirstLeft = m_PolyOuts[e2->OutIdx];
if (!eTmp) eTmp = e2;
else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0;
}
e2 = e2->PrevInAEL;
}
if (IsHole) outrec->IsHole = true;
if (!eTmp)
{
outrec->FirstLeft = 0;
outrec->IsHole = false;
}
else
{
outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx];
outrec->IsHole = !outrec->FirstLeft->IsHole;
}
}
//------------------------------------------------------------------------------
@ -2224,7 +2350,7 @@ OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
}
//------------------------------------------------------------------------------
bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
bool OutRec1RightOfOutRec2(OutRec* outRec1, OutRec* outRec2)
{
do
{
@ -2251,9 +2377,9 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
OutRec *outRec2 = m_PolyOuts[e2->OutIdx];
OutRec *holeStateRec;
if (Param1RightOfParam2(outRec1, outRec2))
if (OutRec1RightOfOutRec2(outRec1, outRec2))
holeStateRec = outRec2;
else if (Param1RightOfParam2(outRec2, outRec1))
else if (OutRec1RightOfOutRec2(outRec2, outRec1))
holeStateRec = outRec1;
else
holeStateRec = GetLowermostRec(outRec1, outRec2);
@ -2266,7 +2392,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
OutPt* p2_lft = outRec2->Pts;
OutPt* p2_rt = p2_lft->Prev;
EdgeSide Side;
//join e2 poly onto e1 poly and delete pointers to e2 ...
if( e1->Side == esLeft )
{
@ -2288,7 +2413,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
p1_rt->Next = p2_lft;
outRec1->Pts = p2_lft;
}
Side = esLeft;
} else
{
if( e2->Side == esRight )
@ -2307,7 +2431,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
p1_lft->Prev = p2_rt;
p2_rt->Next = p1_lft;
}
Side = esRight;
}
outRec1->BottomPt = 0;
@ -2333,7 +2456,7 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
if( e->OutIdx == ObsoleteIdx )
{
e->OutIdx = OKIdx;
e->Side = Side;
e->Side = e1->Side;
break;
}
e = e->NextInAEL;
@ -2343,21 +2466,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
}
//------------------------------------------------------------------------------
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;
}
//------------------------------------------------------------------------------
OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
{
if( e->OutIdx < 0 )
@ -2409,13 +2517,9 @@ OutPt* Clipper::GetLastOutPt(TEdge *e)
void Clipper::ProcessHorizontals()
{
TEdge* horzEdge = m_SortedEdges;
while(horzEdge)
{
DeleteFromSEL(horzEdge);
TEdge* horzEdge;
while (PopEdgeFromSEL(horzEdge))
ProcessHorizontal(horzEdge);
horzEdge = m_SortedEdges;
}
}
//------------------------------------------------------------------------------
@ -2439,64 +2543,21 @@ inline bool IsIntermediate(TEdge *e, const cInt Y)
TEdge *GetMaximaPair(TEdge *e)
{
TEdge* result = 0;
if ((e->Next->Top == e->Top) && !e->Next->NextInLML)
result = e->Next;
return e->Next;
else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML)
result = e->Prev;
if (result && (result->OutIdx == Skip ||
//result is false if both NextInAEL & PrevInAEL are nil & not horizontal ...
(result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result))))
return 0;
return result;
return e->Prev;
else return 0;
}
//------------------------------------------------------------------------------
void Clipper::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2)
TEdge *GetMaximaPairEx(TEdge *e)
{
//check that one or other edge hasn't already been removed from AEL ...
if (Edge1->NextInAEL == Edge1->PrevInAEL ||
Edge2->NextInAEL == Edge2->PrevInAEL) return;
if( Edge1->NextInAEL == Edge2 )
{
TEdge* Next = Edge2->NextInAEL;
if( Next ) Next->PrevInAEL = Edge1;
TEdge* Prev = Edge1->PrevInAEL;
if( Prev ) Prev->NextInAEL = Edge2;
Edge2->PrevInAEL = Prev;
Edge2->NextInAEL = Edge1;
Edge1->PrevInAEL = Edge2;
Edge1->NextInAEL = Next;
}
else if( Edge2->NextInAEL == Edge1 )
{
TEdge* Next = Edge1->NextInAEL;
if( Next ) Next->PrevInAEL = Edge2;
TEdge* Prev = Edge2->PrevInAEL;
if( Prev ) Prev->NextInAEL = Edge1;
Edge1->PrevInAEL = Prev;
Edge1->NextInAEL = Edge2;
Edge2->PrevInAEL = Edge1;
Edge2->NextInAEL = Next;
}
else
{
TEdge* Next = Edge1->NextInAEL;
TEdge* Prev = Edge1->PrevInAEL;
Edge1->NextInAEL = Edge2->NextInAEL;
if( Edge1->NextInAEL ) Edge1->NextInAEL->PrevInAEL = Edge1;
Edge1->PrevInAEL = Edge2->PrevInAEL;
if( Edge1->PrevInAEL ) Edge1->PrevInAEL->NextInAEL = Edge1;
Edge2->NextInAEL = Next;
if( Edge2->NextInAEL ) Edge2->NextInAEL->PrevInAEL = Edge2;
Edge2->PrevInAEL = Prev;
if( Edge2->PrevInAEL ) Edge2->PrevInAEL->NextInAEL = Edge2;
}
if( !Edge1->PrevInAEL ) m_ActiveEdges = Edge1;
else if( !Edge2->PrevInAEL ) m_ActiveEdges = Edge2;
//as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal)
TEdge* result = GetMaximaPair(e);
if (result && (result->OutIdx == Skip ||
(result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0;
return result;
}
//------------------------------------------------------------------------------
@ -2582,7 +2643,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
{
Direction dir;
cInt horzLeft, horzRight;
bool IsOpen = (horzEdge->OutIdx >= 0 && m_PolyOuts[horzEdge->OutIdx]->IsOpen);
bool IsOpen = (horzEdge->WindDelta == 0);
GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
@ -2765,29 +2826,6 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
}
//------------------------------------------------------------------------------
void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
{
if( !e->NextInLML )
throw clipperException("UpdateEdgeIntoAEL: invalid call");
e->NextInLML->OutIdx = e->OutIdx;
TEdge* AelPrev = e->PrevInAEL;
TEdge* AelNext = e->NextInAEL;
if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
else m_ActiveEdges = e->NextInLML;
if (AelNext) AelNext->PrevInAEL = e->NextInLML;
e->NextInLML->Side = e->Side;
e->NextInLML->WindDelta = e->WindDelta;
e->NextInLML->WindCnt = e->WindCnt;
e->NextInLML->WindCnt2 = e->WindCnt2;
e = e->NextInLML;
e->Curr = e->Bot;
e->PrevInAEL = AelPrev;
e->NextInAEL = AelNext;
if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y);
}
//------------------------------------------------------------------------------
bool Clipper::ProcessIntersections(const cInt topY)
{
if( !m_ActiveEdges ) return true;
@ -2845,6 +2883,7 @@ void Clipper::BuildIntersectList(const cInt topY)
if(e->Curr.X > eNext->Curr.X)
{
IntersectPoint(*e, *eNext, Pt);
if (Pt.Y < topY) Pt = IntPoint(TopX(*e, topY), topY);
IntersectNode * newNode = new IntersectNode;
newNode->Edge1 = e;
newNode->Edge2 = eNext;
@ -2919,7 +2958,7 @@ bool Clipper::FixupIntersectionOrder()
void Clipper::DoMaxima(TEdge *e)
{
TEdge* eMaxPair = GetMaximaPair(e);
TEdge* eMaxPair = GetMaximaPairEx(e);
if (!eMaxPair)
{
if (e->OutIdx >= 0)
@ -2980,7 +3019,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
if(IsMaximaEdge)
{
TEdge* eMaxPair = GetMaximaPair(e);
TEdge* eMaxPair = GetMaximaPairEx(e);
IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair));
}
@ -3052,7 +3091,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
if (ePrev && ePrev->Curr.X == e->Bot.X &&
ePrev->Curr.Y == e->Bot.Y && op &&
ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
SlopesEqual(*e, *ePrev, m_UseFullRange) &&
SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange) &&
(e->WindDelta != 0) && (ePrev->WindDelta != 0))
{
OutPt* op2 = AddOutPt(ePrev, e->Bot);
@ -3061,7 +3100,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
else if (eNext && eNext->Curr.X == e->Bot.X &&
eNext->Curr.Y == e->Bot.Y && op &&
eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
SlopesEqual(*e, *eNext, m_UseFullRange) &&
SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange) &&
(e->WindDelta != 0) && (eNext->WindDelta != 0))
{
OutPt* op2 = AddOutPt(eNext, e->Bot);
@ -3588,9 +3627,8 @@ void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec* outRec = m_PolyOuts[i];
if (!outRec->Pts || !outRec->FirstLeft) continue;
OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
if (firstLeft == OldOutRec)
if (outRec->Pts && firstLeft == OldOutRec)
{
if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts))
outRec->FirstLeft = NewOutRec;
@ -3599,13 +3637,41 @@ void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
}
//----------------------------------------------------------------------
void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec)
{
void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec)
{
//A polygon has split into two such that one is now the inner of the other.
//It's possible that these polygons now wrap around other polygons, so check
//every polygon that's also contained by OuterOutRec's FirstLeft container
//(including 0) to see if they've become inner to the new inner polygon ...
OutRec* orfl = OuterOutRec->FirstLeft;
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec* outRec = m_PolyOuts[i];
if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec)
continue;
OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec)
continue;
if (Poly2ContainsPoly1(outRec->Pts, InnerOutRec->Pts))
outRec->FirstLeft = InnerOutRec;
else if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts))
outRec->FirstLeft = OuterOutRec;
else if (outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec)
outRec->FirstLeft = orfl;
}
}
//----------------------------------------------------------------------
void Clipper::FixupFirstLefts3(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];
if (outRec->FirstLeft == OldOutRec) outRec->FirstLeft = NewOutRec;
// unused variable `firstLeft`: is this a bug? (dane)
//OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
if (outRec->Pts && outRec->FirstLeft == OldOutRec)
outRec->FirstLeft = NewOutRec;
}
}
//----------------------------------------------------------------------
@ -3626,8 +3692,8 @@ void Clipper::JoinCommonEdges()
//before calling JoinPoints() ...
OutRec *holeStateRec;
if (outRec1 == outRec2) holeStateRec = outRec1;
else if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2;
else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1;
else holeStateRec = GetLowermostRec(outRec1, outRec2);
if (!JoinPoints(join, outRec1, outRec2)) continue;
@ -3644,25 +3710,12 @@ void Clipper::JoinCommonEdges()
//update all OutRec2.Pts Idx's ...
UpdateOutPtIdxs(*outRec2);
//We now need to check every OutRec.FirstLeft pointer. If it points
//to OutRec1 it may need to point to OutRec2 instead ...
if (m_UsingPolyTree)
for (PolyOutList::size_type j = 0; j < m_PolyOuts.size() - 1; j++)
{
OutRec* oRec = m_PolyOuts[j];
if (!oRec->Pts || ParseFirstLeft(oRec->FirstLeft) != outRec1 ||
oRec->IsHole == outRec1->IsHole) continue;
if (Poly2ContainsPoly1(oRec->Pts, join->OutPt2))
oRec->FirstLeft = outRec2;
}
if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts))
{
//outRec2 is contained by outRec1 ...
//outRec1 contains outRec2 ...
outRec2->IsHole = !outRec1->IsHole;
outRec2->FirstLeft = outRec1;
//fixup FirstLeft pointers that may need reassigning to OutRec1
if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0))
@ -3670,13 +3723,12 @@ void Clipper::JoinCommonEdges()
} else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts))
{
//outRec1 is contained by outRec2 ...
//outRec2 contains outRec1 ...
outRec2->IsHole = outRec1->IsHole;
outRec1->IsHole = !outRec2->IsHole;
outRec2->FirstLeft = outRec1->FirstLeft;
outRec1->FirstLeft = outRec2;
//fixup FirstLeft pointers that may need reassigning to OutRec1
if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2);
if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0))
@ -3705,8 +3757,7 @@ void Clipper::JoinCommonEdges()
outRec1->FirstLeft = outRec2->FirstLeft;
outRec2->FirstLeft = outRec1;
//fixup FirstLeft pointers that may need reassigning to OutRec1
if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1);
}
}
}
@ -4404,6 +4455,7 @@ void CleanPolygon(Path& poly, double distance)
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance)
{
out_polys.resize(in_polys.size());
for (Paths::size_type i = 0; i < in_polys.size(); ++i)
CleanPolygon(in_polys[i], out_polys[i], distance);
}

View File

@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.2.9 *
* Date : 16 February 2015 *
* Version : 6.4.0 *
* Date : 2 July 2015 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2015 *
* *
@ -251,7 +251,7 @@ class ClipperBase
public:
ClipperBase();
virtual ~ClipperBase();
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
virtual void Clear();
IntRect GetBounds();
@ -260,11 +260,18 @@ public:
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
void PopLocalMinima();
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
TEdge* DescendToMin(TEdge *&E);
void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
void InsertScanbeam(const cInt Y);
bool PopScanbeam(cInt &Y);
bool LocalMinimaPending();
bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin);
OutRec* CreateOutRec();
void DisposeAllOutRecs();
void DisposeOutRec(PolyOutList::size_type index);
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DeleteFromAEL(TEdge *e);
void UpdateEdgeIntoAEL(TEdge *&e);
typedef std::vector<LocalMinimum> MinimaList;
MinimaList::iterator m_CurrentLM;
@ -272,8 +279,13 @@ protected:
bool m_UseFullRange;
EdgeList m_edges;
bool m_PreserveCollinear;
bool m_HasOpenPaths;
bool m_PreserveCollinear;
bool m_HasOpenPaths;
PolyOutList m_PolyOuts;
TEdge *m_ActiveEdges;
typedef std::priority_queue<cInt> ScanbeamList;
ScanbeamList m_Scanbeam;
};
//------------------------------------------------------------------------------
@ -281,7 +293,6 @@ class Clipper : public virtual ClipperBase
{
public:
Clipper(int initOptions = 0);
~Clipper();
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType fillType = pftEvenOdd);
@ -305,19 +316,14 @@ public:
void ZFillFunction(ZFillCallback zFillFunc);
#endif
protected:
void Reset();
virtual bool ExecuteInternal();
private:
PolyOutList m_PolyOuts;
JoinList m_Joins;
JoinList m_GhostJoins;
IntersectList m_IntersectList;
ClipType m_ClipType;
typedef std::priority_queue<cInt> ScanbeamList;
ScanbeamList m_Scanbeam;
typedef std::list<cInt> MaximaList;
MaximaList m_Maxima;
TEdge *m_ActiveEdges;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
@ -331,19 +337,15 @@ private:
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
void InsertScanbeam(const cInt Y);
cInt PopScanbeam();
void InsertLocalMinimaIntoAEL(const cInt botY);
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
void AddEdgeToSEL(TEdge *edge);
bool PopEdgeFromSEL(TEdge *&edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
void DeleteFromAEL(TEdge *e);
void UpdateEdgeIntoAEL(TEdge *&e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const cInt XPos);
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DoMaxima(TEdge *e);
void ProcessHorizontals();
void ProcessHorizontal(TEdge *horzEdge);
@ -352,11 +354,8 @@ private:
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2);
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
OutRec* CreateOutRec();
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
OutPt* GetLastOutPt(TEdge *e);
void DisposeAllOutRecs();
void DisposeOutRec(PolyOutList::size_type index);
bool ProcessIntersections(const cInt topY);
void BuildIntersectList(const cInt topY);
void ProcessIntersectList();
@ -379,7 +378,8 @@ private:
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec);
void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef use_xyz
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
#endif