зеркало из https://github.com/SixLabors/Shapes.git
reorganise clipper code some more.
This commit is contained in:
Родитель
c252e17ddc
Коммит
d94db3503b
|
@ -21,8 +21,13 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// 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 const int Skip = -2;
|
||||
private static readonly IComparer<IntersectNode> IntersectNodeComparer = new IntersectNodeSort();
|
||||
private readonly List<IntersectNode> intersectList = new List<IntersectNode>();
|
||||
|
||||
|
@ -574,12 +579,6 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
val2 = tmp;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool IsHorizontal(Edge e)
|
||||
{
|
||||
return e.Delta.Y == 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool SlopesEqual(Edge e1, Edge e2)
|
||||
{
|
||||
|
@ -739,7 +738,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
if (rb != null)
|
||||
{
|
||||
if (IsHorizontal(rb))
|
||||
if (rb.IsHorizontal)
|
||||
{
|
||||
if (rb.NextInLML != null)
|
||||
{
|
||||
|
@ -760,7 +759,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
|
||||
// if output polygons share an Edge with a horizontal rb, they'll need joining later ...
|
||||
if (op1 != null && IsHorizontal(rb) &&
|
||||
if (op1 != null && rb.IsHorizontal &&
|
||||
this.ghostJoins.Count > 0 && rb.WindingDelta != 0)
|
||||
{
|
||||
for (int i = 0; i < this.ghostJoins.Count; i++)
|
||||
|
@ -1127,7 +1126,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
{
|
||||
OutPoint result;
|
||||
Edge e, prevE;
|
||||
if (IsHorizontal(e2) || (e1.Dx > e2.Dx))
|
||||
if (e2.IsHorizontal || (e1.Dx > e2.Dx))
|
||||
{
|
||||
result = this.AddOutPt(e1, pt);
|
||||
e2.OutIndex = e1.OutIndex;
|
||||
|
@ -1695,16 +1694,12 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
this.GetHorzDirection(horzEdge, out dir, out horzLeft, out horzRight);
|
||||
|
||||
Edge lastHorzEdge = horzEdge;
|
||||
Edge lastHorzEdge = horzEdge.LastHorizonalEdge();
|
||||
Edge maxPairEdge = null;
|
||||
while (lastHorzEdge.NextInLML != null && IsHorizontal(lastHorzEdge.NextInLML))
|
||||
{
|
||||
lastHorzEdge = lastHorzEdge.NextInLML;
|
||||
}
|
||||
|
||||
if (lastHorzEdge.NextInLML == null)
|
||||
{
|
||||
maxPairEdge = this.GetMaximaPair(lastHorzEdge);
|
||||
maxPairEdge = lastHorzEdge?.GetMaximaPair();
|
||||
}
|
||||
|
||||
Maxima currMax = this.maxima;
|
||||
|
@ -1743,7 +1738,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
while (true)
|
||||
{
|
||||
bool isLastHorz = horzEdge == lastHorzEdge;
|
||||
Edge e = this.GetNextInAEL(horzEdge, dir);
|
||||
Edge e = horzEdge.GetNextInAEL(dir);
|
||||
while (e != null)
|
||||
{
|
||||
// this code block inserts extra coords into horizontal edges (in output
|
||||
|
@ -1836,13 +1831,13 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
this.IntersectEdges(e, horzEdge, pt);
|
||||
}
|
||||
|
||||
Edge eNext = this.GetNextInAEL(e, dir);
|
||||
Edge eNext = e.GetNextInAEL(dir);
|
||||
this.SwapPositionsInAEL(horzEdge, e);
|
||||
e = eNext;
|
||||
} // end while(e != null)
|
||||
|
||||
// Break out of loop if HorzEdge.NextInLML is not also horizontal ...
|
||||
if (horzEdge.NextInLML == null || !IsHorizontal(horzEdge.NextInLML))
|
||||
if (horzEdge.NextInLML == null || !horzEdge.NextInLML.IsHorizontal)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1923,50 +1918,6 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
}
|
||||
|
||||
private Edge GetNextInAEL(Edge e, Direction direction)
|
||||
{
|
||||
return direction == Direction.LeftToRight ? e.NextInAEL : e.PreviousInAEL;
|
||||
}
|
||||
|
||||
private bool IsMaxima(Edge e, double y)
|
||||
{
|
||||
return e != null && e.Top.Y == y && e.NextInLML == null;
|
||||
}
|
||||
|
||||
private bool IsIntermediate(Edge e, double y)
|
||||
{
|
||||
return e.Top.Y == y && e.NextInLML != null;
|
||||
}
|
||||
|
||||
private Edge GetMaximaPair(Edge e)
|
||||
{
|
||||
if ((e.NextEdge.Top == e.Top) && e.NextEdge.NextInLML == null)
|
||||
{
|
||||
return e.NextEdge;
|
||||
}
|
||||
else if ((e.PreviousEdge.Top == e.Top) && e.PreviousEdge.NextInLML == null)
|
||||
{
|
||||
return e.PreviousEdge;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Edge GetMaximaPairEx(Edge e)
|
||||
{
|
||||
// as above but returns null if MaxPair isn't in AEL (unless it's horizontal)
|
||||
Edge result = this.GetMaximaPair(e);
|
||||
if (result == null || result.OutIndex == Skip ||
|
||||
((result.NextInAEL == result.PreviousInAEL) && !IsHorizontal(result)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ProcessIntersections(float topY)
|
||||
{
|
||||
if (this.activeEdges == null)
|
||||
|
@ -2138,7 +2089,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
if (edge1.Delta.X == 0)
|
||||
{
|
||||
ip.X = edge1.Bottom.X;
|
||||
if (IsHorizontal(edge2))
|
||||
if (edge2.IsHorizontal)
|
||||
{
|
||||
ip.Y = edge2.Bottom.Y;
|
||||
}
|
||||
|
@ -2151,7 +2102,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
else if (edge2.Delta.X == 0)
|
||||
{
|
||||
ip.X = edge2.Bottom.X;
|
||||
if (IsHorizontal(edge1))
|
||||
if (edge1.IsHorizontal)
|
||||
{
|
||||
ip.Y = edge1.Bottom.Y;
|
||||
}
|
||||
|
@ -2222,12 +2173,12 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
{
|
||||
// 1. process maxima, treating them as if they're 'bent' horizontal edges,
|
||||
// but exclude maxima with horizontal edges. nb: e can't be a horizontal.
|
||||
bool isMaximaEdge = this.IsMaxima(e, topY);
|
||||
bool isMaximaEdge = e.IsMaxima(topY);
|
||||
|
||||
if (isMaximaEdge)
|
||||
{
|
||||
Edge eMaxPair = this.GetMaximaPairEx(e);
|
||||
isMaximaEdge = eMaxPair == null || !IsHorizontal(eMaxPair);
|
||||
Edge eMaxPair = e.GetMaximaPairEx();
|
||||
isMaximaEdge = eMaxPair == null || !eMaxPair.IsHorizontal;
|
||||
}
|
||||
|
||||
if (isMaximaEdge)
|
||||
|
@ -2246,7 +2197,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
else
|
||||
{
|
||||
// 2. promote horizontal edges, otherwise update Curr.X and Curr.Y ...
|
||||
if (this.IsIntermediate(e, topY) && IsHorizontal(e.NextInLML))
|
||||
if (e.IsIntermediate(topY) && e.NextInLML.IsHorizontal)
|
||||
{
|
||||
this.UpdateEdgeIntoAEL(ref e);
|
||||
if (e.OutIndex >= 0)
|
||||
|
@ -2273,7 +2224,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
e = this.activeEdges;
|
||||
while (e != null)
|
||||
{
|
||||
if (this.IsIntermediate(e, topY))
|
||||
if (e.IsIntermediate(topY))
|
||||
{
|
||||
OutPoint op = null;
|
||||
if (e.OutIndex >= 0)
|
||||
|
@ -2312,7 +2263,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
|
||||
private void DoMaxima(Edge e)
|
||||
{
|
||||
Edge eMaxPair = this.GetMaximaPairEx(e);
|
||||
Edge eMaxPair = e?.GetMaximaPairEx();
|
||||
if (eMaxPair == null)
|
||||
{
|
||||
if (e.OutIndex >= 0)
|
||||
|
@ -2353,24 +2304,6 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
}
|
||||
}
|
||||
|
||||
private int PointCount(OutPoint pts)
|
||||
{
|
||||
if (pts == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
OutPoint p = pts;
|
||||
do
|
||||
{
|
||||
result++;
|
||||
p = p.Next;
|
||||
}
|
||||
while (p != pts);
|
||||
return result;
|
||||
}
|
||||
|
||||
private ImmutableArray<IShape> BuildResult()
|
||||
{
|
||||
List<IShape> shapes = new List<IShape>(this.polyOuts.Count);
|
||||
|
@ -2379,7 +2312,12 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
for (int i = 0; i < this.polyOuts.Count; i++)
|
||||
{
|
||||
OutRec outRec = this.polyOuts[i];
|
||||
int cnt = this.PointCount(outRec.Points);
|
||||
if (outRec.Points == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int cnt = outRec.Points.Count();
|
||||
if ((outRec.IsOpen && cnt < 2) ||
|
||||
(!outRec.IsOpen && cnt < 3))
|
||||
{
|
||||
|
@ -3255,7 +3193,7 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
e.Current = e.Bottom;
|
||||
e.PreviousInAEL = aelPrev;
|
||||
e.NextInAEL = aelNext;
|
||||
if (!IsHorizontal(e))
|
||||
if (!e.IsHorizontal)
|
||||
{
|
||||
this.InsertScanbeam(e.Top.Y);
|
||||
}
|
||||
|
|
|
@ -155,6 +155,14 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// </summary>
|
||||
public Edge NextInSEL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is horizontal.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is horizontal; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsHorizontal => this.Delta.Y == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the previous in sel.
|
||||
/// </summary>
|
||||
|
@ -176,5 +184,90 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
this.Current = pt;
|
||||
this.OutIndex = Clipper.Unassigned;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lasts the horizonal edge.
|
||||
/// </summary>
|
||||
/// <returns>The last horizontal edge</returns>
|
||||
public Edge LastHorizonalEdge()
|
||||
{
|
||||
var lastHorzEdge = this;
|
||||
while (lastHorzEdge.NextInLML != null && lastHorzEdge.NextInLML.IsHorizontal)
|
||||
{
|
||||
lastHorzEdge = lastHorzEdge.NextInLML;
|
||||
}
|
||||
|
||||
return lastHorzEdge;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next in ael.
|
||||
/// </summary>
|
||||
/// <param name="direction">The direction.</param>
|
||||
/// <returns>the next edge based on direction</returns>
|
||||
public Edge GetNextInAEL(Direction direction)
|
||||
{
|
||||
return direction == Direction.LeftToRight ? this.NextInAEL : this.PreviousInAEL;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the edge is Maxima in relation to y.
|
||||
/// </summary>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified y is maxima; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsMaxima(double y)
|
||||
{
|
||||
return this.Top.Y == y && this.NextInLML == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maxima pair.
|
||||
/// </summary>
|
||||
/// <returns>The maxima pair for this edge</returns>
|
||||
public Edge GetMaximaPair()
|
||||
{
|
||||
if ((this.NextEdge.Top == this.Top) && this.NextEdge.NextInLML == null)
|
||||
{
|
||||
return this.NextEdge;
|
||||
}
|
||||
|
||||
if ((this.PreviousEdge.Top == this.Top) && this.PreviousEdge.NextInLML == null)
|
||||
{
|
||||
return this.PreviousEdge;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified intermediate in relation to y.
|
||||
/// </summary>
|
||||
/// <param name="y">The y.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified y is intermediate; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool IsIntermediate(double y)
|
||||
{
|
||||
return this.Top.Y == y && this.NextInLML != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maxima pair ex.
|
||||
/// </summary>
|
||||
/// <returns>The maxima pair for this edge unless it should be skipped</returns>
|
||||
public Edge GetMaximaPairEx()
|
||||
{
|
||||
// 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 ||
|
||||
((result.NextInAEL == result.PreviousInAEL) && !result.IsHorizontal))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,5 +35,22 @@ namespace SixLabors.Shapes.PolygonClipper
|
|||
/// Gets or sets the previous <see cref="OutPoint"/>
|
||||
/// </summary>
|
||||
public OutPoint Previous { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Counts this instance.
|
||||
/// </summary>
|
||||
/// <returns>count the number of points in this set</returns>
|
||||
public int Count()
|
||||
{
|
||||
int result = 0;
|
||||
OutPoint p = this;
|
||||
do
|
||||
{
|
||||
result++;
|
||||
p = p.Next;
|
||||
}
|
||||
while (p != this);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче