using System.Collections; using System.Collections.Generic; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Physics2D.Primitives; public record Shape(IList 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 Vector2D this[System.Index index] => Vertices[index]; public static Shape CreateCopy(Shape shape) => new(new List(shape.Vertices)); 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 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); } public static Triangle GetSuperTriangle(Shape shape) { float minX = float.MaxValue, minY = float.MaxValue; float maxX = float.MinValue, maxY = float.MinValue; foreach (Vector2D point in shape.Vertices) { minX = Math.Min(minX, point.X); minY = Math.Min(minY, point.Y); maxX = Math.Max(maxX, point.X); maxY = Math.Max(maxY, point.Y); } float dx = maxX - minX; float dy = maxY - minY; float deltaMax = Math.Max(dx, dy); float midX = (minX + maxX) / 2; float midY = (minY + maxY) / 2; 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); return new Triangle(p1, p2, p3); } public static void GetLines(Shape shape, IList lines) { 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])); } public static List GetLines(Shape shape) { List lines = new(shape.Vertices.Count - 1); GetLines(shape, lines); return lines; } public static void Project(Shape shape, Vector2D projectionVector, IList 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; foreach (var vertex in shape) { float projectedLength = projectionVector.Dot(vertex); min = Math.Min(projectedLength, min); max = Math.Max(projectedLength, max); } return new(min, max); } public static Shape TransformShape(Shape shape, ITransform transform) { List 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])); } public static bool ApproximatelyEquals(Shape left, Shape right) { if (left.Vertices.Count != right.Vertices.Count) return false; for (int i = 0; i < left.Vertices.Count; i++) if (!left.Vertices[i].ApproximatelyEquals(right.Vertices[i])) return false; return true; } public IEnumerator GetEnumerator() => Vertices.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator(); } public static class ShapeExtensions { public static Shape CreateCopy(Shape shape) => Shape.CreateCopy(shape); public static Triangle ToSuperTriangle(this Shape shape) => Shape.GetSuperTriangle(shape); public static void ToLines(this Shape shape, IList lines) => Shape.GetLines(shape, lines); public static List ToLines(this Shape shape) => Shape.GetLines(shape); public static void ToProjection(this Shape shape, Vector2D projectionVector, IList list) => Shape.Project(shape, projectionVector, list); public static Projection ToProjection(this Shape shape, Vector2D projectionVector) => Shape.Project(shape, projectionVector); 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); public static bool ApproximatelyEquals(this Shape left, Shape right) => Shape.ApproximatelyEquals(left, right); }