From 025791101857c2d0f482c975bd91e0ab1755af54 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 1 Feb 2024 12:32:58 +0300 Subject: [PATCH] docs(physics2d): Primitives --- Engine.Physics2D/Primitives/AABB.cs | 57 ++++++- Engine.Physics2D/Primitives/Circle.cs | 78 ++++++++- Engine.Physics2D/Primitives/Line.cs | 171 +++++++++++++------- Engine.Physics2D/Primitives/LineEquation.cs | 49 +++++- Engine.Physics2D/Primitives/Projection.cs | 53 +++++- Engine.Physics2D/Primitives/Shape.cs | 149 ++++++++++++++++- 6 files changed, 478 insertions(+), 79 deletions(-) diff --git a/Engine.Physics2D/Primitives/AABB.cs b/Engine.Physics2D/Primitives/AABB.cs index e165fd8..f27df37 100644 --- a/Engine.Physics2D/Primitives/AABB.cs +++ b/Engine.Physics2D/Primitives/AABB.cs @@ -4,16 +4,47 @@ using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; +/// +/// Represents an Axis-Aligned Bounding Box (AABB) in 2D space. +/// +/// The lower boundary of the . +/// The upper boundary of the . +/// +/// Initializes a new instance of the struct with the specified lower and upper boundaries. +/// [System.Diagnostics.DebuggerDisplay("LowerBoundary: {LowerBoundary.ToString(), nq}, UpperBoundary: {UpperBoundary.ToString(), nq}")] -public readonly struct AABB(Vector2D LowerBoundary, Vector2D UpperBoundary) +public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) { - public readonly Vector2D LowerBoundary { get; init; } = LowerBoundary; - public readonly Vector2D UpperBoundary { get; init; } = UpperBoundary; + /// + /// The lower boundary of the . + /// + public readonly Vector2D LowerBoundary = lowerBoundary; + /// + /// The upper boundary of the . + /// + public readonly Vector2D UpperBoundary = upperBoundary; + + /// + /// Gets the center point of the . + /// public readonly Vector2D Center => (LowerBoundary + UpperBoundary) * .5f; + + /// + /// Gets the size of the . + /// public readonly Vector2D Size => LowerBoundary.FromTo(UpperBoundary).Abs(); + + /// + /// Gets half the size of the . + /// public readonly Vector2D SizeHalf => Size * .5f; + /// + /// Creates an from a collection of s. + /// + /// The collection of s. + /// An that bounds all the s. public static AABB FromVectors(IEnumerable vectors) { int counter = 0; @@ -34,13 +65,33 @@ public readonly struct AABB(Vector2D LowerBoundary, Vector2D UpperBoundary) return new(lowerBoundary, upperBoundary); } + /// + /// Checks if two s are approximately equal. + /// + /// The first . + /// The second . + /// if the s are approximately equal; otherwise, . public static bool ApproximatelyEquals(AABB left, AABB right) => left.LowerBoundary.ApproximatelyEquals(right.LowerBoundary) && left.UpperBoundary.ApproximatelyEquals(right.UpperBoundary); } +/// +/// Provides extension methods for the struct. +/// public static class AABBExtensions { + /// + /// Converts a collection of s to an . + /// + /// The collection of s. + /// An that bounds all the s. public static AABB ToAABB(this IEnumerable vectors) => AABB.FromVectors(vectors); + /// + /// Checks if two s are approximately equal. + /// + /// The first . + /// The second . + /// if the s are approximately equal; otherwise, . public static bool ApproximatelyEquals(this AABB left, AABB right) => AABB.ApproximatelyEquals(left, right); } diff --git a/Engine.Physics2D/Primitives/Circle.cs b/Engine.Physics2D/Primitives/Circle.cs index 2be2b56..c760edb 100644 --- a/Engine.Physics2D/Primitives/Circle.cs +++ b/Engine.Physics2D/Primitives/Circle.cs @@ -1,47 +1,115 @@ +using System.Diagnostics; + using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Physics2D.Primitives; -[System.Diagnostics.DebuggerDisplay("Center: {Center.ToString(), nq}, Radius: {Radius}")] -public readonly struct Circle(Vector2D Center, float Radius) +/// +/// Represents a 2D circle. +/// +/// The center of the circle. +/// The radius of the circle. +/// +/// Initializes a new instance of the Circle struct with the specified center and radius. +/// +[DebuggerDisplay("Center: {Center.ToString(),nq}, Radius: {Radius}")] +public readonly struct Circle(Vector2D center, float radius) { - public static readonly Circle UnitCircle = new(Vector2D.Zero, 1f); + /// + /// The center of the circle. + /// + public readonly Vector2D Center = center; - public readonly Vector2D Center { get; init; } = Center; - public readonly float Radius { get; init; } = Radius; + /// + /// The radius of the . + /// + public readonly float Radius = radius; + /// + /// Gets the squared radius of the . + /// public readonly float RadiusSquared => Radius * Radius; + + /// + /// Gets the diameter of the . + /// public readonly float Diameter => 2f * Radius; + /// + /// A predefined unit with a center at the origin and a radius of 1. + /// + public static readonly Circle UnitCircle = new(Vector2D.Zero, 1f); + + /// + /// Sets the center of the . + /// public static Circle SetCenter(Circle circle, Vector2D center) => new(center, circle.Radius); + + /// + /// Sets the radius of the . + /// public static Circle SetRadius(Circle circle, float radius) => new(circle.Center, radius); + /// + /// Displaces the by the specified . + /// public static Circle Displace(Circle circle, Vector2D displaceVector) => new(circle.Center + displaceVector, circle.Radius); + /// + /// Projects the onto the specified . + /// public static Projection Project(Circle circle, Vector2D projectionVector) { float projectedCenter = circle.Center.Dot(projectionVector); return new(projectedCenter - circle.Radius, projectedCenter + circle.Radius); } + /// + /// Transforms the by the specified . + /// public static Circle TransformCircle(ITransform transform, Circle circle) => new(transform.TransformVector2D(circle.Center), circle.Radius * transform.Scale.Magnitude); + /// + /// Checks if two s are approximately equal. + /// public static bool ApproximatelyEquals(Circle left, Circle right) => left.Center.ApproximatelyEquals(right.Center) && left.Radius.ApproximatelyEquals(right.Radius); } +/// +/// Provides extension methods for the struct. +/// public static class CircleExtensions { + /// + /// Sets the center of the . + /// public static Circle SetCenter(this Circle circle, Vector2D center) => Circle.SetCenter(circle, center); + + /// + /// Sets the radius of the . + /// public static Circle SetRadius(this Circle circle, float radius) => Circle.SetRadius(circle, radius); + /// + /// Moves the by the specified . + /// public static Circle Displace(this Circle circle, Vector2D displaceVector) => Circle.Displace(circle, displaceVector); + /// + /// Projects the onto the specified . + /// public static Projection ToProjection(this Circle circle, Vector2D projectionVector) => Circle.Project(circle, projectionVector); + /// + /// Transforms the by the specified . + /// public static Circle TransformCircle(this ITransform transform, Circle circle) => Circle.TransformCircle(transform, circle); + /// + /// Checks if two s are approximately equal. + /// public static bool ApproximatelyEquals(this Circle left, Circle right) => Circle.ApproximatelyEquals(left, right); } diff --git a/Engine.Physics2D/Primitives/Line.cs b/Engine.Physics2D/Primitives/Line.cs index 7d0f1ec..10d5df7 100644 --- a/Engine.Physics2D/Primitives/Line.cs +++ b/Engine.Physics2D/Primitives/Line.cs @@ -1,22 +1,54 @@ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -[System.Diagnostics.DebuggerDisplay("From: {From.ToString(), nq}, To: {To.ToString(), nq}, Direction: {Direction.ToString(), nq}, Length: {Length}")] -public readonly struct Line(Vector2D From, Vector2D To) +/// +/// Represents a 2D line segment defined by two endpoints. +/// +/// +/// Initializes a new instance of the Line struct with the specified endpoints. +/// +/// The starting point of the segment. +/// The ending point of the segment. +[System.Diagnostics.DebuggerDisplay("From: {From.ToString(),nq}, To: {To.ToString(),nq}, Direction: {Direction.ToString(),nq}, Length: {Length}")] +public readonly struct Line(Vector2D from, Vector2D to) { - public readonly Vector2D From { get; init; } = From; - public readonly Vector2D To { get; init; } = To; + /// + /// The starting point of the segment. + /// + public readonly Vector2D From = from; + /// + /// The ending point of the segment. + /// + public readonly Vector2D To = to; + + /// + /// The reversed segment. + /// public readonly Line Reversed => new(To, From); + + /// + /// The normalized direction of the segment. + /// public readonly Vector2D Direction => From.FromTo(To).Normalize(); + + /// + /// The length of the segment. + /// public readonly float Length => From.FromTo(To).Length(); + + /// + /// The squared length of the segment. + /// public readonly float LengthSquared => From.FromTo(To).LengthSquared(); + /// + /// The equation of the defined by this segment. + /// public static LineEquation GetLineEquation(Line line) { Vector2D slopeVector = line.From.FromTo(line.To); @@ -27,9 +59,15 @@ public readonly struct Line(Vector2D From, Vector2D To) return new LineEquation(slope, yOffset); } + /// + /// Determines whether the specified lies on the . + /// public static bool Intersects(Line line, Vector2D point) => LineEquation.Resolve(GetLineEquation(line), point.X).ApproximatelyEquals(point.Y); + /// + /// Calculates the parameter 't' representing the point's position on the segment. + /// public static float GetT(Line line, Vector2D point) { float fromX = MathF.Abs(line.From.X); @@ -52,23 +90,63 @@ public readonly struct Line(Vector2D From, Vector2D To) return t; } - public static bool Exist(Line line, List vertices) + /// + /// Checks if the segment intersects with another segment. + /// + public static bool Intersects(Line left, Line right) { - for (int i = 0; i < vertices.Count - 1; i++) - { - Vector2D vertexCurrent = vertices[i]; - Vector2D vertexNext = vertices[i]; - if (line.From == vertexCurrent && line.To == vertexNext) return true; - if (line.From == vertexNext && line.To == vertexCurrent) return true; - } + int o1 = Vector2D.Orientation(left.From, left.To, right.From); + int o2 = Vector2D.Orientation(left.From, left.To, right.To); + int o3 = Vector2D.Orientation(right.From, right.To, left.From); + int o4 = Vector2D.Orientation(right.From, right.To, left.To); + + if (o1 != o2 && o3 != o4) + return true; + + if (o1 == 0 && OnSegment(left, right.From)) return true; + if (o2 == 0 && OnSegment(left, right.To)) return true; + if (o3 == 0 && OnSegment(right, left.From)) return true; + if (o4 == 0 && OnSegment(right, left.To)) return true; - Vector2D vertexFirst = vertices[0]; - Vector2D vertexLast = vertices[^1]; - if (line.From == vertexFirst && line.To == vertexLast) return true; - if (line.From == vertexLast && line.To == vertexFirst) return true; return false; } + /// + /// Checks if the point lies within the segment. + /// + public static bool OnSegment(Line line, Vector2D point) + { + if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) && + point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y)) + return true; + + return false; + } + + /// + /// Determines whether two segments intersect. + /// + public static bool Intersects(Line left, Line right, [NotNullWhen(returnValue: true)] out Vector2D? point) + { + point = null; + + bool result = Intersects(left, right); + + if (result) + point = IntersectionPoint(left, right); + + return result; + } + + /// + /// Finds the point of intersection between two segments. + /// + public static Vector2D IntersectionPoint(Line left, Line right) + => Vector2D.Lerp(left.From, left.To, IntersectionParameterT(left, right)); + + /// + /// Calculates the parameter 't' representing the intersection point's position on the segment. + /// public static float IntersectionParameterT(Line left, Line right) { float numerator = (left.From.X - right.From.X) * (right.From.Y - right.To.Y) - (left.From.Y - right.From.Y) * (right.From.X - right.To.X); @@ -81,12 +159,18 @@ public readonly struct Line(Vector2D From, Vector2D To) return numerator / denominator; } + /// + /// Linearly interpolates between the two endpoints of the segment using parameter 't'. + /// public static Vector2D Lerp(Line line, float t) - => new Vector2D( + => new( line.From.X + (line.To.X - line.From.X) * t, line.From.Y + (line.To.Y - line.From.Y) * t ); + /// + /// Calculates the closest point on the segment to the specified point. + /// public static Vector2D ClosestPointTo(Line line, Vector2D point) { // Convert edge points to vectors @@ -106,53 +190,20 @@ public readonly struct Line(Vector2D From, Vector2D To) return new Vector2D((float)closestX, (float)closestY); } - public static Vector2D IntersectionPoint(Line left, Line right) - => Vector2D.Lerp(left.From, left.To, IntersectionParameterT(left, right)); - - public static bool Intersects(Line left, Line right) - { - int o1 = Vector2D.Orientation(left.From, left.To, right.From); - int o2 = Vector2D.Orientation(left.From, left.To, right.To); - int o3 = Vector2D.Orientation(right.From, right.To, left.From); - int o4 = Vector2D.Orientation(right.From, right.To, left.To); - - if (o1 != o2 && o3 != o4) - return true; - - if (o1 == 0 && OnSegment(left, right.From)) return true; - if (o2 == 0 && OnSegment(left, right.To)) return true; - if (o3 == 0 && OnSegment(right, left.From)) return true; - if (o4 == 0 && OnSegment(right, left.To)) return true; - - return false; - } - - public static bool OnSegment(Line line, Vector2D point) - { - if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) && - point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y)) - return true; - - return false; - } - - public static bool Intersects(Line left, Line right, [NotNullWhen(returnValue: true)] out Vector2D? point) - { - point = null; - - bool result = Intersects(left, right); - - if (result) - point = IntersectionPoint(left, right); - - return result; - } - + /// + /// Checks if two segments are approximately equal. + /// public static bool ApproximatelyEquals(Line left, Line right) => left.From.ApproximatelyEquals(right.From) && left.To.ApproximatelyEquals(right.To); } +/// +/// Provides extension methods for the Line struct. +/// public static class LineExtensions { + /// + /// Checks if two s are approximately equal. + /// public static bool ApproximatelyEquals(this Line left, Line right) => Line.ApproximatelyEquals(left, right); } diff --git a/Engine.Physics2D/Primitives/LineEquation.cs b/Engine.Physics2D/Primitives/LineEquation.cs index 3a3e417..5640f47 100644 --- a/Engine.Physics2D/Primitives/LineEquation.cs +++ b/Engine.Physics2D/Primitives/LineEquation.cs @@ -2,20 +2,63 @@ using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; +/// +/// Represents a line equation in the form y = mx + b. +/// +/// The slope of the line. +/// The y-intercept of the line. +/// +/// Initializes a new instance of the struct with the specified slope and y-intercept. +/// [System.Diagnostics.DebuggerDisplay("y = {Slope}x + {OffsetY}")] -public readonly struct LineEquation(float Slope, float OffsetY) +public readonly struct LineEquation(float slope, float offsetY) { - public readonly float Slope { get; init; } = Slope; - public readonly float OffsetY { get; init; } = OffsetY; + /// + /// The slope of the line equation. + /// + public readonly float Slope = slope; + /// + /// The y-intercept of the line equation. + /// + public readonly float OffsetY = offsetY; + + /// + /// Resolves the y-coordinate for a given x-coordinate using the line equation. + /// + /// The line equation to resolve. + /// The x-coordinate for which to resolve the y-coordinate. + /// The y-coordinate resolved using the line equation. public static float Resolve(LineEquation lineEquation, float x) => lineEquation.Slope * x + lineEquation.OffsetY; // y = mx + b + /// + /// Checks if two line equations are approximately equal. + /// + /// The first line equation to compare. + /// The second line equation to compare. + /// True if the line equations are approximately equal; otherwise, false. public static bool ApproximatelyEquals(LineEquation left, LineEquation right) => left.Slope.ApproximatelyEquals(right.Slope) && left.OffsetY.ApproximatelyEquals(right.OffsetY); } +/// +/// Provides extension methods for the LineEquation struct. +/// public static class LineEquationExtensions { + /// + /// Resolves the y-coordinate for a given x-coordinate using the line equation. + /// + /// The line equation to resolve. + /// The x-coordinate for which to resolve the y-coordinate. + /// The y-coordinate resolved using the line equation. public static float Resolve(this LineEquation lineEquation, float x) => LineEquation.Resolve(lineEquation, x); + + /// + /// Checks if two line equations are approximately equal. + /// + /// The first line equation to compare. + /// The second line equation to compare. + /// True if the line equations are approximately equal; otherwise, false. public static bool ApproximatelyEquals(this LineEquation left, LineEquation right) => LineEquation.ApproximatelyEquals(left, right); } diff --git a/Engine.Physics2D/Primitives/Projection.cs b/Engine.Physics2D/Primitives/Projection.cs index 2f0af58..67b6b74 100644 --- a/Engine.Physics2D/Primitives/Projection.cs +++ b/Engine.Physics2D/Primitives/Projection.cs @@ -1,12 +1,41 @@ namespace Syntriax.Engine.Physics2D.Primitives; +/// +/// Represents a range of values along a single axis. +/// +/// The minimum value of the projection. +/// The maximum value of the projection. +/// +/// Initializes a new instance of the struct with the specified minimum and maximum values. +/// [System.Diagnostics.DebuggerDisplay("Min: {Min}, Max: {Max}")] -public readonly struct Projection(float Min, float Max) +public readonly struct Projection(float min, float max) { - public readonly float Min { get; init; } = Min; - public readonly float Max { get; init; } = Max; + /// + /// Gets the minimum value of the projection. + /// + public readonly float Min = min; + /// + /// Gets the maximum value of the projection. + /// + public readonly float Max = max; + + /// + /// Checks if two projections overlap. + /// + /// The first projection to check. + /// The second projection to check. + /// if the projections overlap; otherwise, . public static bool Overlaps(Projection left, Projection right) => Overlaps(left, right, out var _); + + /// + /// Checks if two projections overlap and calculates the depth of the overlap. + /// + /// The first projection to check. + /// The second projection to check. + /// The depth of the overlap, if any. + /// if the projections overlap; otherwise, . public static bool Overlaps(Projection left, Projection right, out float depth) { // TODO Try to improve this @@ -42,8 +71,26 @@ public readonly struct Projection(float Min, float Max) return false; } } + +/// +/// Provides extension methods for the struct. +/// public static class ProjectionExtensions { + /// + /// Checks if two projections overlap. + /// + /// The first projection to check. + /// The second projection to check. + /// if the projections overlap; otherwise, . public static bool Overlaps(this Projection left, Projection right) => Projection.Overlaps(left, right); + + /// + /// Checks if two projections overlap and calculates the depth of the overlap. + /// + /// The first projection to check. + /// The second projection to check. + /// The depth of the overlap, if any. + /// if the projections overlap; otherwise, . public static bool Overlaps(this Projection left, Projection right, out float depth) => Projection.Overlaps(left, right, out depth); } diff --git a/Engine.Physics2D/Primitives/Shape.cs b/Engine.Physics2D/Primitives/Shape.cs index d332ab0..0640196 100644 --- a/Engine.Physics2D/Primitives/Shape.cs +++ b/Engine.Physics2D/Primitives/Shape.cs @@ -6,22 +6,55 @@ using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Physics2D.Primitives; +/// +/// Represents a shape defined by a collection of vertices. +/// +/// The vertices of the shape. +/// +/// Initializes a new instance of the struct with the specified vertices. +/// [System.Diagnostics.DebuggerDisplay("Vertices Count: {Vertices.Count}")] -public readonly struct Shape(IList Vertices) : IEnumerable +public readonly struct Shape(List vertices) : IEnumerable { public static readonly Shape Triangle = CreateNgon(3, Vector2D.Up); public static readonly Shape Box = CreateNgon(4, Vector2D.One); public static readonly Shape Pentagon = CreateNgon(5, Vector2D.Up); public static readonly Shape Hexagon = CreateNgon(6, Vector2D.Right); - public readonly IList Vertices { get; init; } = Vertices; + private readonly List _verticesList = vertices; + /// + /// Gets the vertices of the shape. + /// + public IReadOnlyList Vertices => _verticesList; + /// + /// The vertex at the specified index. + /// + /// The zero-based index of the vertex to get or set. + /// The vertex at the specified index. public Vector2D this[System.Index index] => Vertices[index]; + /// + /// Returns a copy of the current shape. + /// + /// The shape to copy. + /// A copy of the input shape. public static Shape CreateCopy(Shape shape) => new(new List(shape.Vertices)); + /// + /// Creates a regular polygon (ngon) with the specified number of vertices. + /// + /// The number of vertices in the polygon. + /// A regular polygon with the specified number of vertices. public static Shape CreateNgon(int vertexCount) => CreateNgon(vertexCount, Vector2D.Up); + + /// + /// Creates a regular polygon (ngon) with the specified number of vertices and a rotation position. + /// + /// The number of vertices in the polygon. + /// The position to use for rotation. + /// A regular polygon with the specified number of vertices and rotation position. public static Shape CreateNgon(int vertexCount, Vector2D positionToRotate) { if (vertexCount < 3) @@ -37,6 +70,11 @@ public readonly struct Shape(IList Vertices) : IEnumerable return new(vertices); } + /// + /// Gets the super triangle that encloses the given shape. + /// + /// The shape to enclose. + /// The super triangle that encloses the given shape. public static Triangle GetSuperTriangle(Shape shape) { float minX = float.MaxValue, minY = float.MaxValue; @@ -63,6 +101,11 @@ public readonly struct Shape(IList Vertices) : IEnumerable return new Triangle(p1, p2, p3); } + /// + /// Gets the lines that form the edges of the shape. + /// + /// The shape to get lines from. + /// The list to populate with lines. public static void GetLines(Shape shape, IList lines) { lines.Clear(); @@ -71,6 +114,11 @@ public readonly struct Shape(IList Vertices) : IEnumerable lines.Add(new(shape.Vertices[^1], shape.Vertices[0])); } + /// + /// Gets a list of lines that form the edges of the shape. + /// + /// The shape to get lines from. + /// A list of lines that form the edges of the shape. public static List GetLines(Shape shape) { List lines = new(shape.Vertices.Count - 1); @@ -78,6 +126,12 @@ public readonly struct Shape(IList Vertices) : IEnumerable return lines; } + /// + /// Projects the shape onto a vector. + /// + /// The shape to project. + /// The vector to project onto. + /// The list to populate with projected values. public static void Project(Shape shape, Vector2D projectionVector, IList list) { list.Clear(); @@ -87,6 +141,12 @@ public readonly struct Shape(IList Vertices) : IEnumerable list.Add(projectionVector.Dot(shape[i])); } + /// + /// Projects the shape onto a vector. + /// + /// The shape to project. + /// The vector to project onto. + /// The projection of the shape onto the vector. public static Projection Project(Shape shape, Vector2D projectionVector) { float min = float.MaxValue; @@ -102,6 +162,12 @@ public readonly struct Shape(IList Vertices) : IEnumerable return new(min, max); } + /// + /// Transforms the shape using the specified transform. + /// + /// The shape to transform. + /// The transform to apply. + /// The transformed shape. public static Shape TransformShape(Shape shape, ITransform transform) { List vertices = new(shape.Vertices.Count); @@ -113,15 +179,27 @@ public readonly struct Shape(IList Vertices) : IEnumerable return new Shape(vertices); } + /// + /// Transforms the shape using the specified transform. + /// + /// The shape to transform. + /// The transform to apply. + /// The transformed shape. public static void TransformShape(Shape from, ITransform transform, ref Shape to) { - to.Vertices.Clear(); + to._verticesList.Clear(); - int count = from.Vertices.Count; + int count = from._verticesList.Count; for (int i = 0; i < count; i++) - to.Vertices.Add(transform.TransformVector2D(from[i])); + to._verticesList.Add(transform.TransformVector2D(from[i])); } + /// + /// Determines whether two shapes are approximately equal. + /// + /// The first shape to compare. + /// The second shape to compare. + /// true if the shapes are approximately equal; otherwise, false. public static bool ApproximatelyEquals(Shape left, Shape right) { if (left.Vertices.Count != right.Vertices.Count) @@ -134,22 +212,83 @@ public readonly struct Shape(IList Vertices) : IEnumerable return true; } + /// public IEnumerator GetEnumerator() => Vertices.GetEnumerator(); + + /// IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator(); } +/// +/// Provides extension methods for the struct. +/// public static class ShapeExtensions { + /// + /// Creates a copy of the shape. + /// + /// The shape to copy. + /// A copy of the input shape. public static Shape CreateCopy(this Shape shape) => Shape.CreateCopy(shape); + + /// + /// Gets the super triangle that encloses the shape. + /// + /// The shape to enclose. + /// The super triangle that encloses the shape. public static Triangle ToSuperTriangle(this Shape shape) => Shape.GetSuperTriangle(shape); + + /// + /// Gets the lines that form the edges of the shape. + /// + /// The shape to get lines from. + /// The list to populate with lines. public static void ToLines(this Shape shape, IList lines) => Shape.GetLines(shape, lines); + + /// + /// Gets a list of lines that form the edges of the shape. + /// + /// The shape to get lines from. + /// A list of lines that form the edges of the shape. public static List ToLines(this Shape shape) => Shape.GetLines(shape); + /// + /// Projects the shape onto a vector. + /// + /// The shape to project. + /// The vector to project onto. + /// The list to populate with projected values. public static void ToProjection(this Shape shape, Vector2D projectionVector, IList list) => Shape.Project(shape, projectionVector, list); + + /// + /// Projects the shape onto a vector. + /// + /// The shape to project. + /// The vector to project onto. + /// The projection of the shape onto the vector. public static Projection ToProjection(this Shape shape, Vector2D projectionVector) => Shape.Project(shape, projectionVector); + /// + /// Transforms the shape using the specified transform. + /// + /// The transform to apply. + /// The shape to transform. + /// The transformed shape. public static Shape TransformShape(this ITransform transform, Shape shape) => Shape.TransformShape(shape, transform); + + /// + /// Transforms the shape using the specified transform. + /// + /// The transform to apply. + /// The shape to transform. + /// The transformed shape. public static void TransformShape(this ITransform transform, Shape from, ref Shape to) => Shape.TransformShape(from, transform, ref to); + /// + /// Determines whether two shapes are approximately equal. + /// + /// The first shape to compare. + /// The second shape to compare. + /// true if the shapes are approximately equal; otherwise, false. public static bool ApproximatelyEquals(this Shape left, Shape right) => Shape.ApproximatelyEquals(left, right); }