Convert Polygon/F to class

This change also now refers to "Points" as "Vertices"
This commit is contained in:
Oliver Booth 2022-06-01 18:30:48 +01:00
parent 34b4777a8e
commit 0b3bf01fa0
No known key found for this signature in database
GPG Key ID: 32A00B35503AF634
4 changed files with 191 additions and 195 deletions

View File

@ -12,25 +12,25 @@ public class PolygonFTests
public void AddPoints_ShouldAddPoints() public void AddPoints_ShouldAddPoints()
{ {
var polygon = PolygonF.Empty; var polygon = PolygonF.Empty;
polygon.AddPoints(new[] {new PointF(1, 2), new PointF(3, 4)}); polygon.AddVertices(new[] {new PointF(1, 2), new PointF(3, 4)});
Assert.AreEqual(2, polygon.PointCount); Assert.AreEqual(2, polygon.VertexCount);
// assert that the empty polygon was not modified // assert that the empty polygon was not modified
Assert.AreEqual(0, PolygonF.Empty.PointCount); Assert.AreEqual(0, PolygonF.Empty.VertexCount);
} }
[TestMethod] [TestMethod]
public void ClearPoints_ShouldClearPoints() public void ClearPoints_ShouldClearPoints()
{ {
var polygon = PolygonF.Empty; var polygon = PolygonF.Empty;
polygon.AddPoints(new[] {new Vector2(1, 2), new Vector2(3, 4)}); polygon.AddVertices(new[] {new Vector2(1, 2), new Vector2(3, 4)});
Assert.AreEqual(2, polygon.PointCount); Assert.AreEqual(2, polygon.VertexCount);
// assert that the empty polygon was not modified // assert that the empty polygon was not modified
Assert.AreEqual(0, PolygonF.Empty.PointCount); Assert.AreEqual(0, PolygonF.Empty.VertexCount);
polygon.ClearPoints(); polygon.ClearVertices();
Assert.AreEqual(0, polygon.PointCount); Assert.AreEqual(0, polygon.VertexCount);
} }
[TestMethod] [TestMethod]
@ -39,26 +39,26 @@ public class PolygonFTests
var pointPolygon = new PolygonF(new[] {new PointF(1, 2), new PointF(3, 4)}); var pointPolygon = new PolygonF(new[] {new PointF(1, 2), new PointF(3, 4)});
var vectorPolygon = new PolygonF(new[] {new Vector2(1, 2), new Vector2(3, 4)}); var vectorPolygon = new PolygonF(new[] {new Vector2(1, 2), new Vector2(3, 4)});
Assert.AreEqual(2, pointPolygon.PointCount); Assert.AreEqual(2, pointPolygon.VertexCount);
Assert.AreEqual(2, vectorPolygon.PointCount); Assert.AreEqual(2, vectorPolygon.VertexCount);
} }
[TestMethod] [TestMethod]
public void CopyConstructor_ShouldCopyPoints_GivenPolygon() public void CopyConstructor_ShouldCopyPoints_GivenPolygon()
{ {
var first = PolygonF.Empty; var first = PolygonF.Empty;
first.AddPoints(new[] {new PointF(1, 2), new PointF(3, 4)}); first.AddVertices(new[] {new PointF(1, 2), new PointF(3, 4)});
var second = new PolygonF(first); var second = new PolygonF(first);
Assert.AreEqual(2, first.PointCount); Assert.AreEqual(2, first.VertexCount);
Assert.AreEqual(2, second.PointCount); Assert.AreEqual(2, second.VertexCount);
// we cannot use CollectionAssert here for reasons I am not entirely sure of. // we cannot use CollectionAssert here for reasons I am not entirely sure of.
// it seems to dislike casting from IReadOnlyList<Point> to ICollection. but okay. // it seems to dislike casting from IReadOnlyList<Point> to ICollection. but okay.
Assert.IsTrue(first.Points.SequenceEqual(second.Points)); Assert.IsTrue(first.Vertices.SequenceEqual(second.Vertices));
// assert that the empty polygon was not modified // assert that the empty polygon was not modified
Assert.AreEqual(0, PolygonF.Empty.PointCount); Assert.AreEqual(0, PolygonF.Empty.VertexCount);
} }
[TestMethod] [TestMethod]
@ -135,9 +135,9 @@ public class PolygonFTests
Assert.AreEqual(polygon, converted); Assert.AreEqual(polygon, converted);
Assert.AreEqual(polygon.IsConvex, converted.IsConvex); Assert.AreEqual(polygon.IsConvex, converted.IsConvex);
Assert.AreEqual(polygon.PointCount, converted.PointCount); Assert.AreEqual(polygon.VertexCount, converted.VertexCount);
Assert.IsTrue(polygon.Points.SequenceEqual(converted.Points.Select(p => (PointF)p))); Assert.IsTrue(polygon.Vertices.SequenceEqual(converted.Vertices.Select(p => (PointF)p)));
} }
[TestMethod] [TestMethod]
@ -148,27 +148,27 @@ public class PolygonFTests
Assert.AreEqual(polygon, converted); Assert.AreEqual(polygon, converted);
Assert.AreEqual(polygon.IsConvex, converted.IsConvex); Assert.AreEqual(polygon.IsConvex, converted.IsConvex);
Assert.AreEqual(polygon.PointCount, converted.PointCount); Assert.AreEqual(polygon.VertexCount, converted.VertexCount);
Assert.IsTrue(converted.Points.SequenceEqual(polygon.Points.Select(p => (PointF)p))); Assert.IsTrue(converted.Vertices.SequenceEqual(polygon.Vertices.Select(p => (PointF)p)));
} }
[TestMethod] [TestMethod]
public void PointCount_ShouldBe1_GivenPolygonFWith1Point() public void PointCount_ShouldBe1_GivenPolygonFWith1Point()
{ {
var polygon = new PolygonF(); var polygon = new PolygonF();
polygon.AddPoint(new Point(1, 1)); polygon.AddVertex(new Point(1, 1));
Assert.AreEqual(1, polygon.PointCount); Assert.AreEqual(1, polygon.VertexCount);
// assert that the empty polygon was not modified // assert that the empty polygon was not modified
Assert.AreEqual(0, PolygonF.Empty.PointCount); Assert.AreEqual(0, PolygonF.Empty.VertexCount);
} }
[TestMethod] [TestMethod]
public void PointCount_ShouldBe0_GivenEmptyPolygon() public void PointCount_ShouldBe0_GivenEmptyPolygon()
{ {
Assert.AreEqual(0, PolygonF.Empty.PointCount); Assert.AreEqual(0, PolygonF.Empty.VertexCount);
} }
[TestMethod] [TestMethod]
@ -182,23 +182,23 @@ public class PolygonFTests
internal static PolygonF CreateHexagon() internal static PolygonF CreateHexagon()
{ {
var hexagon = new PolygonF(); var hexagon = new PolygonF();
hexagon.AddPoint(new Vector2(0, 0)); hexagon.AddVertex(new Vector2(0, 0));
hexagon.AddPoint(new Vector2(1, 0)); hexagon.AddVertex(new Vector2(1, 0));
hexagon.AddPoint(new Vector2(1, 1)); hexagon.AddVertex(new Vector2(1, 1));
hexagon.AddPoint(new Vector2(0, 1)); hexagon.AddVertex(new Vector2(0, 1));
hexagon.AddPoint(new Vector2(-1, 1)); hexagon.AddVertex(new Vector2(-1, 1));
hexagon.AddPoint(new Vector2(-1, 0)); hexagon.AddVertex(new Vector2(-1, 0));
return hexagon; return hexagon;
} }
internal static PolygonF CreateConcavePolygon() internal static PolygonF CreateConcavePolygon()
{ {
var hexagon = new PolygonF(); var hexagon = new PolygonF();
hexagon.AddPoint(new Vector2(0, 0)); hexagon.AddVertex(new Vector2(0, 0));
hexagon.AddPoint(new Vector2(2, 0)); hexagon.AddVertex(new Vector2(2, 0));
hexagon.AddPoint(new Vector2(1, 1)); hexagon.AddVertex(new Vector2(1, 1));
hexagon.AddPoint(new Vector2(2, 1)); hexagon.AddVertex(new Vector2(2, 1));
hexagon.AddPoint(new Vector2(0, 1)); hexagon.AddVertex(new Vector2(0, 1));
return hexagon; return hexagon;
} }
} }

