// 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);
}
}
}