/// <summary> /// Initializes a new instance of the <see cref="ComplexPolygon" /> class. /// </summary> /// <param name="paths">The paths.</param> public ComplexPolygon(params IPath[] paths) { Guard.NotNull(paths, nameof(paths)); this.paths = paths; this.internalPaths = new List <InternalPath>(this.paths.Length); if (paths.Length > 0) { float minX = float.MaxValue; float maxX = float.MinValue; float minY = float.MaxValue; float maxY = float.MinValue; float length = 0; foreach (IPath p in this.paths) { if (p.Bounds.Left < minX) { minX = p.Bounds.Left; } if (p.Bounds.Right > maxX) { maxX = p.Bounds.Right; } if (p.Bounds.Top < minY) { minY = p.Bounds.Top; } if (p.Bounds.Bottom > maxY) { maxY = p.Bounds.Bottom; } foreach (ISimplePath s in p.Flatten()) { var ip = new InternalPath(s.Points, s.IsClosed); length += ip.Length; this.internalPaths.Add(ip); } } this.length = length; this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY); } else { this.length = 0; this.Bounds = RectangleF.Empty; } this.PathType = PathTypes.Mixed; }
/// <inheritdoc /> public int FindIntersections(PointF start, PointF end, Span <PointF> buffer, IntersectionRule intersectionRule) { this.EnsureInternalPathsInitalized(); int totalAdded = 0; InternalPath.PointOrientation[] orientations = ArrayPool <InternalPath.PointOrientation> .Shared.Rent(buffer.Length); // the largest number of intersections of any sub path of the set is the max size with need for this buffer. Span <InternalPath.PointOrientation> orientationsSpan = orientations; try { foreach (var ip in this.internalPaths) { Span <PointF> subBuffer = buffer.Slice(totalAdded); Span <InternalPath.PointOrientation> subOrientationsSpan = orientationsSpan.Slice(totalAdded); var position = ip.FindIntersectionsWithOrientation(start, end, subBuffer, subOrientationsSpan); totalAdded += position; } Span <float> distances = stackalloc float[totalAdded]; for (int i = 0; i < totalAdded; i++) { distances[i] = Vector2.DistanceSquared(start, buffer[i]); } var activeBuffer = buffer.Slice(0, totalAdded); var activeOrientationsSpan = orientationsSpan.Slice(0, totalAdded); SortUtility.Sort(distances, activeBuffer, activeOrientationsSpan); if (intersectionRule == IntersectionRule.Nonzero) { totalAdded = InternalPath.ApplyNonZeroIntersectionRules(activeBuffer, activeOrientationsSpan); } } finally { ArrayPool <InternalPath.PointOrientation> .Shared.Return(orientations); } return(totalAdded); }
/// <summary> /// Finds the intersections. /// </summary> /// <param name="start">The start.</param> /// <param name="end">The end.</param> /// <returns>The points along the line the intersect with the boundaries of the polygon.</returns> internal static IEnumerable <PointF> FindIntersections(this InternalPath path, Vector2 start, Vector2 end, IntersectionRule intersectionRule = IntersectionRule.OddEven) { var results = new List <PointF>(); PointF[] buffer = ArrayPool <PointF> .Shared.Rent(path.PointCount); try { int hits = path.FindIntersections(start, end, buffer, intersectionRule); for (int i = 0; i < hits; i++) { results.Add(buffer[i]); } } finally { ArrayPool <PointF> .Shared.Return(buffer); } return(results); }
private void EnsureInternalPathsInitalized() { if (this.internalPaths == null) { lock (this.paths) { if (this.internalPaths == null) { this.internalPaths = new List <InternalPath>(this.paths.Length); foreach (var p in this.paths) { foreach (var s in p.Flatten()) { var ip = new InternalPath(s.Points, s.IsClosed); this.internalPaths.Add(ip); } } } } } }
private EllipsePolygon(CubicBezierLineSegment segment) { this.segment = segment; this.innerPath = new InternalPath(segment, true); }