clipper.cpp   clipper.cpp 
/************************************************************************** ***** /************************************************************************** *****
* * * *
* Author : Angus Johnson * * Author : Angus Johnson *
* Version : 4.8.5 * Version : 4.8.6
* *
* Date : 15 July 2012 * Date : 11 August 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 52 skipping to change at line 52
#include <cmath> #include <cmath>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <stdexcept> #include <stdexcept>
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <ostream> #include <ostream>
namespace ClipperLib { namespace ClipperLib {
static long64 const loRange = 1518500249; //sqrt(2^63 -1)/2 static long64 const loRange = 0x3FFFFFFF;
static long64 const hiRange = 6521908912666391106LL; //sqrt(2^127 -1)/2 static long64 const hiRange = 0x3FFFFFFFFFFFFFFFLL;
static double const pi = 3.141592653589793238; static double const pi = 3.141592653589793238;
enum Direction { dRightToLeft, dLeftToRight }; enum Direction { dRightToLeft, dLeftToRight };
#define HORIZONTAL (-1.0E+40) #define HORIZONTAL (-1.0E+40)
#define TOLERANCE (1.0e-20) #define TOLERANCE (1.0e-20)
#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) #define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b)) #define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b))
inline long64 Abs(long64 val) inline long64 Abs(long64 val)
{ {
skipping to change at line 117 skipping to change at line 117
} }
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 lo < 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) Int128& operator += (const Int128 &rhs)
{ {
hi += rhs.hi; hi += rhs.hi;
lo += rhs.lo; lo += rhs.lo;
if (ulong64(lo) < ulong64(rhs.lo)) hi++; if (ulong64(lo) < ulong64(rhs.lo)) hi++;
return *this; return *this;
} }
Int128 operator + (const Int128 &rhs) const Int128 operator + (const Int128 &rhs) const
{ {
skipping to change at line 352 skipping to change at line 358
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 );
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
bool Orientation(OutRec *outRec, bool UseFullInt64Range) bool Orientation(OutRec *outRec, bool UseFullInt64Range)
skipping to change at line 397 skipping to change at line 403
while (op != opNext && PointsEqual(op->pt, opNext->pt)) while (op != opNext && PointsEqual(op->pt, opNext->pt))
opNext = opNext->next; opNext = opNext->next;
IntPoint ip1, ip2; IntPoint ip1, ip2;
ip1.X = op->pt.X - opPrev->pt.X; ip1.X = op->pt.X - opPrev->pt.X;
ip1.Y = op->pt.Y - opPrev->pt.Y; ip1.Y = op->pt.Y - opPrev->pt.Y;
ip2.X = opNext->pt.X - op->pt.X; ip2.X = opNext->pt.X - op->pt.X;
ip2.Y = opNext->pt.Y - op->pt.Y; ip2.Y = opNext->pt.Y - op->pt.Y;
if (UseFullInt64Range) 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 else
return (ip1.X * ip2.Y - ip2.X * ip1.Y) > 0; return (ip1.X * ip2.Y - ip2.X * ip1.Y) >= 0;
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
double Area(const Polygon &poly) double Area(const Polygon &poly)
{ {
int highI = (int)poly.size() -1; int highI = (int)poly.size() -1;
if (highI < 2) return 0; if (highI < 2) return 0;
if (FullRangeNeeded(poly)) { if (FullRangeNeeded(poly)) {
Int128 a; Int128 a;
skipping to change at line 1952 skipping to change at line 1958
else if (outPt1->pt.Y < outPt2->pt.Y) return outRec2; else if (outPt1->pt.Y < outPt2->pt.Y) return outRec2;
else if (outPt1->pt.X < outPt2->pt.X) return outRec1; else if (outPt1->pt.X < outPt2->pt.X) return outRec1;
else if (outPt1->pt.X > outPt2->pt.X) return outRec2; else if (outPt1->pt.X > outPt2->pt.X) return outRec2;
else if (outPt1->next == outPt1) return outRec2; else if (outPt1->next == outPt1) return outRec2;
else if (outPt2->next == outPt2) return outRec1; else if (outPt2->next == outPt2) return outRec1;
else if (FirstIsBottomPt(outPt1, outPt2)) return outRec1; else if (FirstIsBottomPt(outPt1, outPt2)) return outRec1;
else return outRec2; else return 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) void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
{ {
//get the start and ends of both output polygons ... //get the start and ends of both output polygons ...
OutRec *outRec1 = m_PolyOuts[e1->outIdx]; OutRec *outRec1 = m_PolyOuts[e1->outIdx];
OutRec *outRec2 = m_PolyOuts[e2->outIdx]; OutRec *outRec2 = m_PolyOuts[e2->outIdx];
OutRec *holeStateRec; OutRec *holeStateRec;
if (outRec1->FirstLeft == outRec2) holeStateRec = outRec2; if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
else if (outRec2->FirstLeft == outRec1) holeStateRec = outRec1; else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
else holeStateRec = GetLowermostRec(outRec1, outRec2); else holeStateRec = GetLowermostRec(outRec1, outRec2);
OutPt* p1_lft = outRec1->pts; OutPt* p1_lft = outRec1->pts;
OutPt* p1_rt = p1_lft->prev; OutPt* p1_rt = p1_lft->prev;
OutPt* p2_lft = outRec2->pts; OutPt* p2_lft = outRec2->pts;
OutPt* p2_rt = p2_lft->prev; OutPt* p2_rt = p2_lft->prev;
EdgeSide side; EdgeSide side;
//join e2 poly onto e1 poly and delete pointers to e2 ... //join e2 poly onto e1 poly and delete pointers to e2 ...
if( e1->side == esLeft ) if( e1->side == esLeft )
skipping to change at line 2522 skipping to change at line 2539
else else
e = eNext; e = eNext;
} }
if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0; if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0;
else break; else break;
} }
m_SortedEdges = 0; m_SortedEdges = 0;
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
bool Process1Before2(IntersectNode &node1, IntersectNode &node2) bool ProcessParam1BeforeParam2(IntersectNode &node1, IntersectNode &node2)
{ {
bool result; bool result;
if (node1.pt.Y == node2.pt.Y) if (node1.pt.Y == node2.pt.Y)
{ {
if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1) if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1)
{ {
result = node2.pt.X > node1.pt.X; result = node2.pt.X > node1.pt.X;
return node2.edge1->dx > 0 ? !result : result; return node2.edge1->dx > 0 ? !result : result;
} }
else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2) else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2)
skipping to change at line 2551 skipping to change at line 2568
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt) void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
{ {
IntersectNode* newNode = new IntersectNode; IntersectNode* newNode = new IntersectNode;
newNode->edge1 = e1; newNode->edge1 = e1;
newNode->edge2 = e2; newNode->edge2 = e2;
newNode->pt = pt; newNode->pt = pt;
newNode->next = 0; newNode->next = 0;
if( !m_IntersectNodes ) m_IntersectNodes = newNode; if( !m_IntersectNodes ) m_IntersectNodes = newNode;
else if( Process1Before2(*newNode, *m_IntersectNodes) ) else if( ProcessParam1BeforeParam2(*newNode, *m_IntersectNodes) )
{ {
newNode->next = m_IntersectNodes; newNode->next = m_IntersectNodes;
m_IntersectNodes = newNode; m_IntersectNodes = newNode;
} }
else else
{ {
IntersectNode* iNode = m_IntersectNodes; IntersectNode* iNode = m_IntersectNodes;
while( iNode->next && Process1Before2(*iNode->next, *newNode) ) while( iNode->next && ProcessParam1BeforeParam2(*iNode->next, *newNode ) )
iNode = iNode->next; iNode = iNode->next;
newNode->next = iNode->next; newNode->next = iNode->next;
iNode->next = newNode; iNode->next = newNode;
} }
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
void Clipper::ProcessIntersectList() void Clipper::ProcessIntersectList()
{ {
while( m_IntersectNodes ) while( m_IntersectNodes )
skipping to change at line 3100 skipping to change at line 3117
{ {
JoinRec* j2 = m_Joins[k]; JoinRec* j2 = m_Joins[k];
if (j2->poly1Idx == ObsoleteIdx) j2->poly1Idx = OKIdx; if (j2->poly1Idx == ObsoleteIdx) j2->poly1Idx = OKIdx;
if (j2->poly2Idx == ObsoleteIdx) j2->poly2Idx = OKIdx; if (j2->poly2Idx == ObsoleteIdx) j2->poly2Idx = OKIdx;
} }
} }
} }
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
void ReversePoints(Polygon& p) void ReversePolygons(Polygon& p)
{ {
std::reverse(p.begin(), p.end()); std::reverse(p.begin(), p.end());
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
void ReversePoints(Polygons& p) void ReversePolygons(Polygons& p)
{ {
for (Polygons::size_type i = 0; i < p.size(); ++i) for (Polygons::size_type i = 0; i < p.size(); ++i)
ReversePoints(p[i]); ReversePolygons(p[i]);
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
// OffsetPolygon functions ... // OffsetPolygon functions ...
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
struct DoublePoint struct DoublePoint
{ {
double X; double X;
double Y; double Y;
skipping to change at line 3261 skipping to change at line 3278
Polygon outer(4); Polygon outer(4);
outer[0] = IntPoint(r.left - 10, r.bottom + 10); outer[0] = IntPoint(r.left - 10, r.bottom + 10);
outer[1] = IntPoint(r.right + 10, r.bottom + 10); outer[1] = IntPoint(r.right + 10, r.bottom + 10);
outer[2] = IntPoint(r.right + 10, r.top - 10); outer[2] = IntPoint(r.right + 10, r.top - 10);
outer[3] = IntPoint(r.left - 10, r.top - 10); outer[3] = IntPoint(r.left - 10, r.top - 10);
clpr.AddPolygon(outer, ptSubject); clpr.AddPolygon(outer, ptSubject);
if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative)) if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative))
{ {
out_polys.erase(out_polys.begin()); out_polys.erase(out_polys.begin());
ReversePoints(out_polys); ReversePolygons(out_polys);
} else } else
out_polys.clear(); out_polys.clear();
} }
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
private: private:
void AddPoint(const IntPoint& pt) void AddPoint(const IntPoint& pt)
skipping to change at line 3291 skipping to change at line 3308
{ {
IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
(long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); (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), 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)); (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 * no rmals[m_k].Y; double sinAngle = normals[m_k].X * normals[m_j].Y - normals[m_j].X * no rmals[m_k].Y;
if (sinAngle * m_delta >= 0) if (sinAngle * m_delta >= 0)
{ {
//occasionally (due to floating point math) sinAngle can be > 1 so .. . //occasionally (due to floating point math) sinAngle can be > 1 so .. .
if (sinAngle > 1) sinAngle = 1; else if (sinAngle < -1) sinAngle = -1 ; if (sinAngle > 1) sinAngle = 1; else if (sinAngle < -1) sinAngle = -1 ;
double dx = tan((pi - asin(sinAngle))/4) * abs(m_delta*mul); double dx = std::tan((pi - std::asin(sinAngle))/4) * std::abs(m_delta *mul);
pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx), pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
(long64)(pt1.Y + normals[m_k].X * dx)); (long64)(pt1.Y + normals[m_k].X * dx));
AddPoint(pt1); AddPoint(pt1);
pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx), pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx),
(long64)(pt2.Y -normals[m_j].X * dx)); (long64)(pt2.Y -normals[m_j].X * dx));
AddPoint(pt2); AddPoint(pt2);
} }
else else
{ {
AddPoint(pt1); AddPoint(pt1);
skipping to change at line 3374 skipping to change at line 3391
{ {
if (&out_polys == &in_polys) if (&out_polys == &in_polys)
{ {
Polygons poly2(in_polys); Polygons poly2(in_polys);
PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit); PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit);
} }
else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit); else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit);
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys) void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillT ype fillType)
{ {
Clipper c; Clipper c;
c.AddPolygon(in_poly, ptSubject); 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, PolyFi llType fillType)
{ {
Clipper c; Clipper c;
c.AddPolygons(in_polys, ptSubject); 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);
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
std::ostream& operator <<(std::ostream &s, IntPoint& p) std::ostream& operator <<(std::ostream &s, IntPoint& p)
{ {
s << p.X << ' ' << p.Y << "\n"; s << p.X << ' ' << p.Y << "\n";
return s; return s;
} }
//------------------------------------------------------------------------- ----- //------------------------------------------------------------------------- -----
 End of changes. 23 change blocks. 
26 lines changed or deleted 44 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/