2024-01-24 12:50:26 +03:00
|
|
|
using System.Collections;
|
2024-01-23 18:39:25 +03:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
using Syntriax.Engine.Core;
|
2024-01-24 19:21:53 +03:00
|
|
|
using Syntriax.Engine.Core.Abstract;
|
2024-01-23 18:39:25 +03:00
|
|
|
|
|
|
|
namespace Syntriax.Engine.Physics2D.Primitives;
|
|
|
|
|
2024-01-27 00:51:34 +03:00
|
|
|
[System.Diagnostics.DebuggerDisplay("Vertices Count: {Vertices.Count()}")]
|
2024-01-26 23:40:02 +03:00
|
|
|
public readonly struct Shape(IList<Vector2D> Vertices) : IEnumerable<Vector2D>
|
2024-01-23 18:39:25 +03:00
|
|
|
{
|
2024-01-26 19:05:17 +03:00
|
|
|
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);
|
|
|
|
|
2024-01-26 23:40:02 +03:00
|
|
|
public readonly IList<Vector2D> Vertices { get; init; } = Vertices;
|
|
|
|
|
2024-01-26 19:05:17 +03:00
|
|
|
|
2024-01-26 12:40:12 +03:00
|
|
|
public Vector2D this[System.Index index] => Vertices[index];
|
2024-01-24 12:02:04 +03:00
|
|
|
|
2024-01-26 12:34:01 +03:00
|
|
|
public static Shape CreateCopy(Shape shape) => new(new List<Vector2D>(shape.Vertices));
|
|
|
|
|
2024-01-26 19:01:53 +03:00
|
|
|
public static Shape CreateNgon(int vertexCount) => CreateNgon(vertexCount, Vector2D.Up);
|
|
|
|
public static Shape CreateNgon(int vertexCount, Vector2D positionToRotate)
|
|
|
|
{
|
|
|
|
if (vertexCount < 3)
|
|
|
|
throw new System.ArgumentException($"{nameof(vertexCount)} must have a value of more than 2.");
|
|
|
|
|
|
|
|
List<Vector2D> vertices = new(vertexCount);
|
|
|
|
|
|
|
|
float radiansPerVertex = 360f / vertexCount * Math.DegreeToRadian;
|
|
|
|
|
|
|
|
for (int i = 0; i < vertexCount; i++)
|
|
|
|
vertices.Add(positionToRotate.Rotate(i * radiansPerVertex));
|
|
|
|
|
|
|
|
return new(vertices);
|
|
|
|
}
|
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
public static Triangle GetSuperTriangle(Shape shape)
|
2024-01-23 18:39:25 +03:00
|
|
|
{
|
2024-01-23 19:17:08 +03:00
|
|
|
float minX = float.MaxValue, minY = float.MaxValue;
|
|
|
|
float maxX = float.MinValue, maxY = float.MinValue;
|
2024-01-23 18:39:25 +03:00
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
foreach (Vector2D point in shape.Vertices)
|
|
|
|
{
|
2024-01-26 12:40:12 +03:00
|
|
|
minX = Math.Min(minX, point.X);
|
|
|
|
minY = Math.Min(minY, point.Y);
|
|
|
|
maxX = Math.Max(maxX, point.X);
|
|
|
|
maxY = Math.Max(maxY, point.Y);
|
2024-01-23 19:17:08 +03:00
|
|
|
}
|
2024-01-23 18:39:25 +03:00
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
float dx = maxX - minX;
|
|
|
|
float dy = maxY - minY;
|
2024-01-26 12:40:12 +03:00
|
|
|
float deltaMax = Math.Max(dx, dy);
|
2024-01-23 19:17:08 +03:00
|
|
|
float midX = (minX + maxX) / 2;
|
|
|
|
float midY = (minY + maxY) / 2;
|
2024-01-23 18:39:25 +03:00
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
Vector2D p1 = new((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
|
|
|
|
Vector2D p2 = new((float)midX, (float)midY + 20 * (float)deltaMax);
|
|
|
|
Vector2D p3 = new((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
|
2024-01-23 18:39:25 +03:00
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
return new Triangle(p1, p2, p3);
|
2024-01-23 18:39:25 +03:00
|
|
|
}
|
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
public static void GetLines(Shape shape, IList<Line> lines)
|
2024-01-23 18:39:25 +03:00
|
|
|
{
|
2024-01-23 19:17:08 +03:00
|
|
|
lines.Clear();
|
|
|
|
for (int i = 0; i < shape.Vertices.Count - 1; i++)
|
|
|
|
lines.Add(new(shape.Vertices[i], shape.Vertices[i + 1]));
|
|
|
|
lines.Add(new(shape.Vertices[^1], shape.Vertices[0]));
|
2024-01-23 18:39:25 +03:00
|
|
|
}
|
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
public static List<Line> GetLines(Shape shape)
|
2024-01-23 18:39:25 +03:00
|
|
|
{
|
2024-01-23 19:17:08 +03:00
|
|
|
List<Line> lines = new(shape.Vertices.Count - 1);
|
|
|
|
GetLines(shape, lines);
|
|
|
|
return lines;
|
2024-01-23 18:39:25 +03:00
|
|
|
}
|
|
|
|
|
2024-01-26 12:41:51 +03:00
|
|
|
public static void Project(Shape shape, Vector2D projectionVector, IList<float> list)
|
|
|
|
{
|
|
|
|
list.Clear();
|
|
|
|
|
|
|
|
int count = shape.Vertices.Count;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
list.Add(projectionVector.Dot(shape[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Projection Project(Shape shape, Vector2D projectionVector)
|
|
|
|
{
|
|
|
|
float min = float.MaxValue;
|
|
|
|
float max = float.MinValue;
|
|
|
|
|
2024-01-26 23:40:02 +03:00
|
|
|
for (int i = 0; i < shape.Vertices.Count; i++)
|
2024-01-26 12:41:51 +03:00
|
|
|
{
|
2024-01-26 23:40:02 +03:00
|
|
|
float projectedLength = projectionVector.Dot(shape.Vertices[i]);
|
2024-01-26 12:41:51 +03:00
|
|
|
min = Math.Min(projectedLength, min);
|
|
|
|
max = Math.Max(projectedLength, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new(min, max);
|
|
|
|
}
|
|
|
|
|
2024-01-24 19:21:53 +03:00
|
|
|
public static Shape TransformShape(Shape shape, ITransform transform)
|
|
|
|
{
|
|
|
|
List<Vector2D> vertices = new(shape.Vertices.Count);
|
|
|
|
|
|
|
|
int count = shape.Vertices.Count;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
vertices.Add(transform.TransformVector2D(shape[i]));
|
|
|
|
|
|
|
|
return new Shape(vertices);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void TransformShape(Shape from, ITransform transform, ref Shape to)
|
|
|
|
{
|
|
|
|
to.Vertices.Clear();
|
|
|
|
|
|
|
|
int count = from.Vertices.Count;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
to.Vertices.Add(transform.TransformVector2D(from[i]));
|
|
|
|
}
|
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
public static bool ApproximatelyEquals(Shape left, Shape right)
|
2024-01-23 18:39:25 +03:00
|
|
|
{
|
2024-01-23 19:17:08 +03:00
|
|
|
if (left.Vertices.Count != right.Vertices.Count)
|
2024-01-23 18:39:25 +03:00
|
|
|
return false;
|
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
for (int i = 0; i < left.Vertices.Count; i++)
|
|
|
|
if (!left.Vertices[i].ApproximatelyEquals(right.Vertices[i]))
|
2024-01-23 18:39:25 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2024-01-24 12:50:26 +03:00
|
|
|
|
|
|
|
public IEnumerator<Vector2D> GetEnumerator() => Vertices.GetEnumerator();
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator();
|
2024-01-23 18:39:25 +03:00
|
|
|
}
|
2024-01-23 19:17:08 +03:00
|
|
|
|
|
|
|
public static class ShapeExtensions
|
|
|
|
{
|
2024-01-26 12:34:01 +03:00
|
|
|
public static Shape CreateCopy(Shape shape) => Shape.CreateCopy(shape);
|
2024-01-23 19:17:08 +03:00
|
|
|
public static Triangle ToSuperTriangle(this Shape shape) => Shape.GetSuperTriangle(shape);
|
|
|
|
public static void ToLines(this Shape shape, IList<Line> lines) => Shape.GetLines(shape, lines);
|
|
|
|
public static List<Line> ToLines(this Shape shape) => Shape.GetLines(shape);
|
|
|
|
|
2024-01-26 12:41:51 +03:00
|
|
|
public static void ToProjection(this Shape shape, Vector2D projectionVector, IList<float> list) => Shape.Project(shape, projectionVector, list);
|
|
|
|
public static Projection ToProjection(this Shape shape, Vector2D projectionVector) => Shape.Project(shape, projectionVector);
|
|
|
|
|
2024-01-24 19:21:53 +03:00
|
|
|
public static Shape TransformShape(this ITransform transform, Shape shape) => Shape.TransformShape(shape, transform);
|
|
|
|
public static void TransformShape(this ITransform transform, Shape from, ref Shape to) => Shape.TransformShape(from, transform, ref to);
|
|
|
|
|
2024-01-23 19:17:08 +03:00
|
|
|
public static bool ApproximatelyEquals(this Shape left, Shape right) => Shape.ApproximatelyEquals(left, right);
|
|
|
|
}
|