mirror of
https://github.com/mapbox/tippecanoe.git
synced 2025-03-25 13:17:38 +00:00
Additional Clipper changes through https://github.com/mapnik/clipper/commit/7484da1
This commit is contained in:
parent
51fffb7710
commit
0f5a32b442
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user