Compare commits
	
		
			9 Commits
		
	
	
		
			a9485475c7
			...
			5ed7ccdded
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5ed7ccdded | |||
| 0d29ab066f | |||
| bd03d036aa | |||
| 3b299c947c | |||
| 6a5d10980a | |||
| dcda78b010 | |||
| 5170dd0aea | |||
| 5c185a664c | |||
| 8ccebaa8fb | 
@@ -1,6 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public record CollisionInformation
 | 
			
		||||
(
 | 
			
		||||
    Vector2 Normal,
 | 
			
		||||
    Vector2 ContactPosition
 | 
			
		||||
    Vector2D Normal,
 | 
			
		||||
    Vector2D ContactPosition
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								Engine.Physics2D/Engine.Physics2D.sln
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Engine.Physics2D/Engine.Physics2D.sln
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
 | 
			
		||||
Microsoft Visual Studio Solution File, Format Version 12.00
 | 
			
		||||
# Visual Studio Version 17
 | 
			
		||||
VisualStudioVersion = 17.5.002.0
 | 
			
		||||
MinimumVisualStudioVersion = 10.0.40219.1
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Engine.Physics2D", "Engine.Physics2D.csproj", "{88874ADD-23BD-4781-A47C-71B5D4AA9C25}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "..\Engine.Core\Engine.Core.csproj", "{A9D6D7DC-4B5A-4D1E-878D-08BA3A871D3A}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
		Debug|Any CPU = Debug|Any CPU
 | 
			
		||||
		Release|Any CPU = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
			
		||||
		{88874ADD-23BD-4781-A47C-71B5D4AA9C25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{88874ADD-23BD-4781-A47C-71B5D4AA9C25}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{88874ADD-23BD-4781-A47C-71B5D4AA9C25}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{88874ADD-23BD-4781-A47C-71B5D4AA9C25}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{A9D6D7DC-4B5A-4D1E-878D-08BA3A871D3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{A9D6D7DC-4B5A-4D1E-878D-08BA3A871D3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{A9D6D7DC-4B5A-4D1E-878D-08BA3A871D3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{A9D6D7DC-4B5A-4D1E-878D-08BA3A871D3A}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ExtensibilityGlobals) = postSolution
 | 
			
		||||
		SolutionGuid = {9C16F1F0-F5F8-4ED9-A3B4-7A0BF8003AA1}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
							
								
								
									
										77
									
								
								Engine.Physics2D/Physics2D.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Engine.Physics2D/Physics2D.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public static partial class Physics2D
 | 
			
		||||
{
 | 
			
		||||
    public const float RadianToDegree = 57.29577866666166f;
 | 
			
		||||
    public const float DegreeToRadian = 0.01745329277777778f;
 | 
			
		||||
 | 
			
		||||
    public static bool Overlaps(this Circle left, Circle right)
 | 
			
		||||
    {
 | 
			
		||||
        float distanceSquared = left.Position.FromTo(right.Position).LengthSquared();
 | 
			
		||||
        float radiusSumSquared = left.RadiusSquared + right.RadiusSquared;
 | 
			
		||||
 | 
			
		||||
        return distanceSquared < radiusSumSquared;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static bool Overlaps(this Circle left, Circle right, out Vector2D normal, out float depth)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D distanceVector = left.Position.FromTo(right.Position);
 | 
			
		||||
        float distanceSquared = distanceVector.LengthSquared();
 | 
			
		||||
        float radiusSumSquared = left.RadiusSquared + right.RadiusSquared;
 | 
			
		||||
        bool isOverlapping = distanceSquared < radiusSumSquared;
 | 
			
		||||
 | 
			
		||||
        depth = 0f;
 | 
			
		||||
        normal = distanceVector.Normalized;
 | 
			
		||||
 | 
			
		||||
        if (isOverlapping)
 | 
			
		||||
            depth = MathF.Sqrt(radiusSumSquared - distanceSquared);
 | 
			
		||||
 | 
			
		||||
        return isOverlapping;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static bool Overlaps(this Circle circle, Vector2D point) => circle.Position.FromTo(point).LengthSquared() <= circle.RadiusSquared;
 | 
			
		||||
    public static bool Overlaps(this Circle circle, Vector2D point, out Vector2D normal, out float depth)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D distanceVector = circle.Position.FromTo(point);
 | 
			
		||||
        float distanceSquared = distanceVector.LengthSquared();
 | 
			
		||||
        float radiusSquared = circle.RadiusSquared;
 | 
			
		||||
        bool isOverlapping = distanceSquared < radiusSquared;
 | 
			
		||||
 | 
			
		||||
        depth = 0f;
 | 
			
		||||
        normal = distanceVector.Normalized;
 | 
			
		||||
 | 
			
		||||
        if (isOverlapping)
 | 
			
		||||
            depth = MathF.Sqrt(radiusSquared - distanceSquared);
 | 
			
		||||
 | 
			
		||||
        return isOverlapping;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static bool Overlaps(this AABB aabb, Vector2D point)
 | 
			
		||||
        => point.X >= aabb.LowerBoundary.X && point.X <= aabb.UpperBoundary.X &&
 | 
			
		||||
            point.Y >= aabb.LowerBoundary.Y && point.Y <= aabb.UpperBoundary.Y;
 | 
			
		||||
 | 
			
		||||
    public static bool Overlaps(this AABB left, AABB right)
 | 
			
		||||
        => left.LowerBoundary.X <= right.UpperBoundary.X && left.UpperBoundary.X >= right.LowerBoundary.X &&
 | 
			
		||||
            left.LowerBoundary.Y <= right.UpperBoundary.Y && left.UpperBoundary.Y >= right.LowerBoundary.Y;
 | 
			
		||||
 | 
			
		||||
    public static bool Overlaps(Triangle triangle, Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        float originalTriangleArea = triangle.Area;
 | 
			
		||||
 | 
			
		||||
        float pointTriangleArea1 = new Triangle(point, triangle.B, triangle.C).Area;
 | 
			
		||||
        float pointTriangleArea2 = new Triangle(triangle.A, point, triangle.C).Area;
 | 
			
		||||
        float pointTriangleArea3 = new Triangle(triangle.A, triangle.B, point).Area;
 | 
			
		||||
 | 
			
		||||
        float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3;
 | 
			
		||||
 | 
			
		||||
        return originalTriangleArea.ApproximatelyEquals(pointTriangleAreasSum, float.Epsilon * 3f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static bool LaysOn(this Vector2D point, Line line) => Line.Intersects(line, point);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
@@ -9,52 +8,6 @@ namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public static class PhysicsMath
 | 
			
		||||
{
 | 
			
		||||
    public static Vector2D Scale(this Vector2D original, Vector2D scale)
 | 
			
		||||
        => new Vector2D(original.X * scale.X, original.Y * scale.Y);
 | 
			
		||||
 | 
			
		||||
    public static Triangle ToSuperTriangle(this IList<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        float minX = float.MaxValue, minY = float.MaxValue;
 | 
			
		||||
        float maxX = float.MinValue, maxY = float.MinValue;
 | 
			
		||||
 | 
			
		||||
        foreach (Vector2D point in vertices)
 | 
			
		||||
        {
 | 
			
		||||
            minX = MathF.Min(minX, point.X);
 | 
			
		||||
            minY = MathF.Min(minY, point.Y);
 | 
			
		||||
            maxX = MathF.Max(maxX, point.X);
 | 
			
		||||
            maxY = MathF.Max(maxY, point.Y);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        float dx = maxX - minX;
 | 
			
		||||
        float dy = maxY - minY;
 | 
			
		||||
        float deltaMax = MathF.Max(dx, dy);
 | 
			
		||||
        float midX = (minX + maxX) / 2;
 | 
			
		||||
        float midY = (minY + maxY) / 2;
 | 
			
		||||
 | 
			
		||||
        Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
        Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax);
 | 
			
		||||
        Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
 | 
			
		||||
        return new Triangle(p1, p2, p3);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IList<Line> ToLines(this IList<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        List<Line> lines = new List<Line>(vertices.Count - 1);
 | 
			
		||||
        ToLines(vertices, lines);
 | 
			
		||||
        return lines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void ToLines(this IList<Vector2D> vertices, IList<Line> lines)
 | 
			
		||||
    {
 | 
			
		||||
        lines.Clear();
 | 
			
		||||
        for (int i = 0; i < vertices.Count - 1; i++)
 | 
			
		||||
            lines.Add(new(vertices[i], vertices[i + 1]));
 | 
			
		||||
        lines.Add(new(vertices[^1], vertices[0]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static bool LaysOn(this Vector2D point, Line line)
 | 
			
		||||
        => line.Resolve(point.X).ApproximatelyEquals(point);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Given three collinear points p, q, r, the function checks if 
 | 
			
		||||
@@ -92,10 +45,6 @@ public static class PhysicsMath
 | 
			
		||||
 | 
			
		||||
    public static bool ApproximatelyEquals(this float a, float b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2 a, Vector2 b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2 a, Vector2 b, float epsilon)
 | 
			
		||||
        => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2D a, Vector2D b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2D a, Vector2D b, float epsilon)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,11 @@ namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary)
 | 
			
		||||
{
 | 
			
		||||
    public bool Overlaps(Vector2D point)
 | 
			
		||||
        => point.X >= LowerBoundary.X && point.X <= UpperBoundary.X &&
 | 
			
		||||
            point.Y >= LowerBoundary.Y && point.Y <= UpperBoundary.Y;
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(AABB other)
 | 
			
		||||
        => LowerBoundary.X <= other.UpperBoundary.X && UpperBoundary.X >= other.LowerBoundary.X &&
 | 
			
		||||
            LowerBoundary.Y <= other.UpperBoundary.Y && UpperBoundary.Y >= other.LowerBoundary.Y;
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(AABB other)
 | 
			
		||||
        => LowerBoundary.ApproximatelyEquals(other.LowerBoundary) && UpperBoundary.ApproximatelyEquals(other.UpperBoundary);
 | 
			
		||||
    public static bool ApproximatelyEquals(AABB left, AABB right)
 | 
			
		||||
        => left.LowerBoundary.ApproximatelyEquals(right.LowerBoundary) && left.UpperBoundary.ApproximatelyEquals(right.UpperBoundary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class AABBExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static bool ApproximatelyEquals(this AABB left, AABB right) => AABB.ApproximatelyEquals(left, right);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,15 +4,14 @@ namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Circle(Vector2D Position, float Radius)
 | 
			
		||||
{
 | 
			
		||||
    public bool Intersects(Circle other)
 | 
			
		||||
    {
 | 
			
		||||
        float distanceSquared = (Position - other.Position).LengthSquared();
 | 
			
		||||
        float radiusSumSquared = Radius * Radius + other.Radius * other.Radius;
 | 
			
		||||
    public float RadiusSquared => Radius * Radius;
 | 
			
		||||
    public float Diameter => 2f * Radius;
 | 
			
		||||
 | 
			
		||||
        return distanceSquared < radiusSumSquared;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(Vector2D point) => (Position - point).LengthSquared() <= Radius * Radius;
 | 
			
		||||
    public bool ApproximatelyEquals(Circle other)
 | 
			
		||||
        => Position.ApproximatelyEquals(other.Position) && Radius.ApproximatelyEquals(other.Radius);
 | 
			
		||||
    public static bool ApproximatelyEquals(Circle left, Circle right)
 | 
			
		||||
        => left.Position.ApproximatelyEquals(right.Position) && left.Radius.ApproximatelyEquals(right.Radius);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class CircleExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static bool ApproximatelyEquals(this Circle left, Circle right) => Circle.ApproximatelyEquals(left, right);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,30 +9,27 @@ namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
public record Line(Vector2D From, Vector2D To)
 | 
			
		||||
{
 | 
			
		||||
    public Line Reversed => new(To, From);
 | 
			
		||||
    public Vector2D Direction => Vector2D.Normalize(To - From);
 | 
			
		||||
    public float Length => (From - To).Length();
 | 
			
		||||
    public float LengthSquared => (From - To).LengthSquared();
 | 
			
		||||
    public Vector2D Direction => From.FromTo(To).Normalize();
 | 
			
		||||
    public float Length => From.FromTo(To).Length();
 | 
			
		||||
    public float LengthSquared => From.FromTo(To).LengthSquared();
 | 
			
		||||
 | 
			
		||||
    public LineEquation LineEquation
 | 
			
		||||
    public static LineEquation GetLineEquation(Line line)
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D slopeVector = To - From;
 | 
			
		||||
            float slope = slopeVector.Y / slopeVector.X;
 | 
			
		||||
        Vector2D slopeVector = line.From.FromTo(line.To);
 | 
			
		||||
        float slope = slopeVector.Y / slopeVector.X;
 | 
			
		||||
 | 
			
		||||
            float yOffset = From.Y - (slope * From.X);
 | 
			
		||||
        float yOffset = line.From.Y - (slope * line.From.X);
 | 
			
		||||
 | 
			
		||||
            return new LineEquation(slope, yOffset);
 | 
			
		||||
        }
 | 
			
		||||
        return new LineEquation(slope, yOffset);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Vector2D point)
 | 
			
		||||
        => Resolve(point.X).ApproximatelyEquals(point);
 | 
			
		||||
    public static bool Intersects(Line line, Vector2D point)
 | 
			
		||||
        => LineEquation.Resolve(GetLineEquation(line), point.X).ApproximatelyEquals(point.Y);
 | 
			
		||||
 | 
			
		||||
    public float GetT(Vector2D point)
 | 
			
		||||
    public static float GetT(Line line, Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        float fromX = MathF.Abs(From.X);
 | 
			
		||||
        float toX = MathF.Abs(To.X);
 | 
			
		||||
        float fromX = MathF.Abs(line.From.X);
 | 
			
		||||
        float toX = MathF.Abs(line.To.X);
 | 
			
		||||
        float pointX = MathF.Abs(point.X);
 | 
			
		||||
 | 
			
		||||
        float min = MathF.Min(fromX, toX);
 | 
			
		||||
@@ -46,32 +43,32 @@ public record Line(Vector2D From, Vector2D To)
 | 
			
		||||
        // I don't even know, apparently whatever I wrote up there doesn't take into account of the direction of the line
 | 
			
		||||
        // Which... I can see how, but I am also not sure how I can make it take into account. Or actually I'm for some reason
 | 
			
		||||
        // too unmotivated to find a solution. Future me, find a better way if possible, please.
 | 
			
		||||
        if (!Lerp(t).ApproximatelyEquals(point))
 | 
			
		||||
        if (!Lerp(line, t).ApproximatelyEquals(point))
 | 
			
		||||
            return 1f - t;
 | 
			
		||||
        return t;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Exist(List<Vector2D> vertices)
 | 
			
		||||
    public static bool Exist(Line line, List<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < vertices.Count - 1; i++)
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D vertexCurrent = vertices[i];
 | 
			
		||||
            Vector2D vertexNext = vertices[i];
 | 
			
		||||
            if (From == vertexCurrent && To == vertexNext) return true;
 | 
			
		||||
            if (From == vertexNext && To == vertexCurrent) return true;
 | 
			
		||||
            if (line.From == vertexCurrent && line.To == vertexNext) return true;
 | 
			
		||||
            if (line.From == vertexNext && line.To == vertexCurrent) return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Vector2D vertexFirst = vertices[0];
 | 
			
		||||
        Vector2D vertexLast = vertices[^1];
 | 
			
		||||
        if (From == vertexFirst && To == vertexLast) return true;
 | 
			
		||||
        if (From == vertexLast && To == vertexFirst) return true;
 | 
			
		||||
        if (line.From == vertexFirst && line.To == vertexLast) return true;
 | 
			
		||||
        if (line.From == vertexLast && line.To == vertexFirst) return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float IntersectionParameterT(Line other)
 | 
			
		||||
    public static float IntersectionParameterT(Line left, Line right)
 | 
			
		||||
    {
 | 
			
		||||
        float numerator = (From.X - other.From.X) * (other.From.Y - other.To.Y) - (From.Y - other.From.Y) * (other.From.X - other.To.X);
 | 
			
		||||
        float denominator = (From.X - To.X) * (other.From.Y - other.To.Y) - (From.Y - To.Y) * (other.From.X - other.To.X);
 | 
			
		||||
        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);
 | 
			
		||||
        float denominator = (left.From.X - left.To.X) * (right.From.Y - right.To.Y) - (left.From.Y - left.To.Y) * (right.From.X - right.To.X);
 | 
			
		||||
 | 
			
		||||
        // Lines are parallel
 | 
			
		||||
        if (denominator == 0)
 | 
			
		||||
@@ -80,20 +77,17 @@ public record Line(Vector2D From, Vector2D To)
 | 
			
		||||
        return numerator / denominator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D Lerp(float t)
 | 
			
		||||
    public static Vector2D Lerp(Line line, float t)
 | 
			
		||||
        => new Vector2D(
 | 
			
		||||
            From.X + (To.X - From.X) * t,
 | 
			
		||||
            From.Y + (To.Y - From.Y) * t
 | 
			
		||||
            line.From.X + (line.To.X - line.From.X) * t,
 | 
			
		||||
            line.From.Y + (line.To.Y - line.From.Y) * t
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    public Vector2D Resolve(float x)
 | 
			
		||||
        => new Vector2D(x, LineEquation.Resolve(x));
 | 
			
		||||
 | 
			
		||||
    public Vector2D ClosestPointTo(Vector2D point)
 | 
			
		||||
    public static Vector2D ClosestPointTo(Line line, Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        // Convert edge points to vectors
 | 
			
		||||
        var edgeVector = new Vector2D(To.X - From.X, To.Y - From.Y);
 | 
			
		||||
        var pointVector = new Vector2D(point.X - From.X, point.Y - From.Y);
 | 
			
		||||
        var edgeVector = new Vector2D(line.To.X - line.From.X, line.To.Y - line.From.Y);
 | 
			
		||||
        var pointVector = new Vector2D(point.X - line.From.X, point.Y - line.From.Y);
 | 
			
		||||
 | 
			
		||||
        // Calculate the projection of pointVector onto edgeVector
 | 
			
		||||
        float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y);
 | 
			
		||||
@@ -102,45 +96,50 @@ public record Line(Vector2D From, Vector2D To)
 | 
			
		||||
        t = MathF.Max(0, MathF.Min(1, t));
 | 
			
		||||
 | 
			
		||||
        // Calculate the closest point on the edge
 | 
			
		||||
        float closestX = From.X + t * edgeVector.X;
 | 
			
		||||
        float closestY = From.Y + t * edgeVector.Y;
 | 
			
		||||
        float closestX = line.From.X + t * edgeVector.X;
 | 
			
		||||
        float closestY = line.From.Y + t * edgeVector.Y;
 | 
			
		||||
 | 
			
		||||
        return new Vector2D((float)closestX, (float)closestY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D IntersectionPoint(Line other)
 | 
			
		||||
        => Vector2D.Lerp(From, To, IntersectionParameterT(other));
 | 
			
		||||
    public static Vector2D IntersectionPoint(Line left, Line right)
 | 
			
		||||
        => Vector2D.Lerp(left.From, left.To, IntersectionParameterT(left, right));
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Line other)
 | 
			
		||||
    public static bool Intersects(Line left, Line right)
 | 
			
		||||
    {
 | 
			
		||||
        int o1 = PhysicsMath.Orientation(From, To, other.From);
 | 
			
		||||
        int o2 = PhysicsMath.Orientation(From, To, other.To);
 | 
			
		||||
        int o3 = PhysicsMath.Orientation(other.From, other.To, From);
 | 
			
		||||
        int o4 = PhysicsMath.Orientation(other.From, other.To, To);
 | 
			
		||||
        int o1 = PhysicsMath.Orientation(left.From, left.To, right.From);
 | 
			
		||||
        int o2 = PhysicsMath.Orientation(left.From, left.To, right.To);
 | 
			
		||||
        int o3 = PhysicsMath.Orientation(right.From, right.To, left.From);
 | 
			
		||||
        int o4 = PhysicsMath.Orientation(right.From, right.To, left.To);
 | 
			
		||||
 | 
			
		||||
        if (o1 != o2 && o3 != o4)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        if (o1 == 0 && PhysicsMath.OnSegment(From, other.From, To)) return true;
 | 
			
		||||
        if (o2 == 0 && PhysicsMath.OnSegment(From, other.To, To)) return true;
 | 
			
		||||
        if (o3 == 0 && PhysicsMath.OnSegment(other.From, From, other.To)) return true;
 | 
			
		||||
        if (o4 == 0 && PhysicsMath.OnSegment(other.From, To, other.To)) return true;
 | 
			
		||||
        if (o1 == 0 && PhysicsMath.OnSegment(left.From, right.From, left.To)) return true;
 | 
			
		||||
        if (o2 == 0 && PhysicsMath.OnSegment(left.From, right.To, left.To)) return true;
 | 
			
		||||
        if (o3 == 0 && PhysicsMath.OnSegment(right.From, left.From, right.To)) return true;
 | 
			
		||||
        if (o4 == 0 && PhysicsMath.OnSegment(right.From, left.To, right.To)) return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Line other, [NotNullWhen(returnValue: true)] out Vector2D? point)
 | 
			
		||||
    public static bool Intersects(Line left, Line right, [NotNullWhen(returnValue: true)] out Vector2D? point)
 | 
			
		||||
    {
 | 
			
		||||
        point = null;
 | 
			
		||||
 | 
			
		||||
        bool result = Intersects(other);
 | 
			
		||||
        bool result = Intersects(left, right);
 | 
			
		||||
 | 
			
		||||
        if (result)
 | 
			
		||||
            point = IntersectionPoint(other);
 | 
			
		||||
            point = IntersectionPoint(left, right);
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(Line other)
 | 
			
		||||
        => From.ApproximatelyEquals(other.From) && To.ApproximatelyEquals(other.To);
 | 
			
		||||
    public static bool ApproximatelyEquals(Line left, Line right)
 | 
			
		||||
        => left.From.ApproximatelyEquals(right.From) && left.To.ApproximatelyEquals(right.To);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class LineExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static bool ApproximatelyEquals(this Line left, Line right) => Line.ApproximatelyEquals(left, right);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,14 @@ namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record LineEquation(float Slope, float OffsetY)
 | 
			
		||||
{
 | 
			
		||||
    public float Resolve(float x) => Slope * x + OffsetY; // y = mx + b
 | 
			
		||||
    public bool ApproximatelyEquals(LineEquation other)
 | 
			
		||||
        => Slope.ApproximatelyEquals(other.Slope) && OffsetY.ApproximatelyEquals(other.OffsetY);
 | 
			
		||||
    public static float Resolve(LineEquation lineEquation, float x) => lineEquation.Slope * x + lineEquation.OffsetY; // y = mx + b
 | 
			
		||||
 | 
			
		||||
    public static bool ApproximatelyEquals(LineEquation left, LineEquation right)
 | 
			
		||||
        => left.Slope.ApproximatelyEquals(right.Slope) && left.OffsetY.ApproximatelyEquals(right.OffsetY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class LineEquationExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static float Resolve(this LineEquation lineEquation, float x) => LineEquation.Resolve(lineEquation, x);
 | 
			
		||||
    public static bool ApproximatelyEquals(this LineEquation left, LineEquation right) => LineEquation.ApproximatelyEquals(left, right);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public static class Math
 | 
			
		||||
{
 | 
			
		||||
    public const float RadianToDegree = 57.29577866666166f;
 | 
			
		||||
    public const float DegreeToRadian = 0.01745329277777778f;
 | 
			
		||||
 | 
			
		||||
    public static float Clamp(float value, float min, float max) => (value < min) ? min : (value > max) ? max : value;
 | 
			
		||||
}
 | 
			
		||||
@@ -7,62 +7,65 @@ namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Shape(IList<Vector2D> Vertices)
 | 
			
		||||
{
 | 
			
		||||
    public Triangle SuperTriangle
 | 
			
		||||
    public static Triangle GetSuperTriangle(Shape shape)
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        float minX = float.MaxValue, minY = float.MaxValue;
 | 
			
		||||
        float maxX = float.MinValue, maxY = float.MinValue;
 | 
			
		||||
 | 
			
		||||
        foreach (Vector2D point in shape.Vertices)
 | 
			
		||||
        {
 | 
			
		||||
            float minX = float.MaxValue, minY = float.MaxValue;
 | 
			
		||||
            float maxX = float.MinValue, maxY = float.MinValue;
 | 
			
		||||
 | 
			
		||||
            foreach (Vector2D point in Vertices)
 | 
			
		||||
            {
 | 
			
		||||
                minX = MathF.Min(minX, point.X);
 | 
			
		||||
                minY = MathF.Min(minY, point.Y);
 | 
			
		||||
                maxX = MathF.Max(maxX, point.X);
 | 
			
		||||
                maxY = MathF.Max(maxY, point.Y);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            float dx = maxX - minX;
 | 
			
		||||
            float dy = maxY - minY;
 | 
			
		||||
            float deltaMax = MathF.Max(dx, dy);
 | 
			
		||||
            float midX = (minX + maxX) / 2;
 | 
			
		||||
            float midY = (minY + maxY) / 2;
 | 
			
		||||
 | 
			
		||||
            Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
            Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax);
 | 
			
		||||
            Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
 | 
			
		||||
            return new Triangle(p1, p2, p3);
 | 
			
		||||
            minX = MathF.Min(minX, point.X);
 | 
			
		||||
            minY = MathF.Min(minY, point.Y);
 | 
			
		||||
            maxX = MathF.Max(maxX, point.X);
 | 
			
		||||
            maxY = MathF.Max(maxY, point.Y);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        float dx = maxX - minX;
 | 
			
		||||
        float dy = maxY - minY;
 | 
			
		||||
        float deltaMax = MathF.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 List<Line> Lines
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            List<Line> lines = new List<Line>(Vertices.Count - 1);
 | 
			
		||||
            GetLinesNonAlloc(lines);
 | 
			
		||||
            return lines;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void GetLinesNonAlloc(IList<Line> lines)
 | 
			
		||||
    public static void GetLines(Shape shape, IList<Line> lines)
 | 
			
		||||
    {
 | 
			
		||||
        lines.Clear();
 | 
			
		||||
        for (int i = 0; i < Vertices.Count - 1; i++)
 | 
			
		||||
            lines.Add(new(Vertices[i], Vertices[i + 1]));
 | 
			
		||||
        lines.Add(new(Vertices[^1], Vertices[0]));
 | 
			
		||||
        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 bool ApproximatelyEquals(Shape other)
 | 
			
		||||
    public static List<Line> GetLines(Shape shape)
 | 
			
		||||
    {
 | 
			
		||||
        if (Vertices.Count != other.Vertices.Count)
 | 
			
		||||
        List<Line> lines = new(shape.Vertices.Count - 1);
 | 
			
		||||
        GetLines(shape, lines);
 | 
			
		||||
        return lines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static bool ApproximatelyEquals(Shape left, Shape right)
 | 
			
		||||
    {
 | 
			
		||||
        if (left.Vertices.Count != right.Vertices.Count)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < Vertices.Count; i++)
 | 
			
		||||
            if (!Vertices[i].ApproximatelyEquals(other.Vertices[i]))
 | 
			
		||||
        for (int i = 0; i < left.Vertices.Count; i++)
 | 
			
		||||
            if (!left.Vertices[i].ApproximatelyEquals(right.Vertices[i]))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class ShapeExtensions
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    public static bool ApproximatelyEquals(this Shape left, Shape right) => Shape.ApproximatelyEquals(left, right);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,49 +6,39 @@ namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Triangle(Vector2D A, Vector2D B, Vector2D C)
 | 
			
		||||
{
 | 
			
		||||
    public float Area => MathF.Abs((
 | 
			
		||||
            A.X * (B.Y - C.Y) +
 | 
			
		||||
            B.X * (C.Y - A.Y) +
 | 
			
		||||
            C.X * (A.Y - B.Y)
 | 
			
		||||
            ) * .5f);
 | 
			
		||||
    public float Area
 | 
			
		||||
        => .5f * MathF.Abs(
 | 
			
		||||
                A.X * (B.Y - C.Y) +
 | 
			
		||||
                B.X * (C.Y - A.Y) +
 | 
			
		||||
                C.X * (A.Y - B.Y)
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
    public Circle CircumCircle
 | 
			
		||||
    public static Circle GetCircumCircle(Triangle triangle)
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        Vector2D midAB = (triangle.A + triangle.B) / 2f;
 | 
			
		||||
        Vector2D midBC = (triangle.B + triangle.C) / 2f;
 | 
			
		||||
 | 
			
		||||
        float slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X);
 | 
			
		||||
        float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X);
 | 
			
		||||
 | 
			
		||||
        Vector2D center;
 | 
			
		||||
        if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon)
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D midAB = (A + B) / 2;
 | 
			
		||||
            Vector2D midBC = (B + C) / 2;
 | 
			
		||||
 | 
			
		||||
            float slopeAB = (B.Y - A.Y) / (B.X - A.X);
 | 
			
		||||
            float slopeBC = (C.Y - B.Y) / (C.X - B.X);
 | 
			
		||||
 | 
			
		||||
            Vector2D center;
 | 
			
		||||
            if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon)
 | 
			
		||||
            {
 | 
			
		||||
                float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB));
 | 
			
		||||
                float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2;
 | 
			
		||||
                center = new Vector2D(x, y);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                center = (midAB + midBC) * .5f;
 | 
			
		||||
 | 
			
		||||
            return new(center, Vector2D.Distance(center, A));
 | 
			
		||||
            float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2f * (slopeBC - slopeAB));
 | 
			
		||||
            float y = -(x - (triangle.A.X + triangle.B.X) / 2f) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2f;
 | 
			
		||||
            center = new Vector2D(x, y);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            center = (midAB + midBC) * .5f;
 | 
			
		||||
 | 
			
		||||
        return new(center, Vector2D.Distance(center, triangle.A));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        float originalTriangleArea = Area;
 | 
			
		||||
 | 
			
		||||
        float pointTriangleArea1 = new Triangle(point, B, C).Area;
 | 
			
		||||
        float pointTriangleArea2 = new Triangle(A, point, C).Area;
 | 
			
		||||
        float pointTriangleArea3 = new Triangle(A, B, point).Area;
 | 
			
		||||
 | 
			
		||||
        float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3;
 | 
			
		||||
 | 
			
		||||
        return originalTriangleArea.ApproximatelyEquals(pointTriangleAreasSum, float.Epsilon * 3f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(Triangle other)
 | 
			
		||||
        => A.ApproximatelyEquals(other.A) && B.ApproximatelyEquals(other.B) && C.ApproximatelyEquals(other.C);
 | 
			
		||||
    public static bool ApproximatelyEquals(Triangle left, Triangle right)
 | 
			
		||||
        => left.A.ApproximatelyEquals(right.A) && left.B.ApproximatelyEquals(right.B) && left.C.ApproximatelyEquals(right.C);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class TriangleExtensions
 | 
			
		||||
{
 | 
			
		||||
    public static bool ApproximatelyEquals(this Triangle left, Triangle right) => Triangle.ApproximatelyEquals(left, right);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user