diff --git a/CHANGELOG.md b/CHANGELOG.md index c7aa94d..4d659e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 3.2.0 ### Added - X10D: Added `MathUtility.InverseLerp(float, float, float)` and `MathUtility.InverseLerp(double, double, double)` -- X10D: Added `Circle`, `CircleF`, `Ellipse`, `EllipseF` `Line`, `LineF`, `Line3D`, `Polygon`, and `PolygonF`, to complement System.Drawing structs such as `Point` and `Rectangle` +- X10D: Added `Circle`, `CircleF`, `Cuboid`, `Ellipse`, `EllipseF`, `Line3D`, `Line`, `LineF`, `Polygon`, `PolygonF`, `Polyhedron`, and `Sphere`, to complement System.Drawing structs such as `Point` and `Rectangle` - X10D: Added `Point.ToSize()` - X10D: Added `Point.ToSizeF()` - X10D: Added `Point.ToVector2()` diff --git a/X10D/src/Drawing/Polyhedron.cs b/X10D/src/Drawing/Polyhedron.cs new file mode 100644 index 0000000..9c2eecc --- /dev/null +++ b/X10D/src/Drawing/Polyhedron.cs @@ -0,0 +1,227 @@ +using System.Drawing; +using System.Numerics; + +namespace X10D.Drawing; + +/// +/// Represents a 3D polyhedron composed of single-precision floating-point points. +/// +public class Polyhedron : IEquatable +{ + /// + /// The empty polyhedron. That is, a polyhedron with no points. + /// + public static readonly Polyhedron Empty = new(); + + private readonly List _vertices = new(); + + /// + /// Initializes a new instance of the class. + /// + public Polyhedron() + { + } + + /// + /// Initializes a new instance of the struct by copying the specified polyhedron. + /// + public Polyhedron(Polyhedron polyhedron) + : this(polyhedron._vertices) + { + } + + /// + /// Initializes a new instance of the struct by constructing it from the specified vertices. + /// + /// An enumerable collection of vertices from which the polyhedron should be constructed. + public Polyhedron(IEnumerable vertices) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(vertices); +#else + if (vertices is null) + { + throw new ArgumentNullException(nameof(vertices)); + } +#endif + + _vertices = new List(vertices); + } + + /// + /// Returns a value indicating whether this polyhedron is convex. + /// + /// if this polyhedron is convex; otherwise, . + public bool IsConvex + { + get + { + if (_vertices.Count < 4) + { + return false; + } + + Vector3[] vertices = _vertices.ToArray(); + int n = vertices.Length; + + for (var i = 0; i < n; i++) + { + int j = (i + 1) % n; + int k = (i + 2) % n; + + if (Vector3.Cross(vertices[j] - vertices[i], vertices[k] - vertices[j]).LengthSquared() < 1e-6f) + { + return false; + } + } + + return true; + } + } + + /// + /// Gets the number of vertices in this polyhedron. + /// + /// An value, representing the number of vertices in this polyhedron. + public int VertexCount + { + get => _vertices.Count; + } + + /// + /// Gets a read-only view of the vertices in this polyhedron. + /// + /// + /// A of values, representing the vertices of this polyhedron. + /// + public IReadOnlyList Vertices + { + get => _vertices.AsReadOnly(); + } + + /// + /// Returns a value indicating whether two instances of are equal. + /// + /// The first instance. + /// The second instance. + /// + /// if and are considered equal; otherwise, + /// . + /// + public static bool operator ==(Polyhedron left, Polyhedron right) + { + return left.Equals(right); + } + + /// + /// Returns a value indicating whether two instances of are not equal. + /// + /// The first instance. + /// The second instance. + /// + /// if and are considered not equal; otherwise, + /// . + /// + public static bool operator !=(Polyhedron left, Polyhedron right) + { + return !left.Equals(right); + } + + /// + /// Implicitly converts a to a . + /// + /// The polyhedron to convert. + /// The converted polyhedron. + public static implicit operator Polyhedron(Polygon polygon) + { + var points = new List(); + + foreach (Point point in polygon.Vertices) + { + points.Add(new Vector3(point.X, point.Y, 0)); + } + + return new Polyhedron(points); + } + + /// + /// Implicitly converts a to a . + /// + /// The polyhedron to convert. + /// The converted polyhedron. + public static implicit operator Polyhedron(PolygonF polygon) + { + var points = new List(); + + foreach (PointF point in polygon.Vertices) + { + points.Add(new Vector3(point.X, point.Y, 0)); + } + + return new Polyhedron(points); + } + + /// + /// Adds a vertex to this polyhedron. + /// + /// The vertex to add. + public void AddVertex(Vector3 vertex) + { + _vertices.Add(vertex); + } + + /// + /// Adds a collection of vertices to this polyhedron. + /// + /// An enumerable collection of vertices to add. + /// is . + public void AddVertices(IEnumerable vertices) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(vertices); +#else + if (vertices is null) + { + throw new ArgumentNullException(nameof(vertices)); + } +#endif + + foreach (Vector3 vertex in vertices) + { + AddVertex(vertex); + } + } + + /// + /// Clears all vertices from this polyhedron. + /// + public void ClearVertices() + { + _vertices.Clear(); + } + + /// + public override bool Equals(object? obj) + { + return obj is Polyhedron polyhedron && Equals(polyhedron); + } + + /// + /// Returns a value indicating whether this instance and another instance are equal. + /// + /// The instance with which to compare. + /// + /// if this instance and are considered equal; otherwise, + /// . + /// + public bool Equals(Polyhedron other) + { + return _vertices.SequenceEqual(other._vertices); + } + + /// + public override int GetHashCode() + { + return _vertices.Aggregate(0, HashCode.Combine); + } +}