// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System; using System.Numerics; using SixLabors.ImageSharp.Drawing.Helpers; namespace SixLabors.ImageSharp.Drawing { /// /// Represents a series of control points that will be joined by straight lines /// /// public sealed class LinearLineSegment : ILineSegment { /// /// The collection of points. /// private readonly PointF[] points; /// /// Initializes a new instance of the class. /// /// The start. /// The end. public LinearLineSegment(PointF start, PointF end) : this([start, end]) { } /// /// Initializes a new instance of the class. /// /// The point1. /// The point2. /// Additional points public LinearLineSegment(PointF point1, PointF point2, params PointF[] additionalPoints) : this(new[] { point1, point2 }.Concat(additionalPoints)) { } /// /// Initializes a new instance of the class. /// /// The points. public LinearLineSegment(PointF[] points) { Guard.NotNull(points, nameof(points)); Guard.MustBeGreaterThanOrEqualTo(points.Length, 2, nameof(points)); this.points = points; this.Bounds = CalculateBounds(points); } /// /// Gets the start point. /// public PointF StartPoint => this.points[0]; /// /// Gets the end point. /// /// /// The end point. /// public PointF EndPoint => this.points[^1]; /// public RectangleF Bounds { get; } /// public int LinearVertexCount(Vector2 scale) => this.points.Length; /// public void CopyTo(Span destination, bool skipFirstPoint, Vector2 scale) { int startIndex = skipFirstPoint ? 1 : 0; ReadOnlySpan source = this.points.AsSpan(startIndex); if (scale == Vector2.One) { source.CopyTo(destination); return; } for (int i = 0; i < source.Length; i++) { destination[i] = new PointF(source[i].X * scale.X, source[i].Y * scale.Y); } } /// /// Transforms the current LineSegment using specified matrix. /// /// The matrix. /// /// A line segment with the matrix applied to it. /// public LinearLineSegment Transform(Matrix4x4 matrix) { if (matrix.IsIdentity) { // no transform to apply skip it return this; } PointF[] transformedPoints = new PointF[this.points.Length]; for (int i = 0; i < this.points.Length; i++) { transformedPoints[i] = PointF.Transform(this.points[i], matrix); } return new LinearLineSegment(transformedPoints); } /// /// Transforms the current LineSegment using specified matrix. /// /// The matrix. /// A line segment with the matrix applied to it. ILineSegment ILineSegment.Transform(Matrix4x4 matrix) => this.Transform(matrix); /// /// Computes the bounds for the retained linear point run. /// private static RectangleF CalculateBounds(ReadOnlySpan points) { float minX = float.MaxValue; float minY = float.MaxValue; float maxX = float.MinValue; float maxY = float.MinValue; for (int i = 0; i < points.Length; i++) { PointF point = points[i]; minX = MathF.Min(minX, point.X); minY = MathF.Min(minY, point.Y); maxX = MathF.Max(maxX, point.X); maxY = MathF.Max(maxY, point.Y); } return RectangleF.FromLTRB(minX, minY, maxX, maxY); } } }