View File

@ -11,44 +11,44 @@ public class PolygonTests
public void AddPoints_ShouldAddPoints() public void AddPoints_ShouldAddPoints()
{ {
var polygon = Polygon.Empty; var polygon = Polygon.Empty;
polygon.AddPoints(new[] {new Point(1, 2), new Point(3, 4)}); polygon.AddVertices(new[] {new Point(1, 2), new Point(3, 4)});
Assert.AreEqual(2, polygon.PointCount); Assert.AreEqual(2, polygon.VertexCount);
// assert that the empty polygon was not modified // assert that the empty polygon was not modified
Assert.AreEqual(0, Polygon.Empty.PointCount); Assert.AreEqual(0, Polygon.Empty.VertexCount);
} }
[TestMethod] [TestMethod]
public void ClearPoints_ShouldClearPoints() public void ClearPoints_ShouldClearPoints()
{ {
var polygon = Polygon.Empty; var polygon = Polygon.Empty;
polygon.AddPoints(new[] {new Point(1, 2), new Point(3, 4)}); polygon.AddVertices(new[] {new Point(1, 2), new Point(3, 4)});
Assert.AreEqual(2, polygon.PointCount); Assert.AreEqual(2, polygon.VertexCount);
// assert that the empty polygon was not modified // assert that the empty polygon was not modified
Assert.AreEqual(0, PolygonF.Empty.PointCount); Assert.AreEqual(0, PolygonF.Empty.VertexCount);
polygon.ClearPoints(); polygon.ClearVertices();
Assert.AreEqual(0, polygon.PointCount); Assert.AreEqual(0, polygon.VertexCount);
} }
[TestMethod] [TestMethod]
public void CopyConstructor_ShouldCopyPoints_GivenPolygon() public void CopyConstructor_ShouldCopyPoints_GivenPolygon()
{ {
var first = Polygon.Empty; var first = Polygon.Empty;
first.AddPoints(new[] {new Point(1, 2), new Point(3, 4)}); first.AddVertices(new[] {new Point(1, 2), new Point(3, 4)});
var second = new Polygon(first); var second = new Polygon(first);
Assert.AreEqual(2, first.PointCount); Assert.AreEqual(2, first.VertexCount);
Assert.AreEqual(2, second.PointCount); Assert.AreEqual(2, second.VertexCount);
// we cannot use CollectionAssert here for reasons I am not entirely sure of. // we cannot use CollectionAssert here for reasons I am not entirely sure of.
// it seems to dislike casting from IReadOnlyList<Point> to ICollection. but okay. // it seems to dislike casting from IReadOnlyList<Point> to ICollection. but okay.
Assert.IsTrue(first.Points.SequenceEqual(second.Points)); Assert.IsTrue(first.Vertices.SequenceEqual(second.Vertices));
// assert that the empty polygon was not modified // assert that the empty polygon was not modified
Assert.AreEqual(0, Polygon.Empty.PointCount); Assert.AreEqual(0, Polygon.Empty.VertexCount);
} }
[TestMethod] [TestMethod]
@ -121,18 +121,18 @@ public class PolygonTests
public void PointCount_ShouldBe1_GivenPolygonWith1Point() public void PointCount_ShouldBe1_GivenPolygonWith1Point()
{ {
var polygon = Polygon.Empty; var polygon = Polygon.Empty;
polygon.AddPoint(new Point(1, 1)); polygon.AddVertex(new Point(1, 1));
Assert.AreEqual(1, polygon.PointCount); Assert.AreEqual(1, polygon.VertexCount);
// assert that the empty polygon was not modified // assert that the empty polygon was not modified
Assert.AreEqual(0, Polygon.Empty.PointCount); Assert.AreEqual(0, Polygon.Empty.VertexCount);
} }
[TestMethod] [TestMethod]
public void PointCount_ShouldBe0_GivenEmptyPolygon() public void PointCount_ShouldBe0_GivenEmptyPolygon()
{ {
Assert.AreEqual(0, Polygon.Empty.PointCount); Assert.AreEqual(0, Polygon.Empty.VertexCount);
} }
[TestMethod] [TestMethod]
@ -146,23 +146,23 @@ public class PolygonTests
internal static Polygon CreateHexagon() internal static Polygon CreateHexagon()
{ {
var hexagon = new Polygon(); var hexagon = new Polygon();
hexagon.AddPoint(new Point(0, 0)); hexagon.AddVertex(new Point(0, 0));
hexagon.AddPoint(new Point(1, 0)); hexagon.AddVertex(new Point(1, 0));
hexagon.AddPoint(new Point(1, 1)); hexagon.AddVertex(new Point(1, 1));
hexagon.AddPoint(new Point(0, 1)); hexagon.AddVertex(new Point(0, 1));
hexagon.AddPoint(new Point(-1, 1)); hexagon.AddVertex(new Point(-1, 1));
hexagon.AddPoint(new Point(-1, 0)); hexagon.AddVertex(new Point(-1, 0));
return hexagon; return hexagon;
} }
internal static Polygon CreateConcavePolygon() internal static Polygon CreateConcavePolygon()
{ {
var hexagon = new Polygon(); var hexagon = new Polygon();
hexagon.AddPoint(new Point(0, 0)); hexagon.AddVertex(new Point(0, 0));
hexagon.AddPoint(new Point(2, 0)); hexagon.AddVertex(new Point(2, 0));
hexagon.AddPoint(new Point(1, 1)); hexagon.AddVertex(new Point(1, 1));
hexagon.AddPoint(new Point(2, 1)); hexagon.AddVertex(new Point(2, 1));
hexagon.AddPoint(new Point(0, 1)); hexagon.AddVertex(new Point(0, 1));
return hexagon; return hexagon;
} }
} }

