polygon: update clipper lib.
This commit is contained in:
parent
1dd0adf7e0
commit
31332c3973
|
@ -1,8 +1,8 @@
|
|||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 4.8.5 *
|
||||
* Date : 15 July 2012 *
|
||||
* Version : 4.9.6 *
|
||||
* Date : 9 November 2012 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2012 *
|
||||
* *
|
||||
|
@ -49,8 +49,8 @@
|
|||
|
||||
namespace ClipperLib {
|
||||
|
||||
static long64 const loRange = 1518500249; //sqrt(2^63 -1)/2
|
||||
static long64 const hiRange = 6521908912666391106LL; //sqrt(2^127 -1)/2
|
||||
static long64 const loRange = 0x3FFFFFFF;
|
||||
static long64 const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||
static double const pi = 3.141592653589793238;
|
||||
enum Direction { dRightToLeft, dLeftToRight };
|
||||
|
||||
|
@ -103,7 +103,7 @@ class Int128
|
|||
if (hi != val.hi)
|
||||
return hi > val.hi;
|
||||
else
|
||||
return lo > val.lo;
|
||||
return ulong64(lo) > ulong64(val.lo);
|
||||
}
|
||||
|
||||
bool operator < (const Int128 &val) const
|
||||
|
@ -111,9 +111,15 @@ class Int128
|
|||
if (hi != val.hi)
|
||||
return hi < val.hi;
|
||||
else
|
||||
return lo < val.lo;
|
||||
return ulong64(lo) < ulong64(val.lo);
|
||||
}
|
||||
|
||||
bool operator >= (const Int128 &val) const
|
||||
{ return !(*this < val);}
|
||||
|
||||
bool operator <= (const Int128 &val) const
|
||||
{ return !(*this > val);}
|
||||
|
||||
Int128& operator += (const Int128 &rhs)
|
||||
{
|
||||
hi += rhs.hi;
|
||||
|
@ -219,20 +225,15 @@ class Int128
|
|||
double AsDouble() const
|
||||
{
|
||||
const double shift64 = 18446744073709551616.0; //2^64
|
||||
const double bit64 = 9223372036854775808.0;
|
||||
if (hi < 0)
|
||||
{
|
||||
Int128 tmp(*this);
|
||||
Negate(tmp);
|
||||
if (tmp.lo < 0)
|
||||
return (double)tmp.lo - bit64 - tmp.hi * shift64;
|
||||
if (lo == 0)
|
||||
return (double)hi * shift64;
|
||||
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
|
||||
return (double)lo + (double)hi * shift64;
|
||||
return (double)(ulong64(lo) + hi * shift64);
|
||||
}
|
||||
|
||||
//for bug testing ...
|
||||
|
@ -317,7 +318,7 @@ bool FullRangeNeeded(const Polygon &pts)
|
|||
return result;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
bool Orientation(const Polygon &poly)
|
||||
{
|
||||
int highI = (int)poly.size() -1;
|
||||
|
@ -349,10 +350,10 @@ bool Orientation(const Polygon &poly)
|
|||
throw "Coordinate exceeds range bounds.";
|
||||
Int128 cross = Int128(vec1.X) * Int128(vec2.Y) -
|
||||
Int128(vec2.X) * Int128(vec1.Y);
|
||||
return cross > 0;
|
||||
return (cross >= 0);
|
||||
}
|
||||
else
|
||||
return (vec1.X * vec2.Y - vec2.X * vec1.Y) > 0;
|
||||
return (vec1.X * vec2.Y - vec2.X * vec1.Y) >= 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -365,7 +366,9 @@ inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2)
|
|||
bool Orientation(OutRec *outRec, bool UseFullInt64Range)
|
||||
{
|
||||
//first make sure bottomPt is correctly assigned ...
|
||||
OutPt *opBottom = outRec->pts, *op = outRec->pts->next;
|
||||
OutPt *opBottom = outRec->pts;
|
||||
if (!opBottom) return true;
|
||||
OutPt *op = outRec->pts->next;
|
||||
while (op != outRec->pts)
|
||||
{
|
||||
if (op->pt.Y >= opBottom->pt.Y)
|
||||
|
@ -394,9 +397,9 @@ bool Orientation(OutRec *outRec, bool UseFullInt64Range)
|
|||
ip2.Y = opNext->pt.Y - op->pt.Y;
|
||||
|
||||
if (UseFullInt64Range)
|
||||
return Int128(ip1.X) * Int128(ip2.Y) - Int128(ip2.X) * Int128(ip1.Y) > 0;
|
||||
return Int128(ip1.X) * Int128(ip2.Y) - Int128(ip2.X) * Int128(ip1.Y) >= 0;
|
||||
else
|
||||
return (ip1.X * ip2.Y - ip2.X * ip1.Y) > 0;
|
||||
return (ip1.X * ip2.Y - ip2.X * ip1.Y) >= 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -428,6 +431,7 @@ double Area(const Polygon &poly)
|
|||
double Area(const OutRec &outRec, bool UseFullInt64Range)
|
||||
{
|
||||
OutPt *op = outRec.pts;
|
||||
if (!op) return 0;
|
||||
if (UseFullInt64Range) {
|
||||
Int128 a(0);
|
||||
do {
|
||||
|
@ -497,10 +501,9 @@ bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range)
|
|||
bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range)
|
||||
{
|
||||
if (UseFullInt64Range)
|
||||
return Int128(e1.ytop - e1.ybot) * Int128(e2.xtop - e2.xbot) ==
|
||||
Int128(e1.xtop - e1.xbot) * Int128(e2.ytop - e2.ybot);
|
||||
else return (e1.ytop - e1.ybot)*(e2.xtop - e2.xbot) ==
|
||||
(e1.xtop - e1.xbot)*(e2.ytop - e2.ybot);
|
||||
return Int128(e1.deltaY) * Int128(e2.deltaX) ==
|
||||
Int128(e1.deltaX) * Int128(e2.deltaY);
|
||||
else return e1.deltaY * e2.deltaX == e1.deltaX * e2.deltaY;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -533,8 +536,11 @@ double GetDx(const IntPoint pt1, const IntPoint pt2)
|
|||
|
||||
void SetDx(TEdge &e)
|
||||
{
|
||||
if (e.ybot == e.ytop) e.dx = HORIZONTAL;
|
||||
else e.dx = (double)(e.xtop - e.xbot) / (double)(e.ytop - e.ybot);
|
||||
e.deltaX = (e.xtop - e.xbot);
|
||||
e.deltaY = (e.ytop - e.ybot);
|
||||
|
||||
if (e.deltaY == 0) e.dx = HORIZONTAL;
|
||||
else e.dx = (double)(e.deltaX) / (double)(e.deltaY);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
@ -556,8 +562,7 @@ void SwapPolyIndexes(TEdge &edge1, TEdge &edge2)
|
|||
|
||||
inline long64 Round(double val)
|
||||
{
|
||||
return (val < 0) ?
|
||||
static_cast<long64>(val - 0.5) : static_cast<long64>(val + 0.5);
|
||||
return (val < 0) ? static_cast<long64>(val - 0.5) : static_cast<long64>(val + 0.5);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -610,33 +615,48 @@ bool IntersectPoint(TEdge &edge1, TEdge &edge2,
|
|||
b1 = edge1.ybot - (edge1.xbot/edge1.dx);
|
||||
ip.Y = Round(ip.X/edge1.dx + b1);
|
||||
}
|
||||
} else
|
||||
} else
|
||||
{
|
||||
b1 = edge1.xbot - edge1.ybot * edge1.dx;
|
||||
b2 = edge2.xbot - edge2.ybot * edge2.dx;
|
||||
b2 = (b2-b1)/(edge1.dx - edge2.dx);
|
||||
ip.Y = Round(b2);
|
||||
ip.X = Round(edge1.dx * b2 + b1);
|
||||
double q = (b2-b1)/(edge1.dx - edge2.dx);
|
||||
ip.Y = Round(q);
|
||||
if (std::fabs(edge1.dx) < std::fabs(edge2.dx))
|
||||
ip.X = Round(edge1.dx * q + b1);
|
||||
else
|
||||
ip.X = Round(edge2.dx * q + b2);
|
||||
}
|
||||
|
||||
return
|
||||
//can be *so close* to the top of one edge that the rounded Y equals one ytop ...
|
||||
(ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > edge2.tmpX) ||
|
||||
(ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > edge2.tmpX) ||
|
||||
(ip.Y > edge1.ytop && ip.Y > edge2.ytop);
|
||||
if (ip.Y < edge1.ytop || ip.Y < edge2.ytop)
|
||||
{
|
||||
if (edge1.ytop > edge2.ytop)
|
||||
{
|
||||
ip.X = edge1.xtop;
|
||||
ip.Y = edge1.ytop;
|
||||
return TopX(edge2, edge1.ytop) < edge1.xtop;
|
||||
} 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)
|
||||
{
|
||||
if (!pp) return;
|
||||
OutPt *pp1, *pp2;
|
||||
pp1 = &pp;
|
||||
pp1 = pp;
|
||||
do {
|
||||
pp2 = pp1->next;
|
||||
pp1->next = pp1->prev;
|
||||
pp1->prev = pp2;
|
||||
pp1 = pp2;
|
||||
} while( pp1 != &pp );
|
||||
} while( pp1 != pp );
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -852,6 +872,7 @@ bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType)
|
|||
{
|
||||
int len = (int)pg.size();
|
||||
if (len < 3) return false;
|
||||
|
||||
Polygon p(len);
|
||||
p[0] = pg[0];
|
||||
int j = 0;
|
||||
|
@ -1308,14 +1329,11 @@ bool Clipper::ExecuteInternal(bool fixHoleLinkages)
|
|||
|
||||
if (outRec->bottomPt == outRec->bottomFlag &&
|
||||
(Orientation(outRec, m_UseFullRange) != (Area(*outRec, m_UseFullRange) > 0)))
|
||||
{
|
||||
DisposeBottomPt(*outRec);
|
||||
FixupOutPolygon(*outRec);
|
||||
};
|
||||
DisposeBottomPt(*outRec);
|
||||
|
||||
if (outRec->isHole ==
|
||||
(m_ReverseOutput ^ Orientation(outRec, m_UseFullRange)))
|
||||
ReversePolyPtLinks(*outRec->pts);
|
||||
ReversePolyPtLinks(outRec->pts);
|
||||
}
|
||||
|
||||
JoinCommonEdges(fixHoleLinkages);
|
||||
|
@ -1473,11 +1491,11 @@ bool Clipper::IsContributing(const TEdge& edge) const
|
|||
|
||||
switch(pft)
|
||||
{
|
||||
case pftEvenOdd:
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
if (Abs(edge.windCnt) != 1) return false;
|
||||
break;
|
||||
case pftPositive:
|
||||
case pftPositive:
|
||||
if (edge.windCnt != 1) return false;
|
||||
break;
|
||||
default: //pftNegative
|
||||
|
@ -1489,46 +1507,46 @@ bool Clipper::IsContributing(const TEdge& edge) const
|
|||
case ctIntersection:
|
||||
switch(pft2)
|
||||
{
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
return (edge.windCnt2 != 0);
|
||||
case pftPositive:
|
||||
case pftPositive:
|
||||
return (edge.windCnt2 > 0);
|
||||
default:
|
||||
default:
|
||||
return (edge.windCnt2 < 0);
|
||||
}
|
||||
case ctUnion:
|
||||
switch(pft2)
|
||||
{
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
return (edge.windCnt2 == 0);
|
||||
case pftPositive:
|
||||
case pftPositive:
|
||||
return (edge.windCnt2 <= 0);
|
||||
default:
|
||||
default:
|
||||
return (edge.windCnt2 >= 0);
|
||||
}
|
||||
case ctDifference:
|
||||
if (edge.polyType == ptSubject)
|
||||
switch(pft2)
|
||||
{
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
return (edge.windCnt2 == 0);
|
||||
case pftPositive:
|
||||
case pftPositive:
|
||||
return (edge.windCnt2 <= 0);
|
||||
default:
|
||||
default:
|
||||
return (edge.windCnt2 >= 0);
|
||||
}
|
||||
else
|
||||
switch(pft2)
|
||||
{
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
case pftEvenOdd:
|
||||
case pftNonZero:
|
||||
return (edge.windCnt2 != 0);
|
||||
case pftPositive:
|
||||
case pftPositive:
|
||||
return (edge.windCnt2 > 0);
|
||||
default:
|
||||
default:
|
||||
return (edge.windCnt2 < 0);
|
||||
}
|
||||
default:
|
||||
|
@ -1548,7 +1566,7 @@ void Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
|
|||
e2->side = esRight;
|
||||
e = e1;
|
||||
if (e->prevInAEL == e2)
|
||||
prevE = e2->prevInAEL;
|
||||
prevE = e2->prevInAEL;
|
||||
else
|
||||
prevE = e->prevInAEL;
|
||||
} else
|
||||
|
@ -1578,9 +1596,9 @@ void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
|
|||
e1->outIdx = -1;
|
||||
e2->outIdx = -1;
|
||||
}
|
||||
else if (e1->outIdx < e2->outIdx)
|
||||
AppendPolygon(e1, e2);
|
||||
else
|
||||
else if (e1->outIdx < e2->outIdx)
|
||||
AppendPolygon(e1, e2);
|
||||
else
|
||||
AppendPolygon(e2, e1);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -1664,7 +1682,7 @@ void Clipper::ClearHorzJoins()
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void Clipper::InsertLocalMinimaIntoAEL( const long64 botY)
|
||||
void Clipper::InsertLocalMinimaIntoAEL(const long64 botY)
|
||||
{
|
||||
while( m_CurrentLM && ( m_CurrentLM->Y == botY ) )
|
||||
{
|
||||
|
@ -1768,7 +1786,7 @@ void Clipper::DeleteFromSEL(TEdge *e)
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
|
||||
const IntPoint &pt, IntersectProtects protects)
|
||||
const IntPoint &pt, const IntersectProtects protects)
|
||||
{
|
||||
//e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before
|
||||
//e2 in AEL except when e1 is being inserted at the intersection point ...
|
||||
|
@ -1839,28 +1857,28 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
|
|||
|
||||
if ( e1Contributing && e2contributing )
|
||||
{
|
||||
if ( e1stops || e2stops ||
|
||||
if ( e1stops || e2stops ||
|
||||
(e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
|
||||
(e1->polyType != e2->polyType && m_ClipType != ctXor) )
|
||||
AddLocalMaxPoly(e1, e2, pt);
|
||||
AddLocalMaxPoly(e1, e2, pt);
|
||||
else
|
||||
DoBothEdges( e1, e2, pt );
|
||||
}
|
||||
else if ( e1Contributing )
|
||||
{
|
||||
if ((e2Wc == 0 || e2Wc == 1) &&
|
||||
(m_ClipType != ctIntersection ||
|
||||
e2->polyType == ptSubject || (e2->windCnt2 != 0)))
|
||||
if ((e2Wc == 0 || e2Wc == 1) &&
|
||||
(m_ClipType != ctIntersection ||
|
||||
e2->polyType == ptSubject || (e2->windCnt2 != 0)))
|
||||
DoEdge1(e1, e2, pt);
|
||||
}
|
||||
else if ( e2contributing )
|
||||
{
|
||||
if ((e1Wc == 0 || e1Wc == 1) &&
|
||||
(m_ClipType != ctIntersection ||
|
||||
e1->polyType == ptSubject || (e1->windCnt2 != 0)))
|
||||
if ((e1Wc == 0 || e1Wc == 1) &&
|
||||
(m_ClipType != ctIntersection ||
|
||||
e1->polyType == ptSubject || (e1->windCnt2 != 0)))
|
||||
DoEdge2(e1, e2, pt);
|
||||
}
|
||||
else if ( (e1Wc == 0 || e1Wc == 1) &&
|
||||
}
|
||||
else if ( (e1Wc == 0 || e1Wc == 1) &&
|
||||
(e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
|
||||
{
|
||||
//neither edge is currently contributing ...
|
||||
|
@ -1950,6 +1968,17 @@ OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
|
||||
{
|
||||
do
|
||||
{
|
||||
outRec1 = outRec1->FirstLeft;
|
||||
if (outRec1 == outRec2) return true;
|
||||
} while (outRec1);
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
|
||||
{
|
||||
//get the start and ends of both output polygons ...
|
||||
|
@ -1957,8 +1986,8 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
|
|||
OutRec *outRec2 = m_PolyOuts[e2->outIdx];
|
||||
|
||||
OutRec *holeStateRec;
|
||||
if (outRec1->FirstLeft == outRec2) holeStateRec = outRec2;
|
||||
else if (outRec2->FirstLeft == outRec1) holeStateRec = outRec1;
|
||||
if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
|
||||
else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
|
||||
else holeStateRec = GetLowermostRec(outRec1, outRec2);
|
||||
|
||||
OutPt* p1_lft = outRec1->pts;
|
||||
|
@ -1973,7 +2002,7 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
|
|||
if( e2->side == esLeft )
|
||||
{
|
||||
//z y x a b c
|
||||
ReversePolyPtLinks(*p2_lft);
|
||||
ReversePolyPtLinks(p2_lft);
|
||||
p2_lft->next = p1_lft;
|
||||
p1_lft->prev = p2_lft;
|
||||
p1_rt->next = p2_rt;
|
||||
|
@ -1994,7 +2023,7 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
|
|||
if( e2->side == esRight )
|
||||
{
|
||||
//a b c z y x
|
||||
ReversePolyPtLinks( *p2_lft );
|
||||
ReversePolyPtLinks(p2_lft);
|
||||
p1_rt->next = p2_rt;
|
||||
p2_rt->prev = p1_rt;
|
||||
p2_lft->next = p1_lft;
|
||||
|
@ -2078,6 +2107,7 @@ void Clipper::DisposeBottomPt(OutRec &outRec)
|
|||
next->prev = prev;
|
||||
prev->next = next;
|
||||
outRec.bottomPt = next;
|
||||
FixupOutPolygon(outRec);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -2116,7 +2146,6 @@ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
|
|||
}
|
||||
else if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt
|
||||
}
|
||||
|
||||
outRec->sides = (EdgeSide)(outRec->sides | e->side);
|
||||
if (outRec->sides == esBoth)
|
||||
{
|
||||
|
@ -2522,7 +2551,7 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool Process1Before2(IntersectNode &node1, IntersectNode &node2)
|
||||
bool ProcessParam1BeforeParam2(const IntersectNode &node1, const IntersectNode &node2)
|
||||
{
|
||||
bool result;
|
||||
if (node1.pt.Y == node2.pt.Y)
|
||||
|
@ -2551,7 +2580,7 @@ void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
|
|||
newNode->pt = pt;
|
||||
newNode->next = 0;
|
||||
if( !m_IntersectNodes ) m_IntersectNodes = newNode;
|
||||
else if( Process1Before2(*newNode, *m_IntersectNodes) )
|
||||
else if( ProcessParam1BeforeParam2(*newNode, *m_IntersectNodes) )
|
||||
{
|
||||
newNode->next = m_IntersectNodes;
|
||||
m_IntersectNodes = newNode;
|
||||
|
@ -2559,7 +2588,7 @@ void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
|
|||
else
|
||||
{
|
||||
IntersectNode* iNode = m_IntersectNodes;
|
||||
while( iNode->next && Process1Before2(*iNode->next, *newNode) )
|
||||
while( iNode->next && ProcessParam1BeforeParam2(*iNode->next, *newNode) )
|
||||
iNode = iNode->next;
|
||||
newNode->next = iNode->next;
|
||||
iNode->next = newNode;
|
||||
|
@ -2617,10 +2646,10 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY)
|
|||
if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, HORIZONTAL) )
|
||||
{
|
||||
//'e' might be removed from AEL, as may any following edges so ...
|
||||
TEdge* ePrior = e->prevInAEL;
|
||||
TEdge* ePrev = e->prevInAEL;
|
||||
DoMaxima(e, topY);
|
||||
if( !ePrior ) e = m_ActiveEdges;
|
||||
else e = ePrior->nextInAEL;
|
||||
if( !ePrev ) e = m_ActiveEdges;
|
||||
else e = ePrev->nextInAEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2669,25 +2698,23 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY)
|
|||
UpdateEdgeIntoAEL(e);
|
||||
|
||||
//if output polygons share an edge, they'll need joining later ...
|
||||
if (e->outIdx >= 0 && e->prevInAEL && e->prevInAEL->outIdx >= 0 &&
|
||||
e->prevInAEL->xcurr == e->xbot && e->prevInAEL->ycurr == e->ybot &&
|
||||
SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop),
|
||||
IntPoint(e->xbot,e->ybot),
|
||||
IntPoint(e->prevInAEL->xtop, e->prevInAEL->ytop), m_UseFullRange))
|
||||
TEdge* ePrev = e->prevInAEL;
|
||||
TEdge* eNext = e->nextInAEL;
|
||||
if (ePrev && ePrev->xcurr == e->xbot &&
|
||||
ePrev->ycurr == e->ybot && e->outIdx >= 0 &&
|
||||
ePrev->outIdx >= 0 && ePrev->ycurr > ePrev->ytop &&
|
||||
SlopesEqual(*e, *ePrev, m_UseFullRange))
|
||||
{
|
||||
AddOutPt(e->prevInAEL, IntPoint(e->xbot, e->ybot));
|
||||
AddJoin(e, e->prevInAEL);
|
||||
AddOutPt(ePrev, IntPoint(e->xbot, e->ybot));
|
||||
AddJoin(e, ePrev);
|
||||
}
|
||||
else if (e->outIdx >= 0 && e->nextInAEL && e->nextInAEL->outIdx >= 0 &&
|
||||
e->nextInAEL->ycurr > e->nextInAEL->ytop &&
|
||||
e->nextInAEL->ycurr <= e->nextInAEL->ybot &&
|
||||
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))
|
||||
else if (eNext && eNext->xcurr == e->xbot &&
|
||||
eNext->ycurr == e->ybot && e->outIdx >= 0 &&
|
||||
eNext->outIdx >= 0 && eNext->ycurr > eNext->ytop &&
|
||||
SlopesEqual(*e, *eNext, m_UseFullRange))
|
||||
{
|
||||
AddOutPt(e->nextInAEL, IntPoint(e->xbot, e->ybot));
|
||||
AddJoin(e, e->nextInAEL);
|
||||
AddOutPt(eNext, IntPoint(e->xbot, e->ybot));
|
||||
AddJoin(e, eNext);
|
||||
}
|
||||
}
|
||||
e = e->nextInAEL;
|
||||
|
@ -2916,55 +2943,28 @@ void Clipper::DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
|
|||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void Clipper::CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2)
|
||||
bool Clipper::JoinPoints(const JoinRec *j, OutPt *&p1, OutPt *&p2)
|
||||
{
|
||||
//when a polygon is split into 2 polygons, make sure any holes the original
|
||||
//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)
|
||||
{
|
||||
for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
|
||||
{
|
||||
JoinRec* j = m_Joins[i];
|
||||
OutRec *outRec1 = m_PolyOuts[j->poly1Idx];
|
||||
OutPt *pp1a = outRec1->pts;
|
||||
OutRec *outRec2 = m_PolyOuts[j->poly2Idx];
|
||||
if (!outRec1 || !outRec2) return false;
|
||||
OutPt *pp1a = outRec1->pts;
|
||||
OutPt *pp2a = outRec2->pts;
|
||||
IntPoint pt1 = j->pt2a, pt2 = j->pt2b;
|
||||
IntPoint pt3 = j->pt1a, pt4 = j->pt1b;
|
||||
if (!FindSegment(pp1a, pt1, pt2)) continue;
|
||||
if (j->poly1Idx == j->poly2Idx)
|
||||
if (!FindSegment(pp1a, pt1, pt2)) return false;
|
||||
if (outRec1 == outRec2)
|
||||
{
|
||||
//we're searching the same polygon for overlapping segments so
|
||||
//segment 2 mustn't be the same as segment 1 ...
|
||||
pp2a = pp1a->next;
|
||||
if (!FindSegment(pp2a, pt3, pt4) || (pp2a == pp1a)) continue;
|
||||
if (!FindSegment(pp2a, pt3, pt4) || (pp2a == pp1a)) return false;
|
||||
}
|
||||
else if (!FindSegment(pp2a, pt3, pt4)) continue;
|
||||
else if (!FindSegment(pp2a, pt3, pt4)) return false;
|
||||
|
||||
if (!GetOverlapSegment(pt1, pt2, pt3, pt4, pt1, pt2)) continue;
|
||||
if (!GetOverlapSegment(pt1, pt2, pt3, pt4, pt1, pt2)) return false;
|
||||
|
||||
OutPt *p1, *p2, *p3, *p4;
|
||||
OutPt *prev = pp1a->prev;
|
||||
OutPt *p3, *p4, *prev = pp1a->prev;
|
||||
//get p1 & p2 polypts - the overlap start & endpoints on poly1
|
||||
if (PointsEqual(pp1a->pt, pt1)) p1 = pp1a;
|
||||
else if (PointsEqual(prev->pt, pt1)) p1 = prev;
|
||||
|
@ -2999,6 +2999,7 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
|
|||
p3->prev = p1;
|
||||
p2->prev = p4;
|
||||
p4->next = p2;
|
||||
return true;
|
||||
}
|
||||
else if (p1->prev == p2 && p3->next == p4)
|
||||
{
|
||||
|
@ -3006,11 +3007,38 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
|
|||
p3->next = p1;
|
||||
p2->next = p4;
|
||||
p4->prev = p2;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
continue; //an orientation is probably wrong
|
||||
return false; //an orientation is probably wrong
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
if (j->poly2Idx == j->poly1Idx)
|
||||
void Clipper::FixupJoinRecs(JoinRec *j, OutPt *pt, unsigned startIdx)
|
||||
{
|
||||
for (JoinList::size_type k = startIdx; k < m_Joins.size(); k++)
|
||||
{
|
||||
JoinRec* j2 = m_Joins[k];
|
||||
if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, pt))
|
||||
j2->poly1Idx = j->poly2Idx;
|
||||
if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, pt))
|
||||
j2->poly2Idx = j->poly2Idx;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void Clipper::JoinCommonEdges(bool fixHoleLinkages)
|
||||
{
|
||||
for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
|
||||
{
|
||||
JoinRec* j = m_Joins[i];
|
||||
OutPt *p1, *p2;
|
||||
if (!JoinPoints(j, p1, p2)) return;
|
||||
|
||||
OutRec *outRec1 = m_PolyOuts[j->poly1Idx];
|
||||
OutRec *outRec2 = m_PolyOuts[j->poly2Idx];
|
||||
|
||||
if (outRec1 == outRec2)
|
||||
{
|
||||
//instead of joining two polygons, we've just created a new one by
|
||||
//splitting one polygon into two.
|
||||
|
@ -3030,8 +3058,15 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
|
|||
//outRec2 is contained by outRec1 ...
|
||||
outRec2->isHole = !outRec1->isHole;
|
||||
outRec2->FirstLeft = outRec1;
|
||||
if (outRec2->isHole == Orientation(outRec2, m_UseFullRange))
|
||||
ReversePolyPtLinks(*outRec2->pts);
|
||||
|
||||
FixupJoinRecs(j, p2, i+1);
|
||||
FixupOutPolygon(*outRec1); //nb: do this BEFORE testing orientation
|
||||
FixupOutPolygon(*outRec2); // but AFTER calling FixupJoinRecs()
|
||||
|
||||
if (outRec2->pts && outRec2->isHole ==
|
||||
(m_ReverseOutput ^ Orientation(outRec2, m_UseFullRange)))
|
||||
ReversePolyPtLinks(outRec2->pts);
|
||||
|
||||
} else if (PointInPolygon(outRec1->pts->pt, outRec2->pts, m_UseFullRange))
|
||||
{
|
||||
//outRec1 is contained by outRec2 ...
|
||||
|
@ -3039,39 +3074,61 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
|
|||
outRec1->isHole = !outRec2->isHole;
|
||||
outRec2->FirstLeft = outRec1->FirstLeft;
|
||||
outRec1->FirstLeft = outRec2;
|
||||
if (outRec1->isHole == Orientation(outRec1, m_UseFullRange))
|
||||
ReversePolyPtLinks(*outRec1->pts);
|
||||
|
||||
FixupJoinRecs(j, p2, i+1);
|
||||
FixupOutPolygon(*outRec1); //nb: do this BEFORE testing orientation
|
||||
FixupOutPolygon(*outRec2); // but AFTER calling FixupJoinRecs()
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//the 2 polygons are completely separate ...
|
||||
outRec2->isHole = outRec1->isHole;
|
||||
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
|
||||
for (JoinList::size_type k = i+1; k < m_Joins.size(); k++)
|
||||
{
|
||||
JoinRec* j2 = m_Joins[k];
|
||||
if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, p2))
|
||||
j2->poly1Idx = j->poly2Idx;
|
||||
if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, p2))
|
||||
j2->poly2Idx = j->poly2Idx;
|
||||
}
|
||||
FixupJoinRecs(j, p2, i+1);
|
||||
FixupOutPolygon(*outRec1); //nb: do this BEFORE testing orientation
|
||||
FixupOutPolygon(*outRec2); // but AFTER calling FixupJoinRecs()
|
||||
|
||||
if (fixHoleLinkages && outRec2->pts)
|
||||
for (PolyOutList::size_type k = 0; k < m_PolyOuts.size(); ++k)
|
||||
{
|
||||
OutRec *orec = m_PolyOuts[k];
|
||||
if (orec->isHole && orec->bottomPt && orec->FirstLeft == outRec1 &&
|
||||
PointInPolygon(orec->bottomPt->pt, outRec2->pts, m_UseFullRange))
|
||||
orec->FirstLeft = outRec2;
|
||||
}
|
||||
}
|
||||
|
||||
if (Orientation(outRec1, m_UseFullRange) != (Area(*outRec1, m_UseFullRange) >= 0))
|
||||
DisposeBottomPt(*outRec1);
|
||||
if (Orientation(outRec2, m_UseFullRange) != (Area(*outRec2, m_UseFullRange) >= 0))
|
||||
DisposeBottomPt(*outRec2);
|
||||
|
||||
//now cleanup redundant edges too ...
|
||||
FixupOutPolygon(*outRec1);
|
||||
FixupOutPolygon(*outRec2);
|
||||
} else
|
||||
{
|
||||
//joined 2 polygons together ...
|
||||
|
||||
//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);
|
||||
|
||||
if (outRec1->pts)
|
||||
|
@ -3100,16 +3157,16 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ReversePoints(Polygon& p)
|
||||
void ReversePolygon(Polygon& p)
|
||||
{
|
||||
std::reverse(p.begin(), p.end());
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ReversePoints(Polygons& p)
|
||||
void ReversePolygons(Polygons& p)
|
||||
{
|
||||
for (Polygons::size_type i = 0; i < p.size(); ++i)
|
||||
ReversePoints(p[i]);
|
||||
ReversePolygon(p[i]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -3143,9 +3200,9 @@ Polygon BuildArc(const IntPoint &pt,
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DoublePoint GetUnitNormal( const IntPoint &pt1, const IntPoint &pt2)
|
||||
DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
|
||||
{
|
||||
if(pt2.X == pt1.X && pt2.Y == pt1.Y)
|
||||
if(pt2.X == pt1.X && pt2.Y == pt1.Y)
|
||||
return DoublePoint(0, 0);
|
||||
|
||||
double dx = (double)(pt2.X - pt1.X);
|
||||
|
@ -3169,11 +3226,11 @@ private:
|
|||
size_t m_i, m_j, m_k;
|
||||
static const int buffLength = 128;
|
||||
JoinType m_jointype;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
||||
double delta, JoinType jointype, double MiterLimit)
|
||||
double delta, JoinType jointype, double MiterLimit, bool CheckInputs)
|
||||
{
|
||||
//nb precondition - out_polys != ptsin_polys
|
||||
if (NEAR_ZERO(delta))
|
||||
|
@ -3185,22 +3242,57 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
|||
this->m_p = in_polys;
|
||||
this->m_delta = delta;
|
||||
this->m_jointype = jointype;
|
||||
|
||||
//ChecksInput - fixes polygon orientation if necessary and removes
|
||||
//duplicate vertices. Can be set false when you're sure that polygon
|
||||
//orientation is correct and that there are no duplicate vertices.
|
||||
if (CheckInputs)
|
||||
{
|
||||
size_t Len = m_p.size(), botI = 0;
|
||||
while (botI < Len && m_p[botI].size() == 0) botI++;
|
||||
if (botI == Len) return;
|
||||
|
||||
//botPt: used to find the lowermost (in inverted Y-axis) & leftmost point
|
||||
//This point (on m_p[botI]) must be on an outer polygon ring and if
|
||||
//its orientation is false (counterclockwise) then assume all polygons
|
||||
//need reversing ...
|
||||
IntPoint botPt = m_p[botI][0];
|
||||
for (size_t i = botI; i < Len; ++i)
|
||||
{
|
||||
if (m_p[i].size() < 3) continue;
|
||||
if (UpdateBotPt(m_p[i][0], botPt)) botI = i;
|
||||
Polygon::iterator it = m_p[i].begin() +1;
|
||||
while (it != m_p[i].end())
|
||||
{
|
||||
if (PointsEqual(*it, *(it -1)))
|
||||
it = m_p[i].erase(it);
|
||||
else
|
||||
{
|
||||
if (UpdateBotPt(*it, botPt)) botI = i;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Orientation(m_p[botI]))
|
||||
ReversePolygons(m_p);
|
||||
}
|
||||
|
||||
if (MiterLimit <= 1) MiterLimit = 1;
|
||||
m_RMin = 2/(MiterLimit*MiterLimit);
|
||||
|
||||
|
||||
double deltaSq = delta*delta;
|
||||
out_polys.clear();
|
||||
out_polys.resize(in_polys.size());
|
||||
for (m_i = 0; m_i < in_polys.size(); m_i++)
|
||||
out_polys.resize(m_p.size());
|
||||
for (m_i = 0; m_i < m_p.size(); m_i++)
|
||||
{
|
||||
m_curr_poly = &out_polys[m_i];
|
||||
size_t len = in_polys[m_i].size();
|
||||
size_t len = m_p[m_i].size();
|
||||
if (len > 1 && m_p[m_i][0].X == m_p[m_i][len - 1].X &&
|
||||
m_p[m_i][0].Y == m_p[m_i][len-1].Y) len--;
|
||||
|
||||
//when 'shrinking' polygons - to minimize artefacts
|
||||
//strip those polygons that have an area < pi * delta^2 ...
|
||||
double a1 = Area(in_polys[m_i]);
|
||||
double a1 = Area(m_p[m_i]);
|
||||
if (delta < 0) { if (a1 > 0 && a1 < deltaSq *pi) len = 0; }
|
||||
else if (a1 < 0 && -a1 < deltaSq *pi) len = 0; //holes have neg. area
|
||||
|
||||
|
@ -3209,7 +3301,7 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
|||
else if (len == 1)
|
||||
{
|
||||
Polygon arc;
|
||||
arc = BuildArc(in_polys[m_i][len-1], 0, 2 * pi, delta);
|
||||
arc = BuildArc(m_p[m_i][len-1], 0, 2 * pi, delta);
|
||||
out_polys[m_i] = arc;
|
||||
continue;
|
||||
}
|
||||
|
@ -3217,10 +3309,10 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
|||
//build normals ...
|
||||
normals.clear();
|
||||
normals.resize(len);
|
||||
normals[len-1] = GetUnitNormal(in_polys[m_i][len-1], in_polys[m_i][0]);
|
||||
normals[len-1] = GetUnitNormal(m_p[m_i][len-1], m_p[m_i][0]);
|
||||
for (m_j = 0; m_j < len -1; ++m_j)
|
||||
normals[m_j] = GetUnitNormal(in_polys[m_i][m_j], in_polys[m_i][m_j+1]);
|
||||
|
||||
normals[m_j] = GetUnitNormal(m_p[m_i][m_j], m_p[m_i][m_j+1]);
|
||||
|
||||
m_k = len -1;
|
||||
for (m_j = 0; m_j < len; ++m_j)
|
||||
{
|
||||
|
@ -3228,7 +3320,7 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
|||
{
|
||||
case jtMiter:
|
||||
{
|
||||
m_R = 1 + (normals[m_j].X*normals[m_k].X +
|
||||
m_R = 1 + (normals[m_j].X*normals[m_k].X +
|
||||
normals[m_j].Y*normals[m_k].Y);
|
||||
if (m_R >= m_RMin) DoMiter(); else DoSquare(MiterLimit);
|
||||
break;
|
||||
|
@ -3261,7 +3353,7 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
|
|||
if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative))
|
||||
{
|
||||
out_polys.erase(out_polys.begin());
|
||||
ReversePoints(out_polys);
|
||||
ReversePolygons(out_polys);
|
||||
|
||||
} else
|
||||
out_polys.clear();
|
||||
|
@ -3286,12 +3378,13 @@ void DoSquare(double mul = 1.0)
|
|||
(long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
|
||||
IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
|
||||
(long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
|
||||
double sinAngle = normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y;
|
||||
if (sinAngle * m_delta >= 0)
|
||||
if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
|
||||
{
|
||||
//occasionally (due to floating point math) sinAngle can be > 1 so ...
|
||||
if (sinAngle > 1) sinAngle = 1; else if (sinAngle < -1) sinAngle = -1;
|
||||
double dx = tan((pi - asin(sinAngle))/4) * abs(m_delta*mul);
|
||||
double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
|
||||
double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X);
|
||||
a1 = std::fabs(a2 - a1);
|
||||
if (a1 > pi) a1 = pi * 2 - a1;
|
||||
double dx = std::tan((pi - a1)/4) * std::fabs(m_delta * mul);
|
||||
pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
|
||||
(long64)(pt1.Y + normals[m_k].X * dx));
|
||||
AddPoint(pt1);
|
||||
|
@ -3301,9 +3394,9 @@ void DoSquare(double mul = 1.0)
|
|||
}
|
||||
else
|
||||
{
|
||||
AddPoint(pt1);
|
||||
AddPoint(m_p[m_i][m_j]);
|
||||
AddPoint(pt2);
|
||||
AddPoint(pt1);
|
||||
AddPoint(m_p[m_i][m_j]);
|
||||
AddPoint(pt2);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -3313,7 +3406,7 @@ void DoMiter()
|
|||
if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
|
||||
{
|
||||
double q = m_delta / m_R;
|
||||
AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X +
|
||||
AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X +
|
||||
(normals[m_k].X + normals[m_j].X) * q),
|
||||
(long64)Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
|
||||
}
|
||||
|
@ -3357,42 +3450,53 @@ void DoRound()
|
|||
}
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool UpdateBotPt(const IntPoint &pt, IntPoint &botPt)
|
||||
{
|
||||
if (pt.Y > botPt.Y || (pt.Y == botPt.Y && pt.X < botPt.X))
|
||||
{
|
||||
botPt = pt;
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
}; //end PolyOffsetBuilder
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
|
||||
double delta, JoinType jointype, double MiterLimit)
|
||||
double delta, JoinType jointype, double MiterLimit, bool CheckInputs)
|
||||
{
|
||||
if (&out_polys == &in_polys)
|
||||
{
|
||||
Polygons poly2(in_polys);
|
||||
PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit);
|
||||
PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit, CheckInputs);
|
||||
}
|
||||
else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit);
|
||||
else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit, CheckInputs);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys)
|
||||
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType)
|
||||
{
|
||||
Clipper c;
|
||||
c.AddPolygon(in_poly, ptSubject);
|
||||
c.Execute(ctUnion, out_polys);
|
||||
c.Execute(ctUnion, out_polys, fillType, fillType);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys)
|
||||
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType)
|
||||
{
|
||||
Clipper c;
|
||||
c.AddPolygons(in_polys, ptSubject);
|
||||
c.Execute(ctUnion, out_polys);
|
||||
c.Execute(ctUnion, out_polys, fillType, fillType);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SimplifyPolygons(Polygons &polys)
|
||||
void SimplifyPolygons(Polygons &polys, PolyFillType fillType)
|
||||
{
|
||||
SimplifyPolygons(polys, polys);
|
||||
SimplifyPolygons(polys, polys, fillType);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 4.8.5 *
|
||||
* Date : 15 July 2012 *
|
||||
* Version : 4.9.6 *
|
||||
* Date : 9 November 2012 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2012 *
|
||||
* *
|
||||
|
@ -78,13 +78,13 @@ enum JoinType { jtSquare, jtRound, jtMiter };
|
|||
bool Orientation(const Polygon &poly);
|
||||
double Area(const Polygon &poly);
|
||||
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
|
||||
double delta, JoinType jointype = jtSquare, double MiterLimit = 2);
|
||||
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys);
|
||||
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys);
|
||||
void SimplifyPolygons(Polygons &polys);
|
||||
double delta, JoinType jointype = jtSquare, double MiterLimit = 2, bool CheckInputs = true);
|
||||
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
|
||||
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
|
||||
void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd);
|
||||
|
||||
void ReversePoints(Polygon& p);
|
||||
void ReversePoints(Polygons& p);
|
||||
void ReversePolygon(Polygon& p);
|
||||
void ReversePolygons(Polygons& p);
|
||||
|
||||
//used internally ...
|
||||
enum EdgeSide { esNeither = 0, esLeft = 1, esRight = 2, esBoth = 3 };
|
||||
|
@ -98,6 +98,8 @@ struct TEdge {
|
|||
long64 xtop;
|
||||
long64 ytop;
|
||||
double dx;
|
||||
long64 deltaX;
|
||||
long64 deltaY;
|
||||
long64 tmpX;
|
||||
PolyType polyType;
|
||||
EdgeSide side;
|
||||
|
@ -257,7 +259,7 @@ private:
|
|||
void DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
|
||||
void DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
|
||||
void IntersectEdges(TEdge *e1, TEdge *e2,
|
||||
const IntPoint &pt, IntersectProtects protects);
|
||||
const IntPoint &pt, const IntersectProtects protects);
|
||||
OutRec* CreateOutRec();
|
||||
void AddOutPt(TEdge *e, const IntPoint &pt);
|
||||
void DisposeBottomPt(OutRec &outRec);
|
||||
|
@ -276,12 +278,12 @@ private:
|
|||
void FixupOutPolygon(OutRec &outRec);
|
||||
bool IsHole(TEdge *e);
|
||||
void FixHoleLinkage(OutRec *outRec);
|
||||
void CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2);
|
||||
void CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2);
|
||||
void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx = -1);
|
||||
void ClearJoins();
|
||||
void AddHorzJoin(TEdge *e, int idx);
|
||||
void ClearHorzJoins();
|
||||
bool JoinPoints(const JoinRec *j, OutPt *&p1, OutPt *&p2);
|
||||
void FixupJoinRecs(JoinRec *j, OutPt *pt, unsigned startIdx);
|
||||
void JoinCommonEdges(bool fixHoleLinkages);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue