// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Drawing { using System.Buffers; using System.Collections.Immutable; using System.Numerics; using ImageSharp.Drawing.Processors; using SixLabors.Shapes; using Rectangle = ImageSharp.Rectangle; /// /// A drawable mapping between a / and a drawable/fillable region. /// /// internal class ShapeRegion : IDrawableRegion { /// /// The fillable shape /// private readonly IShape shape; /// /// The drawable paths /// private readonly ImmutableArray paths; /// /// Initializes a new instance of the class. /// /// The path. public ShapeRegion(IPath path) : this(ImmutableArray.Create(path)) { this.shape = path.AsShape(); this.Bounds = RectangleF.Ceiling(path.Bounds.Convert()); } /// /// Initializes a new instance of the class. /// /// The shape. public ShapeRegion(IShape shape) : this(shape.Paths) { this.shape = shape; this.Bounds = RectangleF.Ceiling(shape.Bounds.Convert()); } /// /// Initializes a new instance of the class. /// /// The paths. private ShapeRegion(ImmutableArray paths) { this.paths = paths; } /// /// Gets the maximum number of intersections to could be returned. /// /// /// The maximum intersections. /// public int MaxIntersections => this.shape.MaxIntersections; /// /// Gets the bounds. /// /// /// The bounds. /// public Rectangle Bounds { get; } /// /// Scans the X axis for intersections. /// /// The x. /// The buffer. /// The length. /// The offset. /// /// The number of intersections found. /// public int ScanX(int x, float[] buffer, int length, int offset) { var start = new Vector2(x, this.Bounds.Top - 1); var end = new Vector2(x, this.Bounds.Bottom + 1); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { int count = this.shape.FindIntersections( start, end, innerbuffer, length, 0); for (var i = 0; i < count; i++) { buffer[i + offset] = innerbuffer[i].Y; } return count; } finally { ArrayPool.Shared.Return(innerbuffer); } } /// /// Scans the Y axis for intersections. /// /// The position along the y axis to find intersections. /// The buffer. /// The length. /// The offset. /// /// The number of intersections found. /// public int ScanY(int y, float[] buffer, int length, int offset) { var start = new Vector2(this.Bounds.Left - 1, y); var end = new Vector2(this.Bounds.Right + 1, y); Vector2[] innerbuffer = ArrayPool.Shared.Rent(length); try { int count = this.shape.FindIntersections( start, end, innerbuffer, length, 0); for (var i = 0; i < count; i++) { buffer[i + offset] = innerbuffer[i].X; } return count; } finally { ArrayPool.Shared.Return(innerbuffer); } } /// /// Gets the point information for the specified x and y location. /// /// The x. /// The y. /// Information about the the point public PointInfo GetPointInfo(int x, int y) { var point = new Vector2(x, y); SixLabors.Shapes.PointInfo result = default(SixLabors.Shapes.PointInfo); float distance = float.MaxValue; for (int i = 0; i < this.paths.Length; i++) { var p = this.paths[i].Distance(point); if (p.DistanceFromPath < distance) { distance = p.DistanceFromPath; result = p; } } return result.Convert(); } } }