View File

@ -3,32 +3,39 @@
namespace X10D.Drawing; namespace X10D.Drawing;
/// <summary> /// <summary>
/// Represents a 2D polygon composed of 32-bit signed integer points. /// Represents a 2D polygon composed of 32-bit signed integer vertices.
/// </summary> /// </summary>
public struct Polygon : IEquatable<Polygon> public class Polygon : IEquatable<Polygon>
{ {
/// <summary> /// <summary>
/// The empty polygon. That is, a polygon with no points. /// The empty polygon. That is, a polygon with no vertices.
/// </summary> /// </summary>
public static readonly Polygon Empty = new(); public static readonly Polygon Empty = new();
private Point[]? _points; private readonly List<Point> _vertices = new();
/// <summary>
/// Initializes a new instance of the <see cref="Polygon" /> class.
/// </summary>
public Polygon()
{
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Polygon" /> struct by copying the specified polygon. /// Initializes a new instance of the <see cref="Polygon" /> struct by copying the specified polygon.
/// </summary> /// </summary>
public Polygon(Polygon polygon) public Polygon(Polygon polygon)
: this(polygon._points ?? ArraySegment<Point>.Empty) : this(polygon._vertices)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Polygon" /> struct by constructing it from the specified points. /// Initializes a new instance of the <see cref="Polygon" /> struct by constructing it from the specified vertices.
/// </summary> /// </summary>
/// <param name="points">An enumerable collection of points from which the polygon should be constructed.</param> /// <param name="vertices">An enumerable collection of vertices from which the polygon should be constructed.</param>
public Polygon(IEnumerable<Point> points) public Polygon(IEnumerable<Point> vertices)
{ {
_points = points.ToArray(); _vertices = new List<Point>(vertices);
} }
/// <summary> /// <summary>
@ -39,18 +46,18 @@ public struct Polygon : IEquatable<Polygon>
{ {
get get
{ {
if (_points is null || _points.Length < 3) if (_vertices.Count < 3)
{ {
return false; return false;
} }
var positive = false; var positive = false;
var negative = false; var negative = false;
Point p0 = _points[0]; Point p0 = _vertices[0];
for (var index = 1; index < _points.Length; index++) for (var index = 1; index < _vertices.Count; index++)
{ {
Point p1 = _points[index]; Point p1 = _vertices[index];
int d = (p1.X - p0.X) * (p1.Y + p0.Y); int d = (p1.X - p0.X) * (p1.Y + p0.Y);
if (d > 0) if (d > 0)
@ -75,21 +82,23 @@ public struct Polygon : IEquatable<Polygon>
} }
/// <summary> /// <summary>
/// Gets the number of points in this polygon. /// Gets the number of vertices in this polygon.
/// </summary> /// </summary>
/// <value>An <see cref="int" /> value, representing the number of points in this polygon.</value> /// <value>An <see cref="int" /> value, representing the number of vertices in this polygon.</value>
public int PointCount public int VertexCount
{ {
get => _points?.Length ?? 0; get => _vertices.Count;
} }
/// <summary> /// <summary>
/// Gets a read-only view of the points in this polygon. /// Gets a read-only view of the vertices in this polygon.
/// </summary> /// </summary>
/// <value>A <see cref="IReadOnlyList{T}" /> of <see cref="Point" /> values, representing the points of this polygon.</value> /// <value>
public IReadOnlyList<Point> Points /// A <see cref="IReadOnlyList{T}" /> of <see cref="Point" /> values, representing the vertices of this polygon.
/// </value>
public IReadOnlyList<Point> Vertices
{ {
get => _points?.ToArray() ?? ArraySegment<Point>.Empty; get => _vertices.AsReadOnly();
} }
/// <summary> /// <summary>
@ -121,46 +130,42 @@ public struct Polygon : IEquatable<Polygon>
} }
/// <summary> /// <summary>
/// Adds a point to this polygon. /// Adds a vertex to this polygon.
/// </summary> /// </summary>
/// <param name="point">The point to add.</param> /// <param name="vertex">The vertex to add.</param>
public void AddPoint(Point point) public void AddVertex(Point vertex)
{ {
_points ??= Array.Empty<Point>(); _vertices.Add(vertex);
Span<Point> span = stackalloc Point[_points.Length + 1];
_points.CopyTo(span);
span[^1] = point;
_points = span.ToArray();
} }
/// <summary> /// <summary>
/// Adds a collection of points to this polygon. /// Adds a collection of vertices to this polygon.
/// </summary> /// </summary>
/// <param name="points">An enumerable collection of points to add.</param> /// <param name="vertices">An enumerable collection of vertices to add.</param>
/// <exception cref="ArgumentNullException"><paramref name="points" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="vertices" /> is <see langword="null" />.</exception>
public void AddPoints(IEnumerable<Point> points) public void AddVertices(IEnumerable<Point> vertices)
{ {
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(points); ArgumentNullException.ThrowIfNull(vertices);
#else #else
if (points is null) if (vertices is null)
{ {
throw new ArgumentNullException(nameof(points)); throw new ArgumentNullException(nameof(vertices));
} }
#endif #endif
foreach (Point point in points) foreach (Point vertex in vertices)
{ {
AddPoint(point); AddVertex(vertex);
} }
} }
/// <summary> /// <summary>
/// Clears all points from this polygon. /// Clears all vertices from this polygon.
/// </summary> /// </summary>
public void ClearPoints() public void ClearVertices()
{ {
_points = Array.Empty<Point>(); _vertices.Clear();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -179,19 +184,12 @@ public struct Polygon : IEquatable<Polygon>
/// </returns> /// </returns>
public bool Equals(Polygon other) public bool Equals(Polygon other)
{ {
return _points switch return _vertices.SequenceEqual(other._vertices);
{
null when other._points is null => true,
null => false,
not null when other._points is null => false,
_ => _points.SequenceEqual(other._points)
};
} }
/// <inheritdoc /> /// <inheritdoc />
public override int GetHashCode() public override int GetHashCode()
{ {
Point[] points = _points ?? Array.Empty<Point>(); return _vertices.Aggregate(0, HashCode.Combine);
return points.Aggregate(0, HashCode.Combine);
} }
} }

View File

@ -5,59 +5,66 @@ using X10D.Numerics;
namespace X10D.Drawing; namespace X10D.Drawing;
/// <summary> /// <summary>
/// Represents a 2D polygon composed of single-precision floating-point points. /// Represents a 2D polygon composed of single-precision floating-vertex vertices.
/// </summary> /// </summary>
public struct PolygonF public class PolygonF
{ {
/// <summary> /// <summary>
/// The empty polygon. That is, a polygon with no points. /// The empty polygon. That is, a polygon with no vertices.
/// </summary> /// </summary>
public static readonly PolygonF Empty = new(); public static readonly PolygonF Empty = new();
private PointF[]? _points; private readonly List<PointF> _vertices = new();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PolygonF" /> struct by copying the specified polygon. /// Initializes a new instance of the <see cref="PolygonF" /> class.
/// </summary>
public PolygonF()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PolygonF" /> class by copying the specified polygon.
/// </summary> /// </summary>
public PolygonF(PolygonF polygon) public PolygonF(PolygonF polygon)
: this(polygon._points ?? Array.Empty<PointF>()) : this(polygon._vertices)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PolygonF" /> struct by constructing it from the specified points. /// Initializes a new instance of the <see cref="PolygonF" /> class by constructing it from the specified vertices.
/// </summary> /// </summary>
/// <param name="points">An enumerable collection of points from which the polygon should be constructed.</param> /// <param name="vertices">An enumerable collection of vertices from which the polygon should be constructed.</param>
public PolygonF(IEnumerable<Vector2> points) public PolygonF(IEnumerable<Vector2> vertices)
: this(points.Select(p => p.ToPointF())) : this(vertices.Select(p => p.ToPointF()))
{ {
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(points); ArgumentNullException.ThrowIfNull(vertices);
#else #else
if (points is null) if (vertices is null)
{ {
throw new ArgumentNullException(nameof(points)); throw new ArgumentNullException(nameof(vertices));
} }
#endif #endif
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PolygonF" /> struct by constructing it from the specified points. /// Initializes a new instance of the <see cref="PolygonF" /> class by constructing it from the specified vertices.
/// </summary> /// </summary>
/// <param name="points">An enumerable collection of points from which the polygon should be constructed.</param> /// <param name="vertices">An enumerable collection of vertices from which the polygon should be constructed.</param>
/// <exception cref="ArgumentNullException"><paramref name="points" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="vertices" /> is <see langword="null" />.</exception>
public PolygonF(IEnumerable<PointF> points) public PolygonF(IEnumerable<PointF> vertices)
{ {
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(points); ArgumentNullException.ThrowIfNull(vertices);
#else #else
if (points is null) if (vertices is null)
{ {
throw new ArgumentNullException(nameof(points)); throw new ArgumentNullException(nameof(vertices));
} }
#endif #endif
_points = points.ToArray(); _vertices = new List<PointF>(vertices);
} }
/// <summary> /// <summary>
@ -68,18 +75,18 @@ public struct PolygonF
{ {
get get
{ {
if (_points is null || _points.Length < 3) if (_vertices.Count < 3)
{ {
return false; return false;
} }
var positive = false; var positive = false;
var negative = false; var negative = false;
PointF p0 = _points[0]; PointF p0 = _vertices[0];
for (var index = 1; index < _points.Length; index++) for (var index = 1; index < _vertices.Count; index++)
{ {
PointF p1 = _points[index]; PointF p1 = _vertices[index];
float d = (p1.X - p0.X) * (p1.Y + p0.Y); float d = (p1.X - p0.X) * (p1.Y + p0.Y);
if (d > 0) if (d > 0)
@ -104,21 +111,23 @@ public struct PolygonF
} }
/// <summary> /// <summary>
/// Gets the number of points in this polygon. /// Gets the number of vertices in this polygon.
/// </summary> /// </summary>
/// <value>An <see cref="int" /> value, representing the number of points in this polygon.</value> /// <value>An <see cref="int" /> value, representing the number of vertices in this polygon.</value>
public int PointCount public int VertexCount
{ {
get => _points?.Length ?? 0; get => _vertices.Count;
} }
/// <summary> /// <summary>
/// Gets a read-only view of the points in this polygon. /// Gets a read-only view of the vertices in this polygon.
/// </summary> /// </summary>
/// <value>A <see cref="IReadOnlyList{T}" /> of <see cref="PointF" /> values, representing the points of this polygon.</value> /// <value>
public IReadOnlyList<PointF> Points /// A <see cref="IReadOnlyList{T}" /> of <see cref="PointF" /> values, representing the vertices of this polygon.
/// </value>
public IReadOnlyList<PointF> Vertices
{ {
get => _points?.ToArray() ?? ArraySegment<PointF>.Empty; get => _vertices.AsReadOnly();
} }
/// <summary> /// <summary>
@ -156,14 +165,14 @@ public struct PolygonF
/// <returns>The converted polygon.</returns> /// <returns>The converted polygon.</returns>
public static explicit operator Polygon(PolygonF polygon) public static explicit operator Polygon(PolygonF polygon)
{ {
var points = new List<Point>(); var vertices = new List<Point>();
foreach (PointF point in polygon.Points) foreach (PointF vertex in polygon.Vertices)
{ {
points.Add(new Point((int)point.X, (int)point.Y)); vertices.Add(new Point((int)vertex.X, (int)vertex.Y));
} }
return new Polygon(points); return new Polygon(vertices);
} }
/// <summary> /// <summary>
@ -173,88 +182,84 @@ public struct PolygonF
/// <returns>The converted polygon.</returns> /// <returns>The converted polygon.</returns>
public static implicit operator PolygonF(Polygon polygon) public static implicit operator PolygonF(Polygon polygon)
{ {
var points = new List<PointF>(); var vertices = new List<PointF>();
foreach (Point point in polygon.Points) foreach (Point vertex in polygon.Vertices)
{ {
points.Add(point); vertices.Add(vertex);
} }
return new PolygonF(points); return new PolygonF(vertices);
} }
/// <summary> /// <summary>
/// Adds a point to this polygon. /// Adds a vertex to this polygon.
/// </summary> /// </summary>
/// <param name="point">The point to add.</param> /// <param name="vertex">The vertex to add.</param>
public void AddPoint(PointF point) public void AddVertex(PointF vertex)
{ {
_points ??= Array.Empty<PointF>(); _vertices.Add(vertex);
Span<PointF> span = stackalloc PointF[_points.Length + 1];
_points.CopyTo(span);
span[^1] = point;
_points = span.ToArray();
} }
/// <summary> /// <summary>
/// Adds a point to this polygon. /// Adds a vertex to this polygon.
/// </summary> /// </summary>
/// <param name="point">The point to add.</param> /// <param name="vertex">The vertex to add.</param>
public void AddPoint(Vector2 point) public void AddVertex(Vector2 vertex)
{ {
AddPoint(point.ToPointF()); AddVertex(vertex.ToPointF());
} }
/// <summary> /// <summary>
/// Adds a collection of points to this polygon. /// Adds a collection of vertices to this polygon.
/// </summary> /// </summary>
/// <param name="points">An enumerable collection of points to add.</param> /// <param name="vertices">An enumerable collection of vertices to add.</param>
/// <exception cref="ArgumentNullException"><paramref name="points" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="vertices" /> is <see langword="null" />.</exception>
public void AddPoints(IEnumerable<PointF> points) public void AddVertices(IEnumerable<PointF> vertices)
{ {
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(points); ArgumentNullException.ThrowIfNull(vertices);
#else #else
if (points is null) if (vertices is null)
{ {
throw new ArgumentNullException(nameof(points)); throw new ArgumentNullException(nameof(vertices));
} }
#endif #endif
foreach (PointF point in points) foreach (PointF vertex in vertices)
{ {
AddPoint(point); AddVertex(vertex);
} }
} }
/// <summary> /// <summary>
/// Adds a collection of points to this polygon. /// Adds a collection of vertices to this polygon.
/// </summary> /// </summary>
/// <param name="points">An enumerable collection of points to add.</param> /// <param name="vertices">An enumerable collection of vertices to add.</param>
/// <exception cref="ArgumentNullException"><paramref name="points" /> is <see langword="null" />.</exception> /// <exception cref="ArgumentNullException"><paramref name="vertices" /> is <see langword="null" />.</exception>
public void AddPoints(IEnumerable<Vector2> points) public void AddVertices(IEnumerable<Vector2> vertices)
{ {
#if NET6_0_OR_GREATER #if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(points); ArgumentNullException.ThrowIfNull(vertices);
#else #else
if (points is null) if (vertices is null)
{ {
throw new ArgumentNullException(nameof(points)); throw new ArgumentNullException(nameof(vertices));
} }
#endif #endif
foreach (Vector2 point in points) foreach (Vector2 vertex in vertices)
{ {
AddPoint(point); AddVertex(vertex);
} }
} }
/// <summary> /// <summary>
/// Clears all points from this polygon. /// Clears all vertices from this polygon.
/// </summary> /// </summary>
public void ClearPoints() public void ClearVertices()
{ {
_points = Array.Empty<PointF>(); _vertices.Clear();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -273,19 +278,12 @@ public struct PolygonF
/// </returns> /// </returns>
public bool Equals(PolygonF other) public bool Equals(PolygonF other)
{ {
return _points switch return _vertices.SequenceEqual(other._vertices);
{
null when other._points is null => true,
null => false,
not null when other._points is null => false,
_ => _points.SequenceEqual(other._points)
};
} }
/// <inheritdoc /> /// <inheritdoc />
public override int GetHashCode() public override int GetHashCode()
{ {
PointF[] points = _points ?? Array.Empty<PointF>(); return _vertices.Aggregate(0, HashCode.Combine);
return points.Aggregate(0, HashCode.Combine);
} }
} }