feat(physics): added area & inertia calculations for the shape and circles

This commit is contained in:
2026-04-04 18:49:27 +03:00
parent 6db427f39b
commit af2eed2200
6 changed files with 107 additions and 2 deletions

View File

@@ -34,6 +34,16 @@ public readonly struct Circle(Vector2D center, float radius) : IEquatable<Circle
/// </summary> /// </summary>
public readonly float Diameter => 2f * Radius; public readonly float Diameter => 2f * Radius;
/// <summary>
/// Gets the area of the <see cref="Circle"/>.
/// </summary>
public readonly float Area => Math.Pi * RadiusSquared;
/// <summary>
/// Gets the geometric interia of the <see cref="Circle"/>.
/// </summary>
public readonly float GeometricInertia => .5f * RadiusSquared;
/// <summary> /// <summary>
/// A predefined unit <see cref="Circle"/> with a center at the origin and a radius of 1. /// A predefined unit <see cref="Circle"/> with a center at the origin and a radius of 1.
/// </summary> /// </summary>

View File

@@ -22,6 +22,31 @@ public class Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
private readonly List<Vector2D> _vertices = vertices; private readonly List<Vector2D> _vertices = vertices;
/// <summary>
/// Gets the area of the <see cref="Shape2D"/>.
/// </summary>
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;
}
}
/// <summary>
/// Gets the geometric interia of the <see cref="Shape2D"/>.
/// </summary>
public float GeometricInertia => GetGeometricInertia(this, Vector2D.Zero);
/// <summary> /// <summary>
/// Gets the vertices of the <see cref="Shape2D"/>. /// Gets the vertices of the <see cref="Shape2D"/>.
/// </summary> /// </summary>
@@ -112,6 +137,40 @@ public class Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
return new Triangle(p1, p2, p3); return new Triangle(p1, p2, p3);
} }
/// <summary>
/// Gets the geometric interia of the <see cref="Shape2D"/>.
/// </summary>
/// <param name="shape">The shape to get the geometrical interia of.</param>
/// <param name="centerOfMass">The point in space to calculate the geometrical interia from.</param>
/// <returns>The geometrical interia of the <see cref="Shape2D"/>.</returns>
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;
}
/// <summary>
/// Gets the interia of the <see cref="Shape2D"/>.
/// </summary>
/// <param name="shape">The shape to get the interia of.</param>
/// <param name="centerOfMass">The point in space to calculate the geometrical interia from.</param>
/// <param name="mass">Mass of the shape.</param>
/// <returns>The interia of the <see cref="Shape2D"/>.</returns>
public static float GetInertia(Shape2D shape, Vector2D centerOfMass, float mass)
=> GetGeometricInertia(shape, centerOfMass) * mass;
/// <summary> /// <summary>
/// Triangulates the given convex <see cref="Shape2D"/>. /// Triangulates the given convex <see cref="Shape2D"/>.
/// </summary> /// </summary>
@@ -297,6 +356,12 @@ public static class Shape2DExtensions
/// <inheritdoc cref="Shape2D.GetSuperTriangle(Shape2D)" /> /// <inheritdoc cref="Shape2D.GetSuperTriangle(Shape2D)" />
public static Triangle ToSuperTriangle(this Shape2D shape) => Shape2D.GetSuperTriangle(shape); public static Triangle ToSuperTriangle(this Shape2D shape) => Shape2D.GetSuperTriangle(shape);
/// <inheritdoc cref="Shape2D.GetGeometricInertia(Shape2D, Vector2D)" />
public static float GetGeometricInertia(this Shape2D shape, Vector2D centerOfMass) => Shape2D.GetGeometricInertia(shape, centerOfMass);
/// <inheritdoc cref="Shape2D.GetInertia(Shape2D, Vector2D, float)" />
public static float GetInertia(this Shape2D shape, Vector2D centerOfMass, float mass) => Shape2D.GetInertia(shape, centerOfMass, mass);
/// <inheritdoc cref="Shape2D.TriangulateConvex(Shape2D, IList{Triangle})" /> /// <inheritdoc cref="Shape2D.TriangulateConvex(Shape2D, IList{Triangle})" />
public static void ToTrianglesConvex(this Shape2D shape, IList<Triangle> triangles) => Shape2D.TriangulateConvex(shape, triangles); public static void ToTrianglesConvex(this Shape2D shape, IList<Triangle> triangles) => Shape2D.TriangulateConvex(shape, triangles);

View File

@@ -30,6 +30,16 @@ public interface ICollider2D : IBehaviour
/// </summary> /// </summary>
IRigidBody2D? RigidBody2D { get; } IRigidBody2D? RigidBody2D { get; }
/// <summary>
/// The area of the <see cref="ICollider2D"/>.
/// </summary>
float Area { get; }
/// <summary>
/// The geometric inertia of the <see cref="ICollider2D"/>.
/// </summary>
float GeometricInertia { get; }
/// <summary> /// <summary>
/// The value indicating whether the <see cref="ICollider2D"/> is a trigger. /// The value indicating whether the <see cref="ICollider2D"/> is a trigger.
/// </summary> /// </summary>

View File

@@ -20,6 +20,9 @@ public abstract class Collider2DBase : Behaviour2D, ICollider2D
public IRigidBody2D? RigidBody2D { get; protected set; } = null; public IRigidBody2D? RigidBody2D { get; protected set; } = null;
public bool IsTrigger { get; set; } = false; public bool IsTrigger { get; set; } = false;
public abstract float Area { get; }
public abstract float GeometricInertia { get; }
public void Recalculate() public void Recalculate()
{ {
if (!NeedsRecalculation) if (!NeedsRecalculation)

View File

@@ -15,7 +15,15 @@ public class Collider2DCircle : Collider2DBase, ICircleCollider2D
} }
} = Circle.UnitCircle; } = 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() { }
public Collider2DCircle(Circle circle) => CircleLocal = circle; public Collider2DCircle(Circle circle) => CircleLocal = circle;

View File

@@ -15,7 +15,16 @@ public class Collider2DShape : Collider2DBase, IShapeCollider2D
} }
} = Shape2D.Square; } = 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() { }
public Collider2DShape(Shape2D shape) { ShapeLocal = shape; } public Collider2DShape(Shape2D shape) { ShapeLocal = shape; }