115 lines
4.0 KiB
C#
115 lines
4.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
using Microsoft.Xna.Framework;
|
|
|
|
using Syntriax.Engine.Physics2D.Primitives;
|
|
|
|
namespace Syntriax.Engine.Physics2D;
|
|
|
|
public static class PhysicsMath
|
|
{
|
|
public static Vector2 Scale(this Vector2 original, Vector2 scale)
|
|
=> new Vector2(original.X * scale.X, original.Y * scale.Y);
|
|
|
|
public static Triangle ToSuperTriangle(this IList<Vector2> vertices)
|
|
{
|
|
float minX = float.MaxValue, minY = float.MaxValue;
|
|
float maxX = float.MinValue, maxY = float.MinValue;
|
|
|
|
foreach (Vector2 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;
|
|
|
|
Vector2 p1 = new Vector2((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
|
|
Vector2 p2 = new Vector2((float)midX, (float)midY + 20 * (float)deltaMax);
|
|
Vector2 p3 = new Vector2((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
|
|
|
|
return new Triangle(p1, p2, p3);
|
|
}
|
|
|
|
public static IList<Line> ToLines(this IList<Vector2> vertices)
|
|
{
|
|
List<Line> lines = new List<Line>(vertices.Count - 1);
|
|
ToLines(vertices, lines);
|
|
return lines;
|
|
}
|
|
|
|
public static void ToLines(this IList<Vector2> 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 Vector2 point, Line line)
|
|
=> line.Resolve(point.X).ApproximatelyEquals(point);
|
|
|
|
|
|
// Given three collinear points p, q, r, the function checks if
|
|
// point q lies on line segment 'pr'
|
|
public static bool OnSegment(Vector2 p, Vector2 q, Vector2 r)
|
|
{
|
|
if (q.X <= MathF.Max(p.X, r.X) && q.X >= MathF.Min(p.X, r.X) &&
|
|
q.Y <= MathF.Max(p.Y, r.Y) && q.Y >= MathF.Min(p.Y, r.Y))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// To find orientation of ordered triplet (p, q, r).
|
|
// The function returns following values
|
|
// 0 --> p, q and r are collinear
|
|
// 1 --> Clockwise
|
|
// 2 --> Counterclockwise
|
|
public static int Orientation(Vector2 p, Vector2 q, Vector2 r)
|
|
{
|
|
// See https://www.geeksforgeeks.org/orientation-3-ordered-points/
|
|
// for details of below formula.
|
|
float val = (q.Y - p.Y) * (r.X - q.X) -
|
|
(q.X - p.X) * (r.Y - q.Y);
|
|
|
|
if (val == 0) return 0; // collinear
|
|
|
|
return (val > 0) ? 1 : 2; // clock or counterclock wise
|
|
}
|
|
|
|
public static float IntersectionParameterT(Vector2 p0, Vector2 p1, Vector2 q0, Vector2 q1)
|
|
=> ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) /
|
|
((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y));
|
|
|
|
|
|
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 float a, float b, float epsilon)
|
|
{
|
|
if (a == b)
|
|
return true;
|
|
|
|
const float floatNormal = (1 << 23) * float.Epsilon;
|
|
float absA = MathF.Abs(a);
|
|
float absB = MathF.Abs(b);
|
|
float diff = MathF.Abs(a - b);
|
|
|
|
if (a == 0.0f || b == 0.0f || diff < floatNormal)
|
|
return diff < (epsilon * floatNormal);
|
|
|
|
return diff / MathF.Min(absA + absB, float.MaxValue) < epsilon;
|
|
}
|
|
}
|