// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; namespace SixLabors.ImageSharp.Drawing { /// /// An elliptical shape made up of a single path made up of one of more s. /// public sealed class EllipsePolygon : Polygon, IPathInternals { /// /// Initializes a new instance of the class. /// /// The location the center of the ellipse will be placed. /// The width/height of the final ellipse. public EllipsePolygon(PointF location, SizeF size) : base(CreateSegment(location, size)) { } /// /// Initializes a new instance of the class. /// /// The location the center of the circle will be placed. /// The radius final circle. public EllipsePolygon(PointF location, float radius) : this(location, new SizeF(radius * 2, radius * 2)) { } /// /// Initializes a new instance of the class. /// /// The x-coordinate of the center of the ellipse. /// The y-coordinate of the center of the ellipse. /// The width the ellipse should have. /// The height the ellipse should have. public EllipsePolygon(float x, float y, float width, float height) : this(new PointF(x, y), new SizeF(width, height)) { } private EllipsePolygon(ILineSegment[] segments) : base(segments, true) { } /// /// Initializes a new instance of the class. /// /// The x-coordinate of the center of the circle. /// The y-coordinate of the center of the circle. /// The radius final circle. public EllipsePolygon(float x, float y, float radius) : this(new PointF(x, y), new SizeF(radius * 2, radius * 2)) { } /// public override IPath Transform(Matrix4x4 matrix) { if (matrix.IsIdentity) { return this; } ILineSegment[] segments = new ILineSegment[this.LineSegments.Count]; for (int i = 0; i < segments.Length; i++) { segments[i] = this.LineSegments[i].Transform(matrix); } return new EllipsePolygon(segments); } /// // TODO switch this out to a calculated algorithm SegmentInfo IPathInternals.PointAlongPath(float distance) => this.InnerPath.PointAlongPath(distance); private static CubicBezierLineSegment CreateSegment(Vector2 location, SizeF size) { Guard.MustBeGreaterThan(size.Width, 0, "width"); Guard.MustBeGreaterThan(size.Height, 0, "height"); const float kappa = 0.5522848f; Vector2 sizeVector = size; sizeVector /= 2; Vector2 rootLocation = location - sizeVector; Vector2 pointO = sizeVector * kappa; Vector2 pointE = location + sizeVector; Vector2 pointM = location; Vector2 pointMminusO = pointM - pointO; Vector2 pointMplusO = pointM + pointO; PointF[] points = [ new Vector2(rootLocation.X, pointM.Y), new Vector2(rootLocation.X, pointMminusO.Y), new Vector2(pointMminusO.X, rootLocation.Y), new Vector2(pointM.X, rootLocation.Y), new Vector2(pointMplusO.X, rootLocation.Y), new Vector2(pointE.X, pointMminusO.Y), new Vector2(pointE.X, pointM.Y), new Vector2(pointE.X, pointMplusO.Y), new Vector2(pointMplusO.X, pointE.Y), new Vector2(pointM.X, pointE.Y), new Vector2(pointMminusO.X, pointE.Y), new Vector2(rootLocation.X, pointMplusO.Y), new Vector2(rootLocation.X, pointM.Y) ]; return new CubicBezierLineSegment(points); } } }