diff --git a/Engine.Core/Primitives/Circle.cs b/Engine.Core/Primitives/Circle.cs index 4c1c20e..633ca46 100644 --- a/Engine.Core/Primitives/Circle.cs +++ b/Engine.Core/Primitives/Circle.cs @@ -34,6 +34,16 @@ public readonly struct Circle(Vector2D center, float radius) : IEquatable public readonly float Diameter => 2f * Radius; + /// + /// Gets the area of the . + /// + public readonly float Area => Math.Pi * RadiusSquared; + + /// + /// Gets the geometric interia of the . + /// + public readonly float GeometricInertia => .5f * RadiusSquared; + /// /// A predefined unit with a center at the origin and a radius of 1. /// diff --git a/Engine.Core/Primitives/Shape2D.cs b/Engine.Core/Primitives/Shape2D.cs index 5871c7a..8f8b03a 100644 --- a/Engine.Core/Primitives/Shape2D.cs +++ b/Engine.Core/Primitives/Shape2D.cs @@ -22,6 +22,31 @@ public class Shape2D(List vertices) : IEnumerable private readonly List _vertices = vertices; + /// + /// Gets the area of the . + /// + public float Area + { + get + { + float area = 0f; + + for (int i = 0; i < _vertices.Count; i++) + { + Vector2D a = _vertices[i]; + Vector2D b = _vertices[(i + 1) % _vertices.Count]; + area += a.Cross(b); + } + + return area.Abs() * .5f; + } + } + + /// + /// Gets the geometric interia of the . + /// + public float GeometricInertia => GetGeometricInertia(this, Vector2D.Zero); + /// /// Gets the vertices of the . /// @@ -112,6 +137,40 @@ public class Shape2D(List vertices) : IEnumerable return new Triangle(p1, p2, p3); } + /// + /// Gets the geometric interia of the . + /// + /// The shape to get the geometrical interia of. + /// The point in space to calculate the geometrical interia from. + /// The geometrical interia of the . + public static float GetGeometricInertia(Shape2D shape, Vector2D centerOfMass) + { + float geometricInertia = 0f; + + for (int i = 0; i < shape._vertices.Count; i++) + { + Vector2D p1 = centerOfMass.FromTo(shape._vertices[i]); + Vector2D p2 = centerOfMass.FromTo(shape._vertices[(i + 1) % shape._vertices.Count]); + + float cross = p1.Cross(p2); + float dot = p1.Dot(p1) + p1.Dot(p2) + p2.Dot(p2); + + geometricInertia += cross * dot; + } + + return geometricInertia.Abs() / 12f; + } + + /// + /// Gets the interia of the . + /// + /// The shape to get the interia of. + /// The point in space to calculate the geometrical interia from. + /// Mass of the shape. + /// The interia of the . + public static float GetInertia(Shape2D shape, Vector2D centerOfMass, float mass) + => GetGeometricInertia(shape, centerOfMass) * mass; + /// /// Triangulates the given convex . /// @@ -297,6 +356,12 @@ public static class Shape2DExtensions /// public static Triangle ToSuperTriangle(this Shape2D shape) => Shape2D.GetSuperTriangle(shape); + /// + public static float GetGeometricInertia(this Shape2D shape, Vector2D centerOfMass) => Shape2D.GetGeometricInertia(shape, centerOfMass); + + /// + public static float GetInertia(this Shape2D shape, Vector2D centerOfMass, float mass) => Shape2D.GetInertia(shape, centerOfMass, mass); + /// public static void ToTrianglesConvex(this Shape2D shape, IList triangles) => Shape2D.TriangulateConvex(shape, triangles); diff --git a/Engine.Physics2D/Abstract/ICollider2D.cs b/Engine.Physics2D/Abstract/ICollider2D.cs index 38f0c75..606ee8f 100644 --- a/Engine.Physics2D/Abstract/ICollider2D.cs +++ b/Engine.Physics2D/Abstract/ICollider2D.cs @@ -30,6 +30,16 @@ public interface ICollider2D : IBehaviour /// IRigidBody2D? RigidBody2D { get; } + /// + /// The area of the . + /// + float Area { get; } + + /// + /// The geometric inertia of the . + /// + float GeometricInertia { get; } + /// /// The value indicating whether the is a trigger. /// diff --git a/Engine.Physics2D/Collider2DBase.cs b/Engine.Physics2D/Collider2DBase.cs index a868c82..329592d 100644 --- a/Engine.Physics2D/Collider2DBase.cs +++ b/Engine.Physics2D/Collider2DBase.cs @@ -20,6 +20,9 @@ public abstract class Collider2DBase : Behaviour2D, ICollider2D public IRigidBody2D? RigidBody2D { get; protected set; } = null; public bool IsTrigger { get; set; } = false; + public abstract float Area { get; } + public abstract float GeometricInertia { get; } + public void Recalculate() { if (!NeedsRecalculation) diff --git a/Engine.Physics2D/Collider2DCircle.cs b/Engine.Physics2D/Collider2DCircle.cs index d1a7500..8bbc56e 100644 --- a/Engine.Physics2D/Collider2DCircle.cs +++ b/Engine.Physics2D/Collider2DCircle.cs @@ -15,7 +15,15 @@ public class Collider2DCircle : Collider2DBase, ICircleCollider2D } } = Circle.UnitCircle; - public override void CalculateCollider() => CircleWorld = Transform.Transform(CircleLocal); + private float area = 0f; public override float Area => area; + private float geometricInertia = 0f; public override float GeometricInertia => geometricInertia; + + public override void CalculateCollider() + { + CircleWorld = Transform.Transform(CircleLocal); + area = CircleWorld.Area; + geometricInertia = CircleWorld.GeometricInertia; + } public Collider2DCircle() { } public Collider2DCircle(Circle circle) => CircleLocal = circle; diff --git a/Engine.Physics2D/Collider2DShape.cs b/Engine.Physics2D/Collider2DShape.cs index e7eeef9..5976b17 100644 --- a/Engine.Physics2D/Collider2DShape.cs +++ b/Engine.Physics2D/Collider2DShape.cs @@ -15,7 +15,16 @@ public class Collider2DShape : Collider2DBase, IShapeCollider2D } } = Shape2D.Square; - public override void CalculateCollider() => ShapeLocal.Transform(Transform, ShapeWorld); + private float area = 0f; public override float Area => area; + private float geometricInertia = 0f; public override float GeometricInertia => geometricInertia; + + public override void CalculateCollider() + { + ShapeLocal.Transform(Transform, ShapeWorld); + + area = ShapeWorld.Area; + geometricInertia = ShapeWorld.GetGeometricInertia(Transform.Position); + } public Collider2DShape() { } public Collider2DShape(Shape2D shape) { ShapeLocal = shape; }