Browse Source

Remove more linq calls

removed a Linq call from the critical path of geting distance from point.
af/merge-core
Scott Williams 10 years ago
parent
commit
0cf795fc27
  1. 92
      src/ImageSharp/Drawing/Shapes/ComplexPolygon.cs

92
src/ImageSharp/Drawing/Shapes/ComplexPolygon.cs

@ -7,6 +7,7 @@ namespace ImageSharp.Drawing.Shapes
{ {
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Numerics; using System.Numerics;
using Paths; using Paths;
@ -19,8 +20,7 @@ namespace ImageSharp.Drawing.Shapes
public sealed class ComplexPolygon : IShape public sealed class ComplexPolygon : IShape
{ {
private const float ClipperScaleFactor = 100f; private const float ClipperScaleFactor = 100f;
private IShape[] holes; private IShape[] shapes;
private IShape[] outlines;
private IEnumerable<IPath> paths; private IEnumerable<IPath> paths;
/// <summary> /// <summary>
@ -41,14 +41,14 @@ namespace ImageSharp.Drawing.Shapes
public ComplexPolygon(IShape[] outlines, IShape[] holes) public ComplexPolygon(IShape[] outlines, IShape[] holes)
{ {
Guard.NotNull(outlines, nameof(outlines)); Guard.NotNull(outlines, nameof(outlines));
Guard.MustBeGreaterThanOrEqualTo(outlines.Count(), 1, nameof(outlines)); Guard.MustBeGreaterThanOrEqualTo(outlines.Length, 1, nameof(outlines));
this.FixAndSetShapes(outlines, holes); this.FixAndSetShapes(outlines, holes);
var minX = outlines.Min(x => x.Bounds.Left); var minX = this.shapes.Min(x => x.Bounds.Left);
var maxX = outlines.Max(x => x.Bounds.Right); var maxX = this.shapes.Max(x => x.Bounds.Right);
var minY = outlines.Min(x => x.Bounds.Top); var minY = this.shapes.Min(x => x.Bounds.Top);
var maxY = outlines.Max(x => x.Bounds.Bottom); var maxY = this.shapes.Max(x => x.Bounds.Bottom);
this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY); this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY);
} }
@ -68,30 +68,36 @@ namespace ImageSharp.Drawing.Shapes
/// <returns> /// <returns>
/// Returns the distance from thr shape to the point /// Returns the distance from thr shape to the point
/// </returns> /// </returns>
/// <remarks>
/// Due to the clipping we did during construction we know that out shapes do not overlap at there edges
/// therefore for apoint to be in more that one we must be in a hole of another, theoretically this could
/// then flip again to be in a outlin inside a hole inside an outline :)
/// </remarks>
float IShape.Distance(Vector2 point) float IShape.Distance(Vector2 point)
{ {
// get the outline we are closest to the center of float dist = float.MaxValue;
// by rights we should only be inside 1 outline bool inside = false;
// othersie we will start returning the distanct to the nearest shape foreach (IShape shape in this.shapes)
var dist = this.outlines.Select(o => o.Distance(point)).OrderBy(p => p).First();
if (dist <= 0 && this.holes != null)
{ {
// inside poly var d = shape.Distance(point);
foreach (var hole in this.holes)
if(d <= 0)
{ {
var distFromHole = hole.Distance(point); // we are inside a poly
d = -d; // flip the sign
inside ^= true; // flip the inside flag
}
// less than zero we are inside shape if(d < dist)
if (distFromHole <= 0) {
{ dist = d;
// invert distance
dist = distFromHole * -1;
break;
}
} }
} }
if (inside) {
return -dist;
}
return dist; return dist;
} }
@ -149,7 +155,7 @@ namespace ImageSharp.Drawing.Shapes
} }
private void ExtractOutlines(ClipperLib.PolyNode tree, List<IShape> outlines, List<IShape> holes) private void ExtractOutlines(ClipperLib.PolyNode tree, List<IShape> shapes)
{ {
if (tree.Contour.Any()) if (tree.Contour.Any())
{ {
@ -164,19 +170,12 @@ namespace ImageSharp.Drawing.Shapes
var polygon = new Polygon(new LinearLineSegment(vectors)); var polygon = new Polygon(new LinearLineSegment(vectors));
if (tree.IsHole) shapes.Add(polygon);
{
holes.Add(polygon);
}
else
{
outlines.Add(polygon);
}
} }
foreach (var c in tree.Childs) foreach (var c in tree.Childs)
{ {
this.ExtractOutlines(c, outlines, holes); this.ExtractOutlines(c, shapes);
} }
} }
@ -198,7 +197,7 @@ namespace ImageSharp.Drawing.Shapes
// as sending then though clipper will turn them into generic polygons and loose thier shape specific optimisations // as sending then though clipper will turn them into generic polygons and loose thier shape specific optimisations
int outlineLength = outlines.Length; int outlineLength = outlines.Length;
int holesLength = holes.Length; int holesLength = holes?.Length ?? 0;
bool[] overlappingOutlines = new bool[outlineLength]; bool[] overlappingOutlines = new bool[outlineLength];
bool[] overlappingHoles = new bool[holesLength]; bool[] overlappingHoles = new bool[holesLength];
bool anyOutlinesOverlapping = false; bool anyOutlinesOverlapping = false;
@ -249,43 +248,32 @@ namespace ImageSharp.Drawing.Shapes
var tree = new ClipperLib.PolyTree(); var tree = new ClipperLib.PolyTree();
clipper.Execute(ClipperLib.ClipType.ctDifference, tree); clipper.Execute(ClipperLib.ClipType.ctDifference, tree);
List<IShape> newOutlines = new List<IShape>(); List<IShape> newShapes = new List<IShape>();
List<IShape> newHoles = new List<IShape>();
// convert the 'tree' back to shapes // convert the 'tree' back to shapes
this.ExtractOutlines(tree, newOutlines, newHoles); this.ExtractOutlines(tree, newShapes);
// add the origional outlines that where not overlapping // add the origional outlines that where not overlapping
for (int i = 0; i < outlineLength - 1; i++) for (int i = 0; i < outlineLength - 1; i++)
{ {
if (!overlappingOutlines[i]) if (!overlappingOutlines[i])
{ {
newOutlines.Add(outlines[i]); newShapes.Add(outlines[i]);
} }
} }
this.outlines = newOutlines.ToArray(); this.shapes = newShapes.ToArray();
if (newHoles.Count > 0)
{
this.holes = newHoles.ToArray();
}
}else }else
{ {
this.outlines = outlines; this.shapes = outlines;
} }
var paths = new List<IPath>(); var paths = new List<IPath>();
foreach (var o in this.outlines) foreach (var o in this.shapes)
{ {
paths.AddRange(o); paths.AddRange(o);
} }
if (this.holes != null)
{
foreach (var o in this.holes)
{
paths.AddRange(o);
}
}
this.paths = paths; this.paths = paths;
} }
} }

Loading…
Cancel
Save