Permalink
Browse files

clipper update to 5.1.3-svn

  • Loading branch information...
1 parent 785dee4 commit 3062fc34ff2e88bd74de437524886c4420e1b9f6 @hurzl hurzl committed Mar 1, 2013
@@ -1,6 +1,14 @@
============================================================
Clipper Change Log
============================================================
+
+v5.1.2 (26 February 2013)
+* Bugfix: PolyNode class was missing a constructor.
+* Update: The MiterLimit parameter in the OffsetPolygons
+ function has been renamed Limit and can now also be used to
+ limit the number of vertices used to construct arcs when
+ JoinType is set to jtRound.
+
v5.1.0 (17 February 2013)
* Update: ExPolygons has been replaced with the PolyTree &
PolyNode classes to more fully represent the parent-child
@@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
-* Version : 5.1.0 *
-* Date : 1 February 2013 *
+* Version : 5.1.3 *
+* Date : 27 February 2013 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2013 *
* *
@@ -77,7 +77,7 @@ void PolyTree::Clear()
}
//------------------------------------------------------------------------------
-PolyNode* PolyTree::GetFirst()
+PolyNode* PolyTree::GetFirst() const
{
if (Childs.size() > 0)
return Childs[0];
@@ -86,7 +86,7 @@ PolyNode* PolyTree::GetFirst()
}
//------------------------------------------------------------------------------
-int PolyTree::Total()
+int PolyTree::Total() const
{
return AllNodes.size();
}
@@ -95,8 +95,12 @@ int PolyTree::Total()
// PolyNode methods ...
//------------------------------------------------------------------------------
+PolyNode::PolyNode(): Childs(), Parent(0), Index(0)
+{
+}
+//------------------------------------------------------------------------------
-int PolyNode::ChildCount()
+int PolyNode::ChildCount() const
{
return Childs.size();
}
@@ -111,16 +115,16 @@ void PolyNode::AddChild(PolyNode& child)
}
//------------------------------------------------------------------------------
-PolyNode* PolyNode::GetNext()
+PolyNode* PolyNode::GetNext() const
{
if (Childs.size() > 0)
return Childs[0];
else
- return GetNextSiblingUp();
+ return GetNextSiblingUp();
}
//------------------------------------------------------------------------------
-PolyNode* PolyNode::GetNextSiblingUp()
+PolyNode* PolyNode::GetNextSiblingUp() const
{
if (!Parent) //protects against PolyTree.GetNextSiblingUp()
return 0;
@@ -131,7 +135,7 @@ PolyNode* PolyNode::GetNextSiblingUp()
}
//------------------------------------------------------------------------------
-bool PolyNode::IsHole()
+bool PolyNode::IsHole() const
{
bool result = true;
PolyNode* node = Parent;
@@ -749,16 +753,17 @@ OutPt* GetBottomPt(OutPt *pp)
}
//------------------------------------------------------------------------------
-bool FindSegment(OutPt* &pp, IntPoint &pt1, IntPoint &pt2)
+bool FindSegment(OutPt* &pp, bool UseFullInt64Range,
+ IntPoint &pt1, IntPoint &pt2)
{
//outPt1 & outPt2 => the overlap segment (if the function returns true)
if (!pp) return false;
OutPt* pp2 = pp;
IntPoint pt1a = pt1, pt2a = pt2;
do
{
- if (SlopesEqual(pt1a, pt2a, pp->pt, pp->prev->pt, true) &&
- SlopesEqual(pt1a, pt2a, pp->pt, true) &&
+ if (SlopesEqual(pt1a, pt2a, pp->pt, pp->prev->pt, UseFullInt64Range) &&
+ SlopesEqual(pt1a, pt2a, pp->pt, UseFullInt64Range) &&
GetOverlapSegment(pt1a, pt2a, pp->pt, pp->prev->pt, pt1, pt2))
return true;
pp = pp->next;
@@ -1756,17 +1761,11 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
}
else if ( e1Contributing )
{
- if ((e2Wc == 0 || e2Wc == 1) &&
- (m_ClipType != ctIntersection ||
- e2->polyType == ptSubject || (e2->windCnt2 != 0)))
- DoEdge1(e1, e2, pt);
+ if (e2Wc == 0 || e2Wc == 1) DoEdge1(e1, e2, pt);
}
else if ( e2contributing )
{
- if ((e1Wc == 0 || e1Wc == 1) &&
- (m_ClipType != ctIntersection ||
- e1->polyType == ptSubject || (e1->windCnt2 != 0)))
- DoEdge2(e1, e2, pt);
+ if (e1Wc == 0 || e1Wc == 1) DoEdge2(e1, e2, pt);
}
else if ( (e1Wc == 0 || e1Wc == 1) &&
(e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
@@ -2202,8 +2201,8 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge)
TEdge* eNext = GetNextInAEL( e, dir );
if (eMaxPair ||
- ((dir == dLeftToRight) && (e->xcurr <= horzRight)) ||
- ((dir == dRightToLeft) && (e->xcurr >= horzLeft)))
+ ((dir == dLeftToRight) && (e->xcurr < horzRight)) ||
+ ((dir == dRightToLeft) && (e->xcurr > horzLeft)))
{
//ok, so far it looks like we're still in range of the horizontal edge
if ( e->xcurr == horzEdge->xtop && !eMaxPair )
@@ -2306,7 +2305,7 @@ bool Clipper::ProcessIntersections(const long64 botY, const long64 topY)
try {
BuildIntersectList(botY, topY);
if ( !m_IntersectNodes) return true;
- if ( FixupIntersections() ) ProcessIntersectList();
+ if ( FixupIntersectionOrder() ) ProcessIntersectList();
else return false;
}
catch(...) {
@@ -2447,7 +2446,7 @@ void Clipper::DoMaxima(TEdge *e, long64 topY)
if (!eNext) throw clipperException("DoMaxima error");
IntersectEdges( e, eNext, IntPoint(X, topY), ipBoth );
SwapPositionsInAEL(e, eNext);
- eNext = eNext->nextInAEL;
+ eNext = e->nextInAEL;
}
if( e->outIdx < 0 && eMaxPair->outIdx < 0 )
{
@@ -2688,7 +2687,7 @@ void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2)
}
//------------------------------------------------------------------------------
-bool Clipper::FixupIntersections()
+bool Clipper::FixupIntersectionOrder()
{
if ( !m_IntersectNodes->next ) return true;
@@ -2703,8 +2702,8 @@ bool Clipper::FixupIntersections()
else if (e1->nextInSEL == int1->edge2) e2 = e1->nextInSEL;
else
{
- //The current intersection is out of order, so try and swap it with
- //a subsequent intersection ...
+ //The current intersection (Int1) is out of order (since it doesn't
+ //contain adjacent edges), so swap it with a subsequent intersection ...
while (int2)
{
if (int2->edge1->nextInSEL == int2->edge2 ||
@@ -2713,7 +2712,8 @@ bool Clipper::FixupIntersections()
}
if ( !int2 ) return false; //oops!!!
- //found an intersect node that can be swapped ...
+ //found an intersect node (Int2) that does contain adjacent edges,
+ //so prepare to process it before Int1 ...
SwapIntersectNodes(*int1, *int2);
e1 = int1->edge1;
e2 = int1->edge2;
@@ -2797,15 +2797,16 @@ bool Clipper::JoinPoints(const JoinRec *j, OutPt *&p1, OutPt *&p2)
OutPt *pp2a = outRec2->pts;
IntPoint pt1 = j->pt2a, pt2 = j->pt2b;
IntPoint pt3 = j->pt1a, pt4 = j->pt1b;
- if (!FindSegment(pp1a, pt1, pt2)) return false;
+ if (!FindSegment(pp1a, m_UseFullRange, 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)) return false;
+ if (!FindSegment(pp2a, m_UseFullRange, pt3, pt4) || (pp2a == pp1a))
+ return false;
}
- else if (!FindSegment(pp2a, pt3, pt4)) return false;
+ else if (!FindSegment(pp2a, m_UseFullRange, pt3, pt4)) return false;
if (!GetOverlapSegment(pt1, pt2, pt3, pt4, pt1, pt2)) return false;
@@ -3067,19 +3068,26 @@ struct DoublePoint
//------------------------------------------------------------------------------
Polygon BuildArc(const IntPoint &pt,
- const double a1, const double a2, const double r)
-{
- long64 steps = std::max(6, int(std::sqrt(std::fabs(r)) * std::fabs(a2 - a1)));
- if (steps > 0x100) steps = 0x100;
- int n = (unsigned)steps;
- Polygon result(n);
- double da = (a2 - a1) / (n -1);
- double a = a1;
- for (int i = 0; i < n; ++i)
- {
- result[i].X = pt.X + Round(std::cos(a)*r);
- result[i].Y = pt.Y + Round(std::sin(a)*r);
- a += da;
+ const double a1, const double a2, const double r, double limit)
+{
+ //see notes in clipper.pas regarding steps
+ double arcFrac = std::fabs(a2 - a1) / (2 * pi);
+ int steps = (int)(arcFrac * pi / std::acos(1 - limit / std::fabs(r)));
+ if (steps < 2) steps = 2;
+ else if (steps > (int)(222.0 * arcFrac)) steps = (int)(222.0 * arcFrac);
+
+ double x = std::cos(a1);
+ double y = std::sin(a1);
+ double c = std::cos((a2 - a1) / steps);
+ double s = std::sin((a2 - a1) / steps);
+ Polygon result(steps +1);
+ for (int i = 0; i <= steps; ++i)
+ {
+ result[i].X = pt.X + Round(x * r);
+ result[i].Y = pt.Y + Round(y * r);
+ double x2 = x;
+ x = x * c - s * y; //cross product
+ y = x2 * s + y * c; //dot product
}
return result;
}
@@ -3115,7 +3123,7 @@ class PolyOffsetBuilder
public:
PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
- double delta, JoinType jointype, double MiterLimit, bool AutoFix)
+ double delta, JoinType jointype, double limit, bool autoFix)
{
//nb precondition - out_polys != ptsin_polys
if (NEAR_ZERO(delta))
@@ -3131,7 +3139,7 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
//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 (AutoFix)
+ if (autoFix)
{
size_t Len = m_p.size(), botI = 0;
while (botI < Len && m_p[botI].size() == 0) botI++;
@@ -3162,8 +3170,19 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
ReversePolygons(m_p);
}
- if (MiterLimit <= 1) MiterLimit = 1;
- m_RMin = 2.0/(MiterLimit*MiterLimit);
+ switch (jointype)
+ {
+ case jtRound: //limit defaults to 0.125
+ if (limit <= 0) limit = 0.125;
+ else if (limit > std::fabs(delta)) limit = std::fabs(delta);
+ break;
+ case jtMiter: //limit defaults to twice delta's width ...
+ if (limit < 2) limit = 2;
+ break;
+ default: //otherwise limit is unused
+ limit = 1;
+ }
+ m_RMin = 2.0/(limit*limit);
double deltaSq = delta*delta;
out_polys.clear();
@@ -3186,7 +3205,7 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
else if (len == 1)
{
Polygon arc;
- arc = BuildArc(m_p[m_i][len-1], 0, 2 * pi, delta);
+ arc = BuildArc(m_p[m_i][len-1], 0, 2 * pi, delta, limit);
out_polys[m_i] = arc;
continue;
}
@@ -3207,11 +3226,11 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
{
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);
+ if (m_R >= m_RMin) DoMiter(); else DoSquare(limit);
break;
}
- case jtSquare: DoSquare(); break;
- case jtRound: DoRound(); break;
+ case jtSquare: DoSquare(1.0); break;
+ case jtRound: DoRound(limit); break;
}
m_k = m_j;
}
@@ -3257,7 +3276,7 @@ void AddPoint(const IntPoint& pt)
}
//------------------------------------------------------------------------------
-void DoSquare(double mul = 1.0)
+void DoSquare(double mul)
{
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));
@@ -3308,7 +3327,7 @@ void DoMiter()
}
//------------------------------------------------------------------------------
-void DoRound()
+void DoRound(double limit)
{
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));
@@ -3324,7 +3343,7 @@ void DoRound()
double a2 = std::atan2(normals[m_j].Y, normals[m_j].X);
if (m_delta > 0 && a2 < a1) a2 += pi *2;
else if (m_delta < 0 && a2 > a1) a2 -= pi *2;
- Polygon arc = BuildArc(m_p[m_i][m_j], a1, a2, m_delta);
+ Polygon arc = BuildArc(m_p[m_i][m_j], a1, a2, m_delta, limit);
for (Polygon::size_type m = 0; m < arc.size(); m++)
AddPoint(arc[m]);
}
@@ -3352,14 +3371,14 @@ bool UpdateBotPt(const IntPoint &pt, IntPoint &botPt)
//------------------------------------------------------------------------------
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
- double delta, JoinType jointype, double MiterLimit, bool AutoFix)
+ double delta, JoinType jointype, double limit, bool autoFix)
{
if (&out_polys == &in_polys)
{
Polygons poly2(in_polys);
- PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit, AutoFix);
+ PolyOffsetBuilder(poly2, out_polys, delta, jointype, limit, autoFix);
}
- else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit, AutoFix);
+ else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, limit, autoFix);
}
//------------------------------------------------------------------------------
Oops, something went wrong.

0 comments on commit 3062fc3

Please sign in to comment.