clipper.cpp   clipper.cpp 
/************************************************************************** ***** /************************************************************************** *****
* * * *
* Author : Angus Johnson * * Author : Angus Johnson *
* Version : 4.8.8 * Version : 4.9.4
* *
* Date : 30 August 2012 * Date : 2 November 2012
* *
* Website : http://www.angusj.com * * Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2012 * * Copyright : Angus Johnson 2010-2012 *
* * * *
* License: * * License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. * * Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt * * http://www.boost.org/LICENSE_1_0.txt *
* * * *
* Attributions: * * Attributions: *
* The code in this library is an extension of Bala Vatti's clipping algorit hm: * * The code in this library is an extension of Bala Vatti's clipping algorit hm: *
* "A generic solution to polygon clipping" * * "A generic solution to polygon clipping" *
skipping to change at line 106 skipping to change at line 106
{return (hi == val.hi && lo == val.lo);} {return (hi == val.hi && lo == val.lo);}
bool operator != (const Int128 &val) const bool operator != (const Int128 &val) const
{ return !(*this == val);} { return !(*this == val);}
bool operator > (const Int128 &val) const bool operator > (const Int128 &val) const
{ {
if (hi != val.hi) if (hi != val.hi)
return hi > val.hi; return hi > val.hi;
else else
return lo > val.lo; return ulong64(lo) > ulong64(val.lo);
} }
bool operator < (const Int128 &val) const bool operator < (const Int128 &val) const
{ {
if (hi != val.hi) if (hi != val.hi)
return hi < val.hi; return hi < val.hi;
else else
return lo < val.lo; return ulong64(lo) < ulong64(val.lo);
} }
bool operator >= (const Int128 &val) const bool operator >= (const Int128 &val) const
{ return !(*this < val);} { return !(*this < val);}
bool operator <= (const Int128 &val) const bool operator <= (const Int128 &val) const
{ return !(*this > val);} { return !(*this > val);}
Int128& operator += (const Int128 &rhs) Int128& operator += (const Int128 &rhs)
{ {
skipping to change at line 228 skipping to change at line 228
if (p.hi < 0) p = p2; if (p.hi < 0) p = p2;
else result.lo++; else result.lo++;
} }
if (negate) Negate(result); if (negate) Negate(result);
return result; return result;
} }
double AsDouble() const double AsDouble() const
{ {
const double shift64 = 18446744073709551616.0; //2^64 const double shift64 = 18446744073709551616.0; //2^64
const double bit64 = 9223372036854775808.0;
if (hi < 0) if (hi < 0)
{ {
Int128 tmp(*this); if (lo == 0)
Negate(tmp); return (double)hi * shift64;
if (tmp.lo < 0)
return (double)tmp.lo - bit64 - tmp.hi * shift64;
else else
return -(double)tmp.lo - tmp.hi * shift64; return -(double)(ulong64(-lo) + ~hi * shift64);
} }
else if (lo < 0)
return -(double)lo + bit64 + hi * shift64;
else else
return (double)lo + (double)hi * shift64; return (double)(ulong64(lo) + hi * shift64);
} }
//for bug testing ... //for bug testing ...
//std::string AsString() const //std::string AsString() const
//{ //{
// std::string result; // std::string result;
// unsigned char r = 0; // unsigned char r = 0;
// Int128 tmp(0), val(*this); // Int128 tmp(0), val(*this);
// if (hi < 0) Negate(val); // if (hi < 0) Negate(val);
// result.resize(50); // result.resize(50);
skipping to change at line 358 skipping to change at line 353
vec2.Y = poly[jplus].Y - poly[j].Y; vec2.Y = poly[jplus].Y - poly[j].Y;
if (Abs(vec1.X) > loRange || Abs(vec1.Y) > loRange || if (Abs(vec1.X) > loRange || Abs(vec1.Y) > loRange ||
Abs(vec2.X) > loRange || Abs(vec2.Y) > loRange) Abs(vec2.X) > loRange || Abs(vec2.Y) > loRange)
{ {
if (Abs(vec1.X) > hiRange || Abs(vec1.Y) > hiRange || if (Abs(vec1.X) > hiRange || Abs(vec1.Y) > hiRange ||
Abs(vec2.X) > hiRange || Abs(vec2.Y) > hiRange) Abs(vec2.X) > hiRange || Abs(vec2.Y) > hiRange)
throw "Coordinate exceeds range bounds."; throw "Coordinate exceeds range bounds.";
Int128 cross = Int128(vec1.X) * Int128(vec2.Y) - Int128 cross = Int128(vec1.X) * Int128(vec2.Y) -
Int128(vec2.X) * Int128(vec1.Y); Int128(vec2.X) * Int128(vec1.Y);
return cross >= 0; return (cross >= 0);
} }
else else
return (vec1.X * vec2.Y - vec2.X * vec1.Y) >= 0; return (vec1.X * vec2.Y - vec2.X * vec1.Y) >= 0;
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2) inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2)
{ {
return ( pt1.X == pt2.X && pt1.Y == pt2.Y ); return ( pt1.X == pt2.X && pt1.Y == pt2.Y );
} }
skipping to change at line 506 skipping to change at line 501
} }
while (pp2 != pp); while (pp2 != pp);
} }
return result; return result;
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range) bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range)
{ {
if (UseFullInt64Range) if (UseFullInt64Range)
return Int128(e1.ytop - e1.ybot) * Int128(e2.xtop - e2.xbot) == return Int128(e1.deltaY) * Int128(e2.deltaX) ==
Int128(e1.xtop - e1.xbot) * Int128(e2.ytop - e2.ybot); Int128(e1.deltaX) * Int128(e2.deltaY);
else return (e1.ytop - e1.ybot)*(e2.xtop - e2.xbot) == else return e1.deltaY * e2.deltaX == e1.deltaX * e2.deltaY;
(e1.xtop - e1.xbot)*(e2.ytop - e2.ybot);
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
const IntPoint pt3, bool UseFullInt64Range) const IntPoint pt3, bool UseFullInt64Range)
{ {
if (UseFullInt64Range) if (UseFullInt64Range)
return Int128(pt1.Y-pt2.Y) * Int128(pt2.X-pt3.X) == return Int128(pt1.Y-pt2.Y) * Int128(pt2.X-pt3.X) ==
Int128(pt1.X-pt2.X) * Int128(pt2.Y-pt3.Y); Int128(pt1.X-pt2.X) * Int128(pt2.Y-pt3.Y);
else return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); else return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y);
skipping to change at line 542 skipping to change at line 536
double GetDx(const IntPoint pt1, const IntPoint pt2) double GetDx(const IntPoint pt1, const IntPoint pt2)
{ {
return (pt1.Y == pt2.Y) ? return (pt1.Y == pt2.Y) ?
HORIZONTAL : (double)(pt2.X - pt1.X) / (double)(pt2.Y - pt1.Y); HORIZONTAL : (double)(pt2.X - pt1.X) / (double)(pt2.Y - pt1.Y);
} }
//------------------------------------------------------------------------- -- //------------------------------------------------------------------------- --
void SetDx(TEdge &e) void SetDx(TEdge &e)
{ {
if (e.ybot == e.ytop) e.dx = HORIZONTAL; e.deltaX = (e.xtop - e.xbot);
else e.dx = (double)(e.xtop - e.xbot) / (double)(e.ytop - e.ybot); e.deltaY = (e.ytop - e.ybot);
if (e.deltaY == 0) e.dx = HORIZONTAL;
else e.dx = (double)(e.deltaX) / (double)(e.deltaY);
} }
//------------------------------------------------------------------------- -- //------------------------------------------------------------------------- --
void SwapSides(TEdge &edge1, TEdge &edge2) void SwapSides(TEdge &edge1, TEdge &edge2)
{ {
EdgeSide side = edge1.side; EdgeSide side = edge1.side;
edge1.side = edge2.side; edge1.side = edge2.side;
edge2.side = side; edge2.side = side;
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
skipping to change at line 565 skipping to change at line 562
void SwapPolyIndexes(TEdge &edge1, TEdge &edge2) void SwapPolyIndexes(TEdge &edge1, TEdge &edge2)
{ {
int outIdx = edge1.outIdx; int outIdx = edge1.outIdx;
edge1.outIdx = edge2.outIdx; edge1.outIdx = edge2.outIdx;
edge2.outIdx = outIdx; edge2.outIdx = outIdx;
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
inline long64 Round(double val) inline long64 Round(double val)
{ {
return (val < 0) ? return (val < 0) ? static_cast<long64>(val - 0.5) : static_cast<long64>(v
static_cast<long64>(val - 0.5) : static_cast<long64>(val + 0.5); al + 0.5);
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
long64 TopX(TEdge &edge, const long64 currentY) long64 TopX(TEdge &edge, const long64 currentY)
{ {
return ( currentY == edge.ytop ) ? return ( currentY == edge.ytop ) ?
edge.xtop : edge.xbot + Round(edge.dx *(currentY - edge.ybot)); edge.xtop : edge.xbot + Round(edge.dx *(currentY - edge.ybot));
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
skipping to change at line 628 skipping to change at line 624
} }
} else } else
{ {
b1 = edge1.xbot - edge1.ybot * edge1.dx; b1 = edge1.xbot - edge1.ybot * edge1.dx;
b2 = edge2.xbot - edge2.ybot * edge2.dx; b2 = edge2.xbot - edge2.ybot * edge2.dx;
b2 = (b2-b1)/(edge1.dx - edge2.dx); b2 = (b2-b1)/(edge1.dx - edge2.dx);
ip.Y = Round(b2); ip.Y = Round(b2);
ip.X = Round(edge1.dx * b2 + b1); ip.X = Round(edge1.dx * b2 + b1);
} }
return if (ip.Y < edge1.ytop || ip.Y < edge2.ytop)
//can be *so close* to the top of one edge that the rounded Y equals on {
e ytop ... if (edge1.ytop > edge2.ytop)
(ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > edge2.tmpX) | {
| ip.X = edge1.xtop;
(ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > edge2.tmpX) | ip.Y = edge1.ytop;
| return TopX(edge2, edge1.ytop) < edge1.xtop;
(ip.Y > edge1.ytop && ip.Y > edge2.ytop); } else
{
ip.X = edge2.xtop;
ip.Y = edge2.ytop;
return TopX(edge1, edge2.ytop) > edge2.xtop;
}
}
else
return true;
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
void ReversePolyPtLinks(OutPt &pp) void ReversePolyPtLinks(OutPt &pp)
{ {
OutPt *pp1, *pp2; OutPt *pp1, *pp2;
pp1 = &pp; pp1 = &pp;
do { do {
pp2 = pp1->next; pp2 = pp1->next;
pp1->next = pp1->prev; pp1->next = pp1->prev;
skipping to change at line 2126 skipping to change at line 2133
{ {
OutRec *outRec = m_PolyOuts[e->outIdx]; OutRec *outRec = m_PolyOuts[e->outIdx];
OutPt* op = outRec->pts; OutPt* op = outRec->pts;
if ((ToFront && PointsEqual(pt, op->pt)) || if ((ToFront && PointsEqual(pt, op->pt)) ||
(!ToFront && PointsEqual(pt, op->prev->pt))) return; (!ToFront && PointsEqual(pt, op->prev->pt))) return;
if ((e->side | outRec->sides) != outRec->sides) if ((e->side | outRec->sides) != outRec->sides)
{ {
//check for 'rounding' artefacts ... //check for 'rounding' artefacts ...
if (outRec->sides == esNeither && pt.Y == op->pt.Y) if (outRec->sides == esNeither && pt.Y == op->pt.Y)
{
if (ToFront) if (ToFront)
{ {
if (pt.X == op->pt.X +1) return; //ie wrong side of bottomPt if (pt.X == op->pt.X +1) return; //ie wrong side of bottomPt
} }
else if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt else if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt
}
outRec->sides = (EdgeSide)(outRec->sides | e->side); outRec->sides = (EdgeSide)(outRec->sides | e->side);
if (outRec->sides == esBoth) if (outRec->sides == esBoth)
{ {
//A vertex from each side has now been added. //A vertex from each side has now been added.
//Vertices of one side of an output polygon are quite commonly clos e to //Vertices of one side of an output polygon are quite commonly clos e to
//or even 'touching' edges of the other side of the output polygon. //or even 'touching' edges of the other side of the output polygon.
//Very occasionally vertices from one side can 'cross' an edge on t he //Very occasionally vertices from one side can 'cross' an edge on t he
//the other side. The distance 'crossed' is always less that a unit //the other side. The distance 'crossed' is always less that a unit
//and is purely an artefact of coordinate rounding. Nevertheless, t his //and is purely an artefact of coordinate rounding. Nevertheless, t his
//results in very tiny self-intersections. Because of the way //results in very tiny self-intersections. Because of the way
skipping to change at line 2632 skipping to change at line 2640
void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY) void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY)
{ {
TEdge* e = m_ActiveEdges; TEdge* e = m_ActiveEdges;
while( e ) while( e )
{ {
//1. process maxima, treating them as if they're 'bent' horizontal edge s, //1. process maxima, treating them as if they're 'bent' horizontal edge s,
// but exclude maxima with horizontal edges. nb: e can't be a horizon tal. // but exclude maxima with horizontal edges. nb: e can't be a horizon tal.
if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, HORIZONTAL) ) if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, HORIZONTAL) )
{ {
//'e' might be removed from AEL, as may any following edges so ... //'e' might be removed from AEL, as may any following edges so ...
TEdge* ePrior = e->prevInAEL; TEdge* ePrev = e->prevInAEL;
DoMaxima(e, topY); DoMaxima(e, topY);
if( !ePrior ) e = m_ActiveEdges; if( !ePrev ) e = m_ActiveEdges;
else e = ePrior->nextInAEL; else e = ePrev->nextInAEL;
} }
else else
{ {
//2. promote horizontal edges, otherwise update xcurr and ycurr ... //2. promote horizontal edges, otherwise update xcurr and ycurr ...
if( IsIntermediate(e, topY) && NEAR_EQUAL(e->nextInLML->dx, HORIZONT AL) ) if( IsIntermediate(e, topY) && NEAR_EQUAL(e->nextInLML->dx, HORIZONT AL) )
{ {
if (e->outIdx >= 0) if (e->outIdx >= 0)
{ {
AddOutPt(e, IntPoint(e->xtop, e->ytop)); AddOutPt(e, IntPoint(e->xtop, e->ytop));
skipping to change at line 2684 skipping to change at line 2692
//4. Promote intermediate vertices ... //4. Promote intermediate vertices ...
e = m_ActiveEdges; e = m_ActiveEdges;
while( e ) while( e )
{ {
if( IsIntermediate( e, topY ) ) if( IsIntermediate( e, topY ) )
{ {
if( e->outIdx >= 0 ) AddOutPt(e, IntPoint(e->xtop,e->ytop)); if( e->outIdx >= 0 ) AddOutPt(e, IntPoint(e->xtop,e->ytop));
UpdateEdgeIntoAEL(e); UpdateEdgeIntoAEL(e);
//if output polygons share an edge, they'll need joining later ... //if output polygons share an edge, they'll need joining later ...
if (e->outIdx >= 0 && e->prevInAEL && e->prevInAEL->outIdx >= 0 && TEdge* ePrev = e->prevInAEL;
e->prevInAEL->xcurr == e->xbot && e->prevInAEL->ycurr == e->ybot && TEdge* eNext = e->nextInAEL;
SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop), if (ePrev && ePrev->xcurr == e->xbot &&
IntPoint(e->xbot,e->ybot), ePrev->ycurr == e->ybot && e->outIdx >= 0 &&
IntPoint(e->prevInAEL->xtop, e->prevInAEL->ytop), m_UseFullRange) ePrev->outIdx >= 0 && ePrev->ycurr > ePrev->ytop &&
) SlopesEqual(*e, *ePrev, m_UseFullRange))
{ {
AddOutPt(e->prevInAEL, IntPoint(e->xbot, e->ybot)); AddOutPt(ePrev, IntPoint(e->xbot, e->ybot));
AddJoin(e, e->prevInAEL); AddJoin(e, ePrev);
} }
else if (e->outIdx >= 0 && e->nextInAEL && e->nextInAEL->outIdx >= 0 else if (eNext && eNext->xcurr == e->xbot &&
&& eNext->ycurr == e->ybot && e->outIdx >= 0 &&
e->nextInAEL->ycurr > e->nextInAEL->ytop && eNext->outIdx >= 0 && eNext->ycurr > eNext->ytop &&
e->nextInAEL->ycurr <= e->nextInAEL->ybot && SlopesEqual(*e, *eNext, m_UseFullRange))
e->nextInAEL->xcurr == e->xbot && e->nextInAEL->ycurr == e->ybot &&
SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop),
IntPoint(e->xbot,e->ybot),
IntPoint(e->nextInAEL->xtop, e->nextInAEL->ytop), m_UseFullRange)
)
{ {
AddOutPt(e->nextInAEL, IntPoint(e->xbot, e->ybot)); AddOutPt(eNext, IntPoint(e->xbot, e->ybot));
AddJoin(e, e->nextInAEL); AddJoin(e, eNext);
} }
} }
e = e->nextInAEL; e = e->nextInAEL;
} }
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
void Clipper::FixupOutPolygon(OutRec &outRec) void Clipper::FixupOutPolygon(OutRec &outRec)
{ {
//FixupOutPolygon() - removes duplicate points and simplifies consecutive //FixupOutPolygon() - removes duplicate points and simplifies consecutive
skipping to change at line 2931 skipping to change at line 2937
void Clipper::DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt) void Clipper::DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
{ {
AddOutPt(edge1, pt); AddOutPt(edge1, pt);
AddOutPt(edge2, pt); AddOutPt(edge2, pt);
SwapSides( *edge1 , *edge2 ); SwapSides( *edge1 , *edge2 );
SwapPolyIndexes( *edge1 , *edge2 ); SwapPolyIndexes( *edge1 , *edge2 );
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void Clipper::CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2)
{
//when a polygon is split into 2 polygons, make sure any holes the origin
al
//polygon contained link to the correct polygon ...
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec *orec = m_PolyOuts[i];
if (orec->isHole && orec->bottomPt && orec->FirstLeft == outRec1 &&
!PointInPolygon(orec->bottomPt->pt, outRec1->pts, m_UseFullRange))
orec->FirstLeft = outRec2;
}
}
//----------------------------------------------------------------------
void Clipper::CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2)
{
//if a hole is owned by outRec2 then make it owned by outRec1 ...
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
if (m_PolyOuts[i]->isHole && m_PolyOuts[i]->bottomPt &&
m_PolyOuts[i]->FirstLeft == outRec2)
m_PolyOuts[i]->FirstLeft = outRec1;
}
//----------------------------------------------------------------------
void Clipper::JoinCommonEdges(bool fixHoleLinkages) void Clipper::JoinCommonEdges(bool fixHoleLinkages)
{ {
for (JoinList::size_type i = 0; i < m_Joins.size(); i++) for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
{ {
JoinRec* j = m_Joins[i]; JoinRec* j = m_Joins[i];
OutRec *outRec1 = m_PolyOuts[j->poly1Idx]; OutRec *outRec1 = m_PolyOuts[j->poly1Idx];
OutPt *pp1a = outRec1->pts; OutPt *pp1a = outRec1->pts;
OutRec *outRec2 = m_PolyOuts[j->poly2Idx]; OutRec *outRec2 = m_PolyOuts[j->poly2Idx];
OutPt *pp2a = outRec2->pts; OutPt *pp2a = outRec2->pts;
IntPoint pt1 = j->pt2a, pt2 = j->pt2b; IntPoint pt1 = j->pt2a, pt2 = j->pt2b;
skipping to change at line 3040 skipping to change at line 3022
outRec1->bottomPt = outRec1->pts; outRec1->bottomPt = outRec1->pts;
outRec1->bottomPt->idx = outRec1->idx; outRec1->bottomPt->idx = outRec1->idx;
outRec2 = CreateOutRec(); outRec2 = CreateOutRec();
m_PolyOuts.push_back(outRec2); m_PolyOuts.push_back(outRec2);
outRec2->idx = (int)m_PolyOuts.size()-1; outRec2->idx = (int)m_PolyOuts.size()-1;
j->poly2Idx = outRec2->idx; j->poly2Idx = outRec2->idx;
outRec2->pts = GetBottomPt(p2); outRec2->pts = GetBottomPt(p2);
outRec2->bottomPt = outRec2->pts; outRec2->bottomPt = outRec2->pts;
outRec2->bottomPt->idx = outRec2->idx; outRec2->bottomPt->idx = outRec2->idx;
int K = 0;
if (PointInPolygon(outRec2->pts->pt, outRec1->pts, m_UseFullRange)) if (PointInPolygon(outRec2->pts->pt, outRec1->pts, m_UseFullRange))
{ {
//outRec2 is contained by outRec1 ... //outRec2 is contained by outRec1 ...
K = 1;
outRec2->isHole = !outRec1->isHole; outRec2->isHole = !outRec1->isHole;
outRec2->FirstLeft = outRec1; outRec2->FirstLeft = outRec1;
if (outRec2->isHole ==
(m_ReverseOutput ^ Orientation(outRec2, m_UseFullRange)))
ReversePolyPtLinks(*outRec2->pts);
} else if (PointInPolygon(outRec1->pts->pt, outRec2->pts, m_UseFullRa nge)) } else if (PointInPolygon(outRec1->pts->pt, outRec2->pts, m_UseFullRa nge))
{ {
//outRec1 is contained by outRec2 ... //outRec1 is contained by outRec2 ...
K = 2;
outRec2->isHole = outRec1->isHole; outRec2->isHole = outRec1->isHole;
outRec1->isHole = !outRec2->isHole; outRec1->isHole = !outRec2->isHole;
outRec2->FirstLeft = outRec1->FirstLeft; outRec2->FirstLeft = outRec1->FirstLeft;
outRec1->FirstLeft = outRec2; outRec1->FirstLeft = outRec2;
if (outRec1->isHole ==
(m_ReverseOutput ^ Orientation(outRec1, m_UseFullRange)))
ReversePolyPtLinks(*outRec1->pts);
//make sure any contained holes now link to the correct polygon ...
if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
} else } else
{ {
outRec2->isHole = outRec1->isHole; outRec2->isHole = outRec1->isHole;
outRec2->FirstLeft = outRec1->FirstLeft; outRec2->FirstLeft = outRec1->FirstLeft;
//make sure any contained holes now link to the correct polygon ...
if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
} }
//now fixup any subsequent joins that match this polygon //now fixup any subsequent joins that match this polygon
for (JoinList::size_type k = i+1; k < m_Joins.size(); k++) for (JoinList::size_type k = i+1; k < m_Joins.size(); k++)
{ {
JoinRec* j2 = m_Joins[k]; JoinRec* j2 = m_Joins[k];
if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, p2)) if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, p2))
j2->poly1Idx = j->poly2Idx; j2->poly1Idx = j->poly2Idx;
if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, p2)) if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, p2))
j2->poly2Idx = j->poly2Idx; j2->poly2Idx = j->poly2Idx;
} }
//now cleanup redundant edges too ... FixupOutPolygon(*outRec1); //nb: do this BEFORE testing orientation
FixupOutPolygon(*outRec1); FixupOutPolygon(*outRec2); // but AFTER calling PointIsVertex()
FixupOutPolygon(*outRec2);
switch( K ) {
case 1:
{
if (outRec2->pts && outRec2->isHole ==
(m_ReverseOutput ^ Orientation(outRec2, m_UseFullRange)))
ReversePolyPtLinks(*outRec2->pts);
break;
}
case 2:
{
if (outRec1->pts)
{
if (outRec1->isHole ==
(m_ReverseOutput ^ Orientation(outRec1, m_UseFullRange)))
ReversePolyPtLinks(*outRec1->pts);
//make sure any contained holes now link to the correct polyg
on ...
if (fixHoleLinkages && outRec1->isHole)
for (PolyOutList::size_type k = 0; k < m_PolyOuts.size(); +
+k)
{
OutRec *orec = m_PolyOuts[k];
if (orec->isHole && orec->bottomPt && orec->FirstLeft ==
outRec1)
orec->FirstLeft = outRec2;
}
}
break;
}
default:
{
//make sure any contained holes now link to the correct polygon
...
if (fixHoleLinkages)
for (PolyOutList::size_type k = 0; k < m_PolyOuts.size(); ++k
)
{
OutRec *orec = m_PolyOuts[k];
if (orec->isHole && orec->bottomPt && orec->FirstLeft == ou
tRec1 &&
!PointInPolygon(orec->bottomPt->pt, outRec1->pts, m_UseFu
llRange))
orec->FirstLeft = outRec2;
}
}
}
if (Orientation(outRec1, m_UseFullRange) != (Area(*outRec1, m_UseFull Range) > 0)) if (outRec1->pts && Orientation(outRec1, m_UseFullRange) != (Area(*ou tRec1, m_UseFullRange) > 0))
DisposeBottomPt(*outRec1); DisposeBottomPt(*outRec1);
if (Orientation(outRec2, m_UseFullRange) != (Area(*outRec2, m_UseFull Range) > 0)) if (outRec2->pts && Orientation(outRec2, m_UseFullRange) != (Area(*ou tRec2, m_UseFullRange) > 0))
DisposeBottomPt(*outRec2); DisposeBottomPt(*outRec2);
} else } else
{ {
//joined 2 polygons together ... //joined 2 polygons together ...
//make sure any holes contained by outRec2 now link to outRec1 ... //make sure any holes contained by outRec2 now link to outRec1 ...
if (fixHoleLinkages) CheckHoleLinkages2(outRec1, outRec2); if (fixHoleLinkages)
for (PolyOutList::size_type k = 0; k < m_PolyOuts.size(); ++k)
if (m_PolyOuts[k]->isHole && m_PolyOuts[k]->bottomPt &&
m_PolyOuts[k]->FirstLeft == outRec2)
m_PolyOuts[k]->FirstLeft = outRec1;
//now cleanup redundant edges too ... //and cleanup redundant edges too ...
FixupOutPolygon(*outRec1); FixupOutPolygon(*outRec1);
if (outRec1->pts) if (outRec1->pts)
{ {
outRec1->isHole = !Orientation(outRec1, m_UseFullRange); outRec1->isHole = !Orientation(outRec1, m_UseFullRange);
if (outRec1->isHole && !outRec1->FirstLeft) if (outRec1->isHole && !outRec1->FirstLeft)
outRec1->FirstLeft = outRec2->FirstLeft; outRec1->FirstLeft = outRec2->FirstLeft;
} }
//delete the obsolete pointer ... //delete the obsolete pointer ...
 End of changes. 31 change blocks. 
99 lines changed or deleted 119 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/