зеркало из https://github.com/SixLabors/Shapes.git
move more methods
This commit is contained in:
Родитель
d94db3503b
Коммит
734d97031f
|
@ -17,17 +17,6 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// </summary>
|
||||
public class Clipper
|
||||
{
|
||||
/// <summary>
|
||||
/// The unassigned
|
||||
/// </summary>
|
||||
internal const int Unassigned = -1; // InitOptions that can be passed to the constructor ...
|
||||
|
||||
/// <summary>
|
||||
/// The skip
|
||||
/// </summary>
|
||||
internal const int Skip = -2;
|
||||
|
||||
private const double HorizontalDeltaLimit = -3.4E+38;
|
||||
private static readonly IComparer<IntersectNode> IntersectNodeComparer = new IntersectNodeSort();
|
||||
private readonly List<IntersectNode> intersectList = new List<IntersectNode>();
|
||||
|
||||
|
@ -220,7 +209,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
continue;
|
||||
}
|
||||
|
||||
if (VectorHelpers.SlopesEqual(edge.PreviousEdge.Current, edge.Current, edge.NextEdge.Current))
|
||||
if (Helpers.SlopesEqual(edge.PreviousEdge.Current, edge.Current, edge.NextEdge.Current))
|
||||
{
|
||||
// Collinear edges are allowed for open paths but in closed paths
|
||||
// the default is to merge adjacent collinear edges into a single edge.
|
||||
|
@ -329,22 +318,22 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
locMin.RightBound.WindingDelta = -locMin.LeftBound.WindingDelta;
|
||||
|
||||
edge = this.ProcessBound(locMin.LeftBound, leftBoundIsForward);
|
||||
if (edge.OutIndex == Skip)
|
||||
if (edge.OutIndex == Constants.Skip)
|
||||
{
|
||||
edge = this.ProcessBound(edge, leftBoundIsForward);
|
||||
}
|
||||
|
||||
Edge edge2 = this.ProcessBound(locMin.RightBound, !leftBoundIsForward);
|
||||
if (edge2.OutIndex == Skip)
|
||||
if (edge2.OutIndex == Constants.Skip)
|
||||
{
|
||||
edge2 = this.ProcessBound(edge2, !leftBoundIsForward);
|
||||
}
|
||||
|
||||
if (locMin.LeftBound.OutIndex == Skip)
|
||||
if (locMin.LeftBound.OutIndex == Constants.Skip)
|
||||
{
|
||||
locMin.LeftBound = null;
|
||||
}
|
||||
else if (locMin.RightBound.OutIndex == Skip)
|
||||
else if (locMin.RightBound.OutIndex == Constants.Skip)
|
||||
{
|
||||
locMin.RightBound = null;
|
||||
}
|
||||
|
@ -360,21 +349,6 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
}
|
||||
|
||||
private static float Round(double value)
|
||||
{
|
||||
return value < 0 ? (float)(value - 0.5) : (float)(value + 0.5);
|
||||
}
|
||||
|
||||
private static float TopX(Edge edge, float currentY)
|
||||
{
|
||||
if (currentY == edge.Top.Y)
|
||||
{
|
||||
return edge.Top.X;
|
||||
}
|
||||
|
||||
return edge.Bottom.X + Round(edge.Dx * (currentY - edge.Bottom.Y));
|
||||
}
|
||||
|
||||
private static void FixHoleLinkage(OutRec outRec)
|
||||
{
|
||||
// skip if an outermost polygon or
|
||||
|
@ -394,100 +368,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
outRec.FirstLeft = orfl;
|
||||
}
|
||||
|
||||
// See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
|
||||
// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
|
||||
private static int PointInPolygon(Vector2 pt, OutPoint op)
|
||||
{
|
||||
// returns 0 if false, +1 if true, -1 if pt ON polygon boundary
|
||||
int result = 0;
|
||||
OutPoint startOp = op;
|
||||
float ptx = pt.X;
|
||||
float pty = pt.Y;
|
||||
float poly0x = op.Point.X;
|
||||
float poly0y = op.Point.Y;
|
||||
do
|
||||
{
|
||||
op = op.Next;
|
||||
float poly1x = op.Point.X;
|
||||
float poly1y = op.Point.Y;
|
||||
|
||||
if (poly1y == pty)
|
||||
{
|
||||
if ((poly1x == ptx) || (poly0y == pty &&
|
||||
((poly1x > ptx) == (poly0x < ptx))))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((poly0y < pty) != (poly1y < pty))
|
||||
{
|
||||
if (poly0x >= ptx)
|
||||
{
|
||||
if (poly1x > ptx)
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
else
|
||||
{
|
||||
double d = (double)((poly0x - ptx) * (poly1y - pty)) -
|
||||
(double)((poly1x - ptx) * (poly0y - pty));
|
||||
if (d == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((d > 0) == (poly1y > poly0y))
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (poly1x > ptx)
|
||||
{
|
||||
double d = (double)((poly0x - ptx) * (poly1y - pty)) - (double)((poly1x - ptx) * (poly0y - pty));
|
||||
if (d == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((d > 0) == (poly1y > poly0y))
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
poly0x = poly1x;
|
||||
poly0y = poly1y;
|
||||
}
|
||||
while (startOp != op);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool Poly2ContainsPoly1(OutPoint outPt1, OutPoint outPt2)
|
||||
{
|
||||
OutPoint op = outPt1;
|
||||
do
|
||||
{
|
||||
// nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
|
||||
int res = PointInPolygon(op.Point, outPt2);
|
||||
if (res >= 0)
|
||||
{
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
op = op.Next;
|
||||
}
|
||||
while (op != outPt1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static void SwapSides(Edge edge1, Edge edge2)
|
||||
{
|
||||
EdgeSide side = edge1.Side;
|
||||
|
@ -502,17 +383,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
edge2.OutIndex = outIdx;
|
||||
}
|
||||
|
||||
private static double GetDx(Vector2 pt1, Vector2 pt2)
|
||||
{
|
||||
if (pt1.Y == pt2.Y)
|
||||
{
|
||||
return HorizontalDeltaLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool HorizontalSegmentsOverlap(float seg1a, float seg1b, float seg2a, float seg2b)
|
||||
{
|
||||
|
@ -539,18 +410,18 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
edge = edge.NextEdge;
|
||||
}
|
||||
|
||||
if (edge.Dx != HorizontalDeltaLimit && edge.PreviousEdge.Dx != HorizontalDeltaLimit)
|
||||
if (edge.Dx != Constants.HorizontalDeltaLimit && edge.PreviousEdge.Dx != Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while (edge.PreviousEdge.Dx == HorizontalDeltaLimit)
|
||||
while (edge.PreviousEdge.Dx == Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
edge = edge.PreviousEdge;
|
||||
}
|
||||
|
||||
edge2 = edge;
|
||||
while (edge.Dx == HorizontalDeltaLimit)
|
||||
while (edge.Dx == Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
edge = edge.NextEdge;
|
||||
}
|
||||
|
@ -777,7 +648,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
if (lb.OutIndex >= 0 && lb.PreviousInAEL != null &&
|
||||
lb.PreviousInAEL.Current.X == lb.Bottom.X &&
|
||||
lb.PreviousInAEL.OutIndex >= 0 &&
|
||||
VectorHelpers.SlopesEqual(lb.PreviousInAEL.Current, lb.PreviousInAEL.Top, lb.Current, lb.Top) &&
|
||||
Helpers.SlopesEqual(lb.PreviousInAEL.Current, lb.PreviousInAEL.Top, lb.Current, lb.Top) &&
|
||||
lb.WindingDelta != 0 && lb.PreviousInAEL.WindingDelta != 0)
|
||||
{
|
||||
OutPoint op2 = this.AddOutPt(lb.PreviousInAEL, lb.Bottom);
|
||||
|
@ -787,7 +658,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
if (lb.NextInAEL != rb)
|
||||
{
|
||||
if (rb.OutIndex >= 0 && rb.PreviousInAEL.OutIndex >= 0 &&
|
||||
VectorHelpers.SlopesEqual(rb.PreviousInAEL.Current, rb.PreviousInAEL.Top, rb.Current, rb.Top) &&
|
||||
Helpers.SlopesEqual(rb.PreviousInAEL.Current, rb.PreviousInAEL.Top, rb.Current, rb.Top) &&
|
||||
rb.WindingDelta != 0 && rb.PreviousInAEL.WindingDelta != 0)
|
||||
{
|
||||
OutPoint op2 = this.AddOutPt(rb.PreviousInAEL, rb.Bottom);
|
||||
|
@ -854,11 +725,11 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
{
|
||||
if (e2.Top.Y > e1.Top.Y)
|
||||
{
|
||||
return e2.Top.X < TopX(e1, e2.Top.Y);
|
||||
return e2.Top.X < e1.TopX(e2.Top.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
return e1.Top.X > TopX(e2, e1.Top.Y);
|
||||
return e1.Top.X > e2.TopX(e1.Top.Y);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1109,8 +980,8 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
if (e1.OutIndex == e2.OutIndex)
|
||||
{
|
||||
e1.OutIndex = Unassigned;
|
||||
e2.OutIndex = Unassigned;
|
||||
e1.OutIndex = Constants.Unassigned;
|
||||
e2.OutIndex = Constants.Unassigned;
|
||||
}
|
||||
else if (e1.OutIndex < e2.OutIndex)
|
||||
{
|
||||
|
@ -1161,12 +1032,12 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
if (prevE != null && prevE.OutIndex >= 0)
|
||||
{
|
||||
float xPrev = TopX(prevE, pt.Y);
|
||||
float xE = TopX(e, pt.Y);
|
||||
float xPrev = prevE.TopX(pt.Y);
|
||||
float xE = e.TopX(pt.Y);
|
||||
if ((xPrev == xE) &&
|
||||
(e.WindingDelta != 0) &&
|
||||
(prevE.WindingDelta != 0) &&
|
||||
VectorHelpers.SlopesEqual(new Vector2(xPrev, pt.Y), prevE.Top, new Vector2(xE, pt.Y), e.Top))
|
||||
Helpers.SlopesEqual(new Vector2(xPrev, pt.Y), prevE.Top, new Vector2(xE, pt.Y), e.Top))
|
||||
{
|
||||
OutPoint outPt = this.AddOutPt(prevE, pt);
|
||||
this.AddJoin(result, outPt, e.Top);
|
||||
|
@ -1282,148 +1153,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
}
|
||||
|
||||
private bool FirstIsBottomPt(OutPoint btmPt1, OutPoint btmPt2)
|
||||
{
|
||||
OutPoint p = btmPt1.Previous;
|
||||
while ((p.Point == btmPt1.Point) && (p != btmPt1))
|
||||
{
|
||||
p = p.Previous;
|
||||
}
|
||||
|
||||
double dx1p = Math.Abs(GetDx(btmPt1.Point, p.Point));
|
||||
p = btmPt1.Next;
|
||||
while ((p.Point == btmPt1.Point) && (p != btmPt1))
|
||||
{
|
||||
p = p.Next;
|
||||
}
|
||||
|
||||
double dx1n = Math.Abs(GetDx(btmPt1.Point, p.Point));
|
||||
|
||||
p = btmPt2.Previous;
|
||||
while ((p.Point == btmPt2.Point) && (p != btmPt2))
|
||||
{
|
||||
p = p.Previous;
|
||||
}
|
||||
|
||||
double dx2p = Math.Abs(GetDx(btmPt2.Point, p.Point));
|
||||
p = btmPt2.Next;
|
||||
while ((p.Point == btmPt2.Point) && (p != btmPt2))
|
||||
{
|
||||
p = p.Next;
|
||||
}
|
||||
|
||||
double dx2n = Math.Abs(GetDx(btmPt2.Point, p.Point));
|
||||
|
||||
if (Math.Max(dx1p, dx1n) == Math.Max(dx2p, dx2n) &&
|
||||
Math.Min(dx1p, dx1n) == Math.Min(dx2p, dx2n))
|
||||
{
|
||||
return this.Area(btmPt1) > 0; // if otherwise identical use orientation
|
||||
}
|
||||
else
|
||||
{
|
||||
return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
|
||||
}
|
||||
}
|
||||
|
||||
private OutPoint GetBottomPt(OutPoint pp)
|
||||
{
|
||||
OutPoint dups = null;
|
||||
OutPoint p = pp.Next;
|
||||
while (p != pp)
|
||||
{
|
||||
if (p.Point.Y > pp.Point.Y)
|
||||
{
|
||||
pp = p;
|
||||
dups = null;
|
||||
}
|
||||
else if (p.Point.Y == pp.Point.Y && p.Point.X <= pp.Point.X)
|
||||
{
|
||||
if (p.Point.X < pp.Point.X)
|
||||
{
|
||||
dups = null;
|
||||
pp = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p.Next != pp && p.Previous != pp)
|
||||
{
|
||||
dups = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p = p.Next;
|
||||
}
|
||||
|
||||
if (dups != null)
|
||||
{
|
||||
// there appears to be at least 2 vertices at bottomPt so ...
|
||||
while (dups != p)
|
||||
{
|
||||
if (!this.FirstIsBottomPt(p, dups))
|
||||
{
|
||||
pp = dups;
|
||||
}
|
||||
|
||||
dups = dups.Next;
|
||||
while (dups.Point != pp.Point)
|
||||
{
|
||||
dups = dups.Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
||||
private OutRec GetLowermostRec(OutRec outRec1, OutRec outRec2)
|
||||
{
|
||||
// work out which polygon fragment has the correct hole state ...
|
||||
if (outRec1.BottomPoint == null)
|
||||
{
|
||||
outRec1.BottomPoint = this.GetBottomPt(outRec1.Points);
|
||||
}
|
||||
|
||||
if (outRec2.BottomPoint == null)
|
||||
{
|
||||
outRec2.BottomPoint = this.GetBottomPt(outRec2.Points);
|
||||
}
|
||||
|
||||
OutPoint bPt1 = outRec1.BottomPoint;
|
||||
OutPoint bPt2 = outRec2.BottomPoint;
|
||||
if (bPt1.Point.Y > bPt2.Point.Y)
|
||||
{
|
||||
return outRec1;
|
||||
}
|
||||
else if (bPt1.Point.Y < bPt2.Point.Y)
|
||||
{
|
||||
return outRec2;
|
||||
}
|
||||
else if (bPt1.Point.X < bPt2.Point.X)
|
||||
{
|
||||
return outRec1;
|
||||
}
|
||||
else if (bPt1.Point.X > bPt2.Point.X)
|
||||
{
|
||||
return outRec2;
|
||||
}
|
||||
else if (bPt1.Next == bPt1)
|
||||
{
|
||||
return outRec2;
|
||||
}
|
||||
else if (bPt2.Next == bPt2)
|
||||
{
|
||||
return outRec1;
|
||||
}
|
||||
else if (this.FirstIsBottomPt(bPt1, bPt2))
|
||||
{
|
||||
return outRec1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return outRec2;
|
||||
}
|
||||
}
|
||||
|
||||
private bool OutRec1RightOfOutRec2(OutRec outRec1, OutRec outRec2)
|
||||
{
|
||||
|
@ -1467,7 +1197,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
else
|
||||
{
|
||||
holeStateRec = this.GetLowermostRec(outRec1, outRec2);
|
||||
holeStateRec = OutRec.GetLowermostRec(outRec1, outRec2);
|
||||
}
|
||||
|
||||
// get the start and ends of both output polygons and
|
||||
|
@ -1540,8 +1270,8 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
int okIdx = e1.OutIndex;
|
||||
int obsoleteIdx = e2.OutIndex;
|
||||
|
||||
e1.OutIndex = Unassigned; // nb: safe because we only get here via AddLocalMaxPoly
|
||||
e2.OutIndex = Unassigned;
|
||||
e1.OutIndex = Constants.Unassigned; // nb: safe because we only get here via AddLocalMaxPoly
|
||||
e2.OutIndex = Constants.Unassigned;
|
||||
|
||||
Edge e = this.activeEdges;
|
||||
while (e != null)
|
||||
|
@ -1967,7 +1697,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
{
|
||||
e.PreviousInSEL = e.PreviousInAEL;
|
||||
e.NextInSEL = e.NextInAEL;
|
||||
e.Current = new Vector2(TopX(e, topY), e.Current.Y);
|
||||
e.Current = new Vector2(e.TopX(topY), e.Current.Y);
|
||||
e = e.NextInAEL;
|
||||
}
|
||||
|
||||
|
@ -1986,7 +1716,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
this.IntersectPoint(e, nextEdge, out pt);
|
||||
if (pt.Y < topY)
|
||||
{
|
||||
pt = new Vector2(TopX(e, topY), topY);
|
||||
pt = new Vector2(e.TopX(topY), topY);
|
||||
}
|
||||
|
||||
IntersectNode newNode = new IntersectNode();
|
||||
|
@ -2082,7 +1812,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
if (edge1.Dx == edge2.Dx)
|
||||
{
|
||||
ip.Y = edge1.Current.Y;
|
||||
ip.X = TopX(edge1, ip.Y);
|
||||
ip.X = edge1.TopX(ip.Y);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2096,7 +1826,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
else
|
||||
{
|
||||
b2 = edge2.Bottom.Y - (edge2.Bottom.X / edge2.Dx);
|
||||
ip.Y = Round((ip.X / edge2.Dx) + b2);
|
||||
ip.Y = Helpers.Round((ip.X / edge2.Dx) + b2);
|
||||
}
|
||||
}
|
||||
else if (edge2.Delta.X == 0)
|
||||
|
@ -2109,7 +1839,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
else
|
||||
{
|
||||
b1 = edge1.Bottom.Y - (edge1.Bottom.X / edge1.Dx);
|
||||
ip.Y = Round((ip.X / edge1.Dx) + b1);
|
||||
ip.Y = Helpers.Round((ip.X / edge1.Dx) + b1);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2117,14 +1847,14 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
b1 = edge1.Bottom.X - (edge1.Bottom.Y * edge1.Dx);
|
||||
b2 = edge2.Bottom.X - (edge2.Bottom.Y * edge2.Dx);
|
||||
double q = (b2 - b1) / (edge1.Dx - edge2.Dx);
|
||||
ip.Y = Round(q);
|
||||
ip.Y = Helpers.Round(q);
|
||||
if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx))
|
||||
{
|
||||
ip.X = Round((edge1.Dx * q) + b1);
|
||||
ip.X = Helpers.Round((edge1.Dx * q) + b1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip.X = Round((edge2.Dx * q) + b2);
|
||||
ip.X = Helpers.Round((edge2.Dx * q) + b2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2141,11 +1871,11 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
if (Math.Abs(edge1.Dx) < Math.Abs(edge2.Dx))
|
||||
{
|
||||
ip.X = TopX(edge1, ip.Y);
|
||||
ip.X = edge1.TopX(ip.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip.X = TopX(edge2, ip.Y);
|
||||
ip.X = edge2.TopX(ip.Y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2157,11 +1887,11 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
// better to use the more vertical edge to derive X ...
|
||||
if (Math.Abs(edge1.Dx) > Math.Abs(edge2.Dx))
|
||||
{
|
||||
ip.X = TopX(edge2, ip.Y);
|
||||
ip.X = edge2.TopX(ip.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip.X = TopX(edge1, ip.Y);
|
||||
ip.X = edge1.TopX(ip.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2209,7 +1939,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
else
|
||||
{
|
||||
e.Current = new Vector2(TopX(e, topY), topY);
|
||||
e.Current = new Vector2(e.TopX(topY), topY);
|
||||
}
|
||||
|
||||
e = e.NextInAEL;
|
||||
|
@ -2240,7 +1970,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
if (prevEdge != null && prevEdge.Current.X == e.Bottom.X &&
|
||||
prevEdge.Current.Y == e.Bottom.Y && op != null &&
|
||||
prevEdge.OutIndex >= 0 && prevEdge.Current.Y > prevEdge.Top.Y &&
|
||||
VectorHelpers.SlopesEqual(e.Current, e.Top, prevEdge.Current, prevEdge.Top) &&
|
||||
Helpers.SlopesEqual(e.Current, e.Top, prevEdge.Current, prevEdge.Top) &&
|
||||
(e.WindingDelta != 0) && (prevEdge.WindingDelta != 0))
|
||||
{
|
||||
OutPoint op2 = this.AddOutPt(prevEdge, e.Bottom);
|
||||
|
@ -2249,7 +1979,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
else if (nextEdge != null && nextEdge.Current.X == e.Bottom.X &&
|
||||
nextEdge.Current.Y == e.Bottom.Y && op != null &&
|
||||
nextEdge.OutIndex >= 0 && nextEdge.Current.Y > nextEdge.Top.Y &&
|
||||
VectorHelpers.SlopesEqual(e.Current, e.Top, nextEdge.Current, nextEdge.Top) &&
|
||||
Helpers.SlopesEqual(e.Current, e.Top, nextEdge.Current, nextEdge.Top) &&
|
||||
(e.WindingDelta != 0) && (nextEdge.WindingDelta != 0))
|
||||
{
|
||||
OutPoint op2 = this.AddOutPt(nextEdge, e.Bottom);
|
||||
|
@ -2283,7 +2013,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
nextEdge = e.NextInAEL;
|
||||
}
|
||||
|
||||
if (e.OutIndex == Unassigned && eMaxPair.OutIndex == Unassigned)
|
||||
if (e.OutIndex == Constants.Unassigned && eMaxPair.OutIndex == Constants.Unassigned)
|
||||
{
|
||||
this.DeleteFromAEL(e);
|
||||
this.DeleteFromAEL(eMaxPair);
|
||||
|
@ -2355,29 +2085,6 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
return shapes.ToImmutableArray();
|
||||
}
|
||||
|
||||
private OutPoint DupOutPt(OutPoint outPt, bool insertAfter)
|
||||
{
|
||||
OutPoint result = new OutPoint();
|
||||
result.Point = outPt.Point;
|
||||
result.Index = outPt.Index;
|
||||
if (insertAfter)
|
||||
{
|
||||
result.Next = outPt.Next;
|
||||
result.Previous = outPt;
|
||||
outPt.Next.Previous = result;
|
||||
outPt.Next = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Previous = outPt.Previous;
|
||||
result.Next = outPt;
|
||||
outPt.Previous.Next = result;
|
||||
outPt.Previous = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool GetOverlap(float a1, float a2, float b1, float b2, out float left, out float right)
|
||||
{
|
||||
if (a1 < a2)
|
||||
|
@ -2437,12 +2144,12 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
op1 = op1.Next;
|
||||
}
|
||||
|
||||
op1b = this.DupOutPt(op1, !discardLeft);
|
||||
op1b = op1.Duplicate(!discardLeft);
|
||||
if (op1b.Point != pt)
|
||||
{
|
||||
op1 = op1b;
|
||||
op1.Point = pt;
|
||||
op1b = this.DupOutPt(op1, !discardLeft);
|
||||
op1b = op1.Duplicate(!discardLeft);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2459,12 +2166,12 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
op1 = op1.Next;
|
||||
}
|
||||
|
||||
op1b = this.DupOutPt(op1, discardLeft);
|
||||
op1b = op1.Duplicate(discardLeft);
|
||||
if (op1b.Point != pt)
|
||||
{
|
||||
op1 = op1b;
|
||||
op1.Point = pt;
|
||||
op1b = this.DupOutPt(op1, discardLeft);
|
||||
op1b = op1.Duplicate(discardLeft);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2482,12 +2189,12 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
op2 = op2.Next;
|
||||
}
|
||||
|
||||
op2b = this.DupOutPt(op2, !discardLeft);
|
||||
op2b = op2.Duplicate(!discardLeft);
|
||||
if (op2b.Point != pt)
|
||||
{
|
||||
op2 = op2b;
|
||||
op2.Point = pt;
|
||||
op2b = this.DupOutPt(op2, !discardLeft);
|
||||
op2b = op2.Duplicate(!discardLeft);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2504,12 +2211,12 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
op2 = op2.Next;
|
||||
}
|
||||
|
||||
op2b = this.DupOutPt(op2, discardLeft);
|
||||
op2b = op2.Duplicate(discardLeft);
|
||||
if (op2b.Point != pt)
|
||||
{
|
||||
op2 = op2b;
|
||||
op2.Point = pt;
|
||||
op2b = this.DupOutPt(op2, discardLeft);
|
||||
op2b = op2.Duplicate(discardLeft);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2574,8 +2281,8 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
if (reverse1)
|
||||
{
|
||||
op1b = this.DupOutPt(op1, false);
|
||||
op2b = this.DupOutPt(op2, true);
|
||||
op1b = op1.Duplicate(false);
|
||||
op2b = op2.Duplicate(true);
|
||||
op1.Previous = op2;
|
||||
op2.Next = op1;
|
||||
op1b.Next = op2b;
|
||||
|
@ -2586,8 +2293,8 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
else
|
||||
{
|
||||
op1b = this.DupOutPt(op1, true);
|
||||
op2b = this.DupOutPt(op2, false);
|
||||
op1b = op1.Duplicate(true);
|
||||
op2b = op2.Duplicate(false);
|
||||
op1.Next = op2;
|
||||
op2.Previous = op1;
|
||||
op1b.Previous = op2b;
|
||||
|
@ -2685,7 +2392,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
op1b = op1b.Next;
|
||||
}
|
||||
|
||||
bool reverse1 = (op1b.Point.Y > op1.Point.Y) || !VectorHelpers.SlopesEqual(op1.Point, op1b.Point, j.OffPoint);
|
||||
bool reverse1 = (op1b.Point.Y > op1.Point.Y) || !Helpers.SlopesEqual(op1.Point, op1b.Point, j.OffPoint);
|
||||
if (reverse1)
|
||||
{
|
||||
op1b = op1.Previous;
|
||||
|
@ -2695,7 +2402,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
|
||||
if ((op1b.Point.Y > op1.Point.Y) ||
|
||||
!VectorHelpers.SlopesEqual(op1.Point, op1b.Point, j.OffPoint))
|
||||
!Helpers.SlopesEqual(op1.Point, op1b.Point, j.OffPoint))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2707,7 +2414,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
op2b = op2b.Next;
|
||||
}
|
||||
|
||||
bool reverse2 = (op2b.Point.Y > op2.Point.Y) || !VectorHelpers.SlopesEqual(op2.Point, op2b.Point, j.OffPoint);
|
||||
bool reverse2 = (op2b.Point.Y > op2.Point.Y) || !Helpers.SlopesEqual(op2.Point, op2b.Point, j.OffPoint);
|
||||
if (reverse2)
|
||||
{
|
||||
op2b = op2.Previous;
|
||||
|
@ -2717,7 +2424,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
|
||||
if ((op2b.Point.Y > op2.Point.Y) ||
|
||||
!VectorHelpers.SlopesEqual(op2.Point, op2b.Point, j.OffPoint))
|
||||
!Helpers.SlopesEqual(op2.Point, op2b.Point, j.OffPoint))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2731,8 +2438,8 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
if (reverse1)
|
||||
{
|
||||
op1b = this.DupOutPt(op1, false);
|
||||
op2b = this.DupOutPt(op2, true);
|
||||
op1b = op1.Duplicate(false);
|
||||
op2b = op2.Duplicate(true);
|
||||
op1.Previous = op2;
|
||||
op2.Next = op1;
|
||||
op1b.Next = op2b;
|
||||
|
@ -2743,8 +2450,8 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
else
|
||||
{
|
||||
op1b = this.DupOutPt(op1, true);
|
||||
op2b = this.DupOutPt(op2, false);
|
||||
op1b = op1.Duplicate(true);
|
||||
op2b = op2.Duplicate(false);
|
||||
op1.Next = op2;
|
||||
op2.Previous = op1;
|
||||
op1b.Previous = op2b;
|
||||
|
@ -2763,7 +2470,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
OutRec firstLeft = ParseFirstLeft(outRec.FirstLeft);
|
||||
if (outRec.Points != null && firstLeft == oldOutRec)
|
||||
{
|
||||
if (Poly2ContainsPoly1(outRec.Points, newOutRec.Points))
|
||||
if (newOutRec.Points.Contains(outRec.Points))
|
||||
{
|
||||
outRec.FirstLeft = newOutRec;
|
||||
}
|
||||
|
@ -2791,11 +2498,11 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
continue;
|
||||
}
|
||||
|
||||
if (Poly2ContainsPoly1(outRec.Points, innerOutRec.Points))
|
||||
if (innerOutRec.Points.Contains(outRec.Points))
|
||||
{
|
||||
outRec.FirstLeft = innerOutRec;
|
||||
}
|
||||
else if (Poly2ContainsPoly1(outRec.Points, outerOutRec.Points))
|
||||
else if (outerOutRec.Points.Contains(outRec.Points))
|
||||
{
|
||||
outRec.FirstLeft = outerOutRec;
|
||||
}
|
||||
|
@ -2855,7 +2562,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
else
|
||||
{
|
||||
holeStateRec = this.GetLowermostRec(outRec1, outRec2);
|
||||
holeStateRec = OutRec.GetLowermostRec(outRec1, outRec2);
|
||||
}
|
||||
|
||||
if (!this.JoinPoints(join, outRec1, outRec2))
|
||||
|
@ -2873,16 +2580,16 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
outRec2.Points = join.OutPoint2;
|
||||
|
||||
// update all OutRec2.Pts Idx's ...
|
||||
this.UpdateOutPtIdxs(outRec2);
|
||||
outRec2.SyncroniseOutpointIndexes();
|
||||
|
||||
if (Poly2ContainsPoly1(outRec2.Points, outRec1.Points))
|
||||
if (outRec1.Points.Contains(outRec2.Points))
|
||||
{
|
||||
// outRec1 contains outRec2 ...
|
||||
outRec2.IsHole = !outRec1.IsHole;
|
||||
outRec2.FirstLeft = outRec1;
|
||||
this.FixupFirstLefts2(outRec2, outRec1);
|
||||
}
|
||||
else if (Poly2ContainsPoly1(outRec1.Points, outRec2.Points))
|
||||
else if (outRec2.Points.Contains(outRec1.Points))
|
||||
{
|
||||
// outRec2 contains outRec1 ...
|
||||
outRec2.IsHole = outRec1.IsHole;
|
||||
|
@ -2919,17 +2626,6 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
}
|
||||
|
||||
private void UpdateOutPtIdxs(OutRec outrec)
|
||||
{
|
||||
OutPoint op = outrec.Points;
|
||||
do
|
||||
{
|
||||
op.Index = outrec.Index;
|
||||
op = op.Previous;
|
||||
}
|
||||
while (op != outrec.Points);
|
||||
}
|
||||
|
||||
private void DoSimplePolygons()
|
||||
{
|
||||
int i = 0;
|
||||
|
@ -2961,15 +2657,15 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
outrec.Points = op;
|
||||
OutRec outrec2 = this.CreateOutRec();
|
||||
outrec2.Points = op2;
|
||||
this.UpdateOutPtIdxs(outrec2);
|
||||
if (Poly2ContainsPoly1(outrec2.Points, outrec.Points))
|
||||
outrec2.SyncroniseOutpointIndexes();
|
||||
if (outrec.Points.Contains(outrec2.Points))
|
||||
{
|
||||
// OutRec2 is contained by OutRec1 ...
|
||||
outrec2.IsHole = !outrec.IsHole;
|
||||
outrec2.FirstLeft = outrec;
|
||||
this.FixupFirstLefts2(outrec2, outrec);
|
||||
}
|
||||
else if (Poly2ContainsPoly1(outrec.Points, outrec2.Points))
|
||||
else if (outrec2.Points.Contains(outrec.Points))
|
||||
{
|
||||
// OutRec1 is contained by OutRec2 ...
|
||||
outrec2.IsHole = outrec.IsHole;
|
||||
|
@ -3022,7 +2718,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
e.Delta = new Vector2(e.Top.X - e.Bottom.X, e.Top.Y - e.Bottom.Y);
|
||||
if (e.Delta.Y == 0)
|
||||
{
|
||||
e.Dx = HorizontalDeltaLimit;
|
||||
e.Dx = Constants.HorizontalDeltaLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3084,14 +2780,14 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
if (e != null)
|
||||
{
|
||||
e.Current = e.Bottom;
|
||||
e.OutIndex = Unassigned;
|
||||
e.OutIndex = Constants.Unassigned;
|
||||
}
|
||||
|
||||
e = lm.RightBound;
|
||||
if (e != null)
|
||||
{
|
||||
e.Current = e.Bottom;
|
||||
e.OutIndex = Unassigned;
|
||||
e.OutIndex = Constants.Unassigned;
|
||||
}
|
||||
|
||||
lm = lm.Next;
|
||||
|
@ -3334,7 +3030,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
Edge eStart, result = edge;
|
||||
Edge horz;
|
||||
|
||||
if (result.OutIndex == Skip)
|
||||
if (result.OutIndex == Constants.Skip)
|
||||
{
|
||||
// check if there are edges beyond the skip edge in the bound and if so
|
||||
// create another LocMin and calling ProcessBound once more ...
|
||||
|
@ -3346,7 +3042,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
edge = edge.NextEdge;
|
||||
}
|
||||
|
||||
while (edge != result && edge.Dx == HorizontalDeltaLimit)
|
||||
while (edge != result && edge.Dx == Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
edge = edge.PreviousEdge;
|
||||
}
|
||||
|
@ -3358,7 +3054,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
edge = edge.PreviousEdge;
|
||||
}
|
||||
|
||||
while (edge != result && edge.Dx == HorizontalDeltaLimit)
|
||||
while (edge != result && edge.Dx == Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
edge = edge.NextEdge;
|
||||
}
|
||||
|
@ -3400,7 +3096,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
return result;
|
||||
}
|
||||
|
||||
if (edge.Dx == HorizontalDeltaLimit)
|
||||
if (edge.Dx == Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
// We need to be careful with open paths because this may not be a
|
||||
// true local minima (ie E may be following a skip edge).
|
||||
|
@ -3415,7 +3111,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
|
||||
// ie an adjoining horizontal skip edge
|
||||
if (eStart.Dx == HorizontalDeltaLimit)
|
||||
if (eStart.Dx == Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
if (eStart.Bottom.X != edge.Bottom.X && eStart.Top.X != edge.Bottom.X)
|
||||
{
|
||||
|
@ -3431,18 +3127,18 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
eStart = edge;
|
||||
if (leftBoundIsForward)
|
||||
{
|
||||
while (result.Top.Y == result.NextEdge.Bottom.Y && result.NextEdge.OutIndex != Skip)
|
||||
while (result.Top.Y == result.NextEdge.Bottom.Y && result.NextEdge.OutIndex != Constants.Skip)
|
||||
{
|
||||
result = result.NextEdge;
|
||||
}
|
||||
|
||||
if (result.Dx == HorizontalDeltaLimit && result.NextEdge.OutIndex != Skip)
|
||||
if (result.Dx == Constants.HorizontalDeltaLimit && result.NextEdge.OutIndex != Constants.Skip)
|
||||
{
|
||||
// nb: at the top of a bound, horizontals are added to the bound
|
||||
// only when the preceding edge attaches to the horizontal's left vertex
|
||||
// unless a Skip edge is encountered when that becomes the top divide
|
||||
horz = result;
|
||||
while (horz.PreviousEdge.Dx == HorizontalDeltaLimit)
|
||||
while (horz.PreviousEdge.Dx == Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
horz = horz.PreviousEdge;
|
||||
}
|
||||
|
@ -3456,7 +3152,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
while (edge != result)
|
||||
{
|
||||
edge.NextInLML = edge.NextEdge;
|
||||
if (edge.Dx == HorizontalDeltaLimit && edge != eStart && edge.Bottom.X != edge.PreviousEdge.Top.X)
|
||||
if (edge.Dx == Constants.HorizontalDeltaLimit && edge != eStart && edge.Bottom.X != edge.PreviousEdge.Top.X)
|
||||
{
|
||||
ReverseHorizontal(edge);
|
||||
}
|
||||
|
@ -3464,7 +3160,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
edge = edge.NextEdge;
|
||||
}
|
||||
|
||||
if (edge.Dx == HorizontalDeltaLimit && edge != eStart && edge.Bottom.X != edge.PreviousEdge.Top.X)
|
||||
if (edge.Dx == Constants.HorizontalDeltaLimit && edge != eStart && edge.Bottom.X != edge.PreviousEdge.Top.X)
|
||||
{
|
||||
ReverseHorizontal(edge);
|
||||
}
|
||||
|
@ -3473,15 +3169,15 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
else
|
||||
{
|
||||
while (result.Top.Y == result.PreviousEdge.Bottom.Y && result.PreviousEdge.OutIndex != Skip)
|
||||
while (result.Top.Y == result.PreviousEdge.Bottom.Y && result.PreviousEdge.OutIndex != Constants.Skip)
|
||||
{
|
||||
result = result.PreviousEdge;
|
||||
}
|
||||
|
||||
if (result.Dx == HorizontalDeltaLimit && result.PreviousEdge.OutIndex != Skip)
|
||||
if (result.Dx == Constants.HorizontalDeltaLimit && result.PreviousEdge.OutIndex != Constants.Skip)
|
||||
{
|
||||
horz = result;
|
||||
while (horz.NextEdge.Dx == HorizontalDeltaLimit)
|
||||
while (horz.NextEdge.Dx == Constants.HorizontalDeltaLimit)
|
||||
{
|
||||
horz = horz.NextEdge;
|
||||
}
|
||||
|
@ -3495,7 +3191,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
while (edge != result)
|
||||
{
|
||||
edge.NextInLML = edge.PreviousEdge;
|
||||
if (edge.Dx == HorizontalDeltaLimit && edge != eStart && edge.Bottom.X != edge.NextEdge.Top.X)
|
||||
if (edge.Dx == Constants.HorizontalDeltaLimit && edge != eStart && edge.Bottom.X != edge.NextEdge.Top.X)
|
||||
{
|
||||
ReverseHorizontal(edge);
|
||||
}
|
||||
|
@ -3503,7 +3199,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
edge = edge.PreviousEdge;
|
||||
}
|
||||
|
||||
if (edge.Dx == HorizontalDeltaLimit && edge != eStart && edge.Bottom.X != edge.NextEdge.Top.X)
|
||||
if (edge.Dx == Constants.HorizontalDeltaLimit && edge != eStart && edge.Bottom.X != edge.NextEdge.Top.X)
|
||||
{
|
||||
ReverseHorizontal(edge);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SixLabors.Shapes.PolygonClipper
|
||||
{
|
||||
/// <summary>
|
||||
/// Clipper contants
|
||||
/// </summary>
|
||||
internal static class Constants
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The unassigned
|
||||
/// </summary>
|
||||
public const int Unassigned = -1; // InitOptions that can be passed to the constructor ...
|
||||
|
||||
/// <summary>
|
||||
/// The skip
|
||||
/// </summary>
|
||||
public const int Skip = -2;
|
||||
|
||||
/// <summary>
|
||||
/// The horizontal delta limit
|
||||
/// </summary>
|
||||
public const double HorizontalDeltaLimit = -3.4E+38;
|
||||
}
|
||||
}
|
|
@ -182,7 +182,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
this.NextEdge = next;
|
||||
this.PreviousEdge = prev;
|
||||
this.Current = pt;
|
||||
this.OutIndex = Clipper.Unassigned;
|
||||
this.OutIndex = Constants.Unassigned;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -261,7 +261,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
{
|
||||
// as above but returns null if MaxPair isn't in AEL (unless it's horizontal)
|
||||
Edge result = this.GetMaximaPair();
|
||||
if (result == null || result.OutIndex == Clipper.Skip ||
|
||||
if (result == null || result.OutIndex == Constants.Skip ||
|
||||
((result.NextInAEL == result.PreviousInAEL) && !result.IsHorizontal))
|
||||
{
|
||||
return null;
|
||||
|
@ -269,5 +269,20 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tops the x.
|
||||
/// </summary>
|
||||
/// <param name="currentY">The current y.</param>
|
||||
/// <returns>Returns the calcualted top X the current Y</returns>
|
||||
public float TopX(float currentY)
|
||||
{
|
||||
if (currentY == this.Top.Y)
|
||||
{
|
||||
return this.Top.X;
|
||||
}
|
||||
|
||||
return this.Bottom.X + Helpers.Round(this.Dx * (currentY - this.Bottom.Y));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// <copyright file="VectorHelpers.cs" company="Scott Williams">
|
||||
// <copyright file="Helpers.cs" company="Scott Williams">
|
||||
// Copyright (c) Scott Williams and contributors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
||||
// </copyright>
|
||||
|
@ -11,8 +11,19 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// <summary>
|
||||
/// Some helpers for vector data
|
||||
/// </summary>
|
||||
internal static class VectorHelpers
|
||||
internal static class Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Rounds the specified value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>the value rounded</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Round(double value)
|
||||
{
|
||||
return value < 0 ? (float)(value - 0.5) : (float)(value + 0.5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slopeses the equal.
|
||||
/// </summary>
|
||||
|
@ -21,7 +32,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// <param name="pt3">The PT3.</param>
|
||||
/// <returns>Returns true if the slopes are equal</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static bool SlopesEqual(Vector2 pt1, Vector2 pt2, Vector2 pt3)
|
||||
public static bool SlopesEqual(Vector2 pt1, Vector2 pt2, Vector2 pt3)
|
||||
{
|
||||
return SlopesEqual(pt1, pt2, pt2, pt3);
|
||||
}
|
||||
|
@ -35,12 +46,30 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// <param name="pt4">The PT4.</param>
|
||||
/// <returns>Returns true if the slopes are equal</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static bool SlopesEqual(Vector2 pt1, Vector2 pt2, Vector2 pt3, Vector2 pt4)
|
||||
public static bool SlopesEqual(Vector2 pt1, Vector2 pt2, Vector2 pt3, Vector2 pt4)
|
||||
{
|
||||
var dif12 = pt1 - pt2;
|
||||
var dif34 = pt3 - pt4;
|
||||
|
||||
return (dif12.Y * dif34.X) - (dif12.X * dif34.Y) == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dxes the specified PT2.
|
||||
/// </summary>
|
||||
/// <param name="pt1">The PT1.</param>
|
||||
/// <param name="pt2">The PT2.</param>
|
||||
/// <returns></returns>
|
||||
public static double Dx(this Vector2 pt1, Vector2 pt2)
|
||||
{
|
||||
if (pt1.Y == pt2.Y)
|
||||
{
|
||||
return Constants.HorizontalDeltaLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,6 +36,115 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// </summary>
|
||||
public OutPoint Previous { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Points the in polygon.
|
||||
/// </summary>
|
||||
/// <param name="point">The point.</param>
|
||||
/// <returns></returns>
|
||||
public int PointInPolygon(Vector2 point)
|
||||
{
|
||||
// See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
|
||||
// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
|
||||
OutPoint op = this;
|
||||
// returns 0 if false, +1 if true, -1 if pt ON polygon boundary
|
||||
int result = 0;
|
||||
OutPoint startOp = op;
|
||||
float ptx = point.X;
|
||||
float pty = point.Y;
|
||||
float poly0x = op.Point.X;
|
||||
float poly0y = op.Point.Y;
|
||||
do
|
||||
{
|
||||
op = op.Next;
|
||||
float poly1x = op.Point.X;
|
||||
float poly1y = op.Point.Y;
|
||||
|
||||
if (poly1y == pty)
|
||||
{
|
||||
if ((poly1x == ptx) || (poly0y == pty &&
|
||||
((poly1x > ptx) == (poly0x < ptx))))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((poly0y < pty) != (poly1y < pty))
|
||||
{
|
||||
if (poly0x >= ptx)
|
||||
{
|
||||
if (poly1x > ptx)
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
else
|
||||
{
|
||||
double d = (double)((poly0x - ptx) * (poly1y - pty)) -
|
||||
(double)((poly1x - ptx) * (poly0y - pty));
|
||||
if (d == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((d > 0) == (poly1y > poly0y))
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (poly1x > ptx)
|
||||
{
|
||||
double d = (double)((poly0x - ptx) * (poly1y - pty)) - (double)((poly1x - ptx) * (poly0y - pty));
|
||||
if (d == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((d > 0) == (poly1y > poly0y))
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
poly0x = poly1x;
|
||||
poly0y = poly1y;
|
||||
}
|
||||
while (startOp != op);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [contains] [the specified out PT1].
|
||||
/// </summary>
|
||||
/// <param name="outPt1">The out PT1.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if [contains] [the specified out PT1]; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool Contains(OutPoint outPt1)
|
||||
{
|
||||
OutPoint outPt2 = this;
|
||||
OutPoint op = outPt1;
|
||||
do
|
||||
{
|
||||
// nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
|
||||
int res = outPt2.PointInPolygon(op.Point);
|
||||
if (res >= 0)
|
||||
{
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
op = op.Next;
|
||||
}
|
||||
while (op != outPt1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Counts this instance.
|
||||
/// </summary>
|
||||
|
@ -52,5 +161,162 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
while (p != this);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Duplicates the specified insert after.
|
||||
/// </summary>
|
||||
/// <param name="insertAfter">if set to <c>true</c> [insert after].</param>
|
||||
/// <returns>the duplicated point</returns>
|
||||
public OutPoint Duplicate(bool insertAfter)
|
||||
{
|
||||
OutPoint result = new OutPoint();
|
||||
result.Point = this.Point;
|
||||
result.Index = this.Index;
|
||||
if (insertAfter)
|
||||
{
|
||||
result.Next = this.Next;
|
||||
result.Previous = this;
|
||||
this.Next.Previous = result;
|
||||
this.Next = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Previous = this.Previous;
|
||||
result.Next = this;
|
||||
this.Previous.Next = result;
|
||||
this.Previous = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the area.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double CalculateArea()
|
||||
{
|
||||
OutPoint op = this;
|
||||
double a = 0;
|
||||
do
|
||||
{
|
||||
a = a + ((op.Previous.Point.X + op.Point.X) * (op.Previous.Point.Y - op.Point.Y));
|
||||
op = op.Next;
|
||||
}
|
||||
while (op != this);
|
||||
|
||||
return a * 0.5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bottom pt.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public OutPoint GetBottomPt()
|
||||
{
|
||||
OutPoint pp = this;
|
||||
OutPoint dups = null;
|
||||
OutPoint p = pp.Next;
|
||||
while (p != pp)
|
||||
{
|
||||
if (p.Point.Y > pp.Point.Y)
|
||||
{
|
||||
pp = p;
|
||||
dups = null;
|
||||
}
|
||||
else if (p.Point.Y == pp.Point.Y && p.Point.X <= pp.Point.X)
|
||||
{
|
||||
if (p.Point.X < pp.Point.X)
|
||||
{
|
||||
dups = null;
|
||||
pp = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p.Next != pp && p.Previous != pp)
|
||||
{
|
||||
dups = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p = p.Next;
|
||||
}
|
||||
|
||||
if (dups != null)
|
||||
{
|
||||
// there appears to be at least 2 vertices at bottomPt so ...
|
||||
while (dups != p)
|
||||
{
|
||||
if (!p.FirstIsBottomPt(dups))
|
||||
{
|
||||
pp = dups;
|
||||
}
|
||||
|
||||
dups = dups.Next;
|
||||
while (dups.Point != pp.Point)
|
||||
{
|
||||
dups = dups.Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Firsts the is bottom pt.
|
||||
/// </summary>
|
||||
/// <param name="btmPt2">The BTM PT2.</param>
|
||||
/// <returns></returns>
|
||||
public bool FirstIsBottomPt(OutPoint btmPt2)
|
||||
{
|
||||
OutPoint btmPt1 = this;
|
||||
OutPoint p = btmPt1.Previous;
|
||||
while ((p.Point == btmPt1.Point) && (p != btmPt1))
|
||||
{
|
||||
p = p.Previous;
|
||||
}
|
||||
|
||||
double dx1p = Math.Abs(btmPt1.Point.Dx(p.Point));
|
||||
p = btmPt1.Next;
|
||||
while ((p.Point == btmPt1.Point) && (p != btmPt1))
|
||||
{
|
||||
p = p.Next;
|
||||
}
|
||||
|
||||
double dx1n = Math.Abs(btmPt1.Point.Dx(p.Point));
|
||||
|
||||
p = btmPt2.Previous;
|
||||
while ((p.Point == btmPt2.Point) && (p != btmPt2))
|
||||
{
|
||||
p = p.Previous;
|
||||
}
|
||||
|
||||
double dx2p = Math.Abs(btmPt2.Point.Dx(p.Point));
|
||||
p = btmPt2.Next;
|
||||
while ((p.Point == btmPt2.Point) && (p != btmPt2))
|
||||
{
|
||||
p = p.Next;
|
||||
}
|
||||
|
||||
double dx2n = Math.Abs(btmPt2.Point.Dx(p.Point));
|
||||
|
||||
if (Math.Max(dx1p, dx1n) == Math.Max(dx2p, dx2n) &&
|
||||
Math.Min(dx1p, dx1n) == Math.Min(dx2p, dx2n))
|
||||
{
|
||||
if (btmPt1 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return btmPt1.CalculateArea() > 0; // if otherwise identical use orientation
|
||||
}
|
||||
else
|
||||
{
|
||||
return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,6 +74,70 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// </value>
|
||||
public OutPoint BottomPoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Syncronises the outpoint indexes.
|
||||
/// </summary>
|
||||
public void SyncroniseOutpointIndexes()
|
||||
{
|
||||
OutPoint op = this.Points;
|
||||
do
|
||||
{
|
||||
op.Index = this.Index;
|
||||
op = op.Previous;
|
||||
}
|
||||
while (op != this.Points);
|
||||
}
|
||||
|
||||
|
||||
public static OutRec GetLowermostRec(OutRec outRec1, OutRec outRec2)
|
||||
{
|
||||
// work out which polygon fragment has the correct hole state ...
|
||||
if (outRec1.BottomPoint == null)
|
||||
{
|
||||
outRec1.BottomPoint = outRec1.Points.GetBottomPt();
|
||||
}
|
||||
|
||||
if (outRec2.BottomPoint == null)
|
||||
{
|
||||
outRec2.BottomPoint = outRec2.Points.GetBottomPt();
|
||||
}
|
||||
|
||||
OutPoint bPt1 = outRec1.BottomPoint;
|
||||
OutPoint bPt2 = outRec2.BottomPoint;
|
||||
if (bPt1.Point.Y > bPt2.Point.Y)
|
||||
{
|
||||
return outRec1;
|
||||
}
|
||||
else if (bPt1.Point.Y < bPt2.Point.Y)
|
||||
{
|
||||
return outRec2;
|
||||
}
|
||||
else if (bPt1.Point.X < bPt2.Point.X)
|
||||
{
|
||||
return outRec1;
|
||||
}
|
||||
else if (bPt1.Point.X > bPt2.Point.X)
|
||||
{
|
||||
return outRec2;
|
||||
}
|
||||
else if (bPt1.Next == bPt1)
|
||||
{
|
||||
return outRec2;
|
||||
}
|
||||
else if (bPt2.Next == bPt2)
|
||||
{
|
||||
return outRec1;
|
||||
}
|
||||
else if (bPt1.FirstIsBottomPt(bPt2))
|
||||
{
|
||||
return outRec1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return outRec2;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fixups the outs.
|
||||
/// </summary>
|
||||
|
@ -94,6 +158,9 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fixups the out polyline.
|
||||
/// </summary>
|
||||
private void FixupOutPolyline()
|
||||
{
|
||||
OutPoint pp = this.Points;
|
||||
|
@ -121,6 +188,9 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fixups the out polygon.
|
||||
/// </summary>
|
||||
private void FixupOutPolygon()
|
||||
{
|
||||
// FixupOutPolygon() - removes duplicate points and simplifies consecutive
|
||||
|
@ -138,7 +208,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
// test for duplicate points and collinear edges ...
|
||||
if ((pp.Point == pp.Next.Point) || (pp.Point == pp.Previous.Point) ||
|
||||
VectorHelpers.SlopesEqual(pp.Previous.Point, pp.Point, pp.Next.Point))
|
||||
Helpers.SlopesEqual(pp.Previous.Point, pp.Point, pp.Next.Point))
|
||||
{
|
||||
lastOK = null;
|
||||
pp.Previous.Next = pp.Next;
|
||||
|
|
Загрузка…
Ссылка в новой задаче