docs(physics2d): Primitives
This commit is contained in:
@@ -1,22 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||
|
||||
[System.Diagnostics.DebuggerDisplay("From: {From.ToString(), nq}, To: {To.ToString(), nq}, Direction: {Direction.ToString(), nq}, Length: {Length}")]
|
||||
public readonly struct Line(Vector2D From, Vector2D To)
|
||||
/// <summary>
|
||||
/// Represents a 2D line segment defined by two endpoints.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the Line struct with the specified endpoints.
|
||||
/// </remarks>
|
||||
/// <param name="from">The starting point of the <see cref="Line"/> segment.</param>
|
||||
/// <param name="to">The ending point of the <see cref="Line"/> segment.</param>
|
||||
[System.Diagnostics.DebuggerDisplay("From: {From.ToString(),nq}, To: {To.ToString(),nq}, Direction: {Direction.ToString(),nq}, Length: {Length}")]
|
||||
public readonly struct Line(Vector2D from, Vector2D to)
|
||||
{
|
||||
public readonly Vector2D From { get; init; } = From;
|
||||
public readonly Vector2D To { get; init; } = To;
|
||||
/// <summary>
|
||||
/// The starting point of the <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public readonly Vector2D From = from;
|
||||
|
||||
/// <summary>
|
||||
/// The ending point of the <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public readonly Vector2D To = to;
|
||||
|
||||
/// <summary>
|
||||
/// The reversed <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public readonly Line Reversed => new(To, From);
|
||||
|
||||
/// <summary>
|
||||
/// The normalized direction <see cref="Vector2D"/> of the <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public readonly Vector2D Direction => From.FromTo(To).Normalize();
|
||||
|
||||
/// <summary>
|
||||
/// The length of the <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public readonly float Length => From.FromTo(To).Length();
|
||||
|
||||
/// <summary>
|
||||
/// The squared length of the <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public readonly float LengthSquared => From.FromTo(To).LengthSquared();
|
||||
|
||||
/// <summary>
|
||||
/// The equation of the <see cref="Line"/> defined by this <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public static LineEquation GetLineEquation(Line line)
|
||||
{
|
||||
Vector2D slopeVector = line.From.FromTo(line.To);
|
||||
@@ -27,9 +59,15 @@ public readonly struct Line(Vector2D From, Vector2D To)
|
||||
return new LineEquation(slope, yOffset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="Vector2D"/> lies on the <see cref="Line"/>.
|
||||
/// </summary>
|
||||
public static bool Intersects(Line line, Vector2D point)
|
||||
=> LineEquation.Resolve(GetLineEquation(line), point.X).ApproximatelyEquals(point.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the parameter 't' representing the point's position on the <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public static float GetT(Line line, Vector2D point)
|
||||
{
|
||||
float fromX = MathF.Abs(line.From.X);
|
||||
@@ -52,23 +90,63 @@ public readonly struct Line(Vector2D From, Vector2D To)
|
||||
return t;
|
||||
}
|
||||
|
||||
public static bool Exist(Line line, List<Vector2D> vertices)
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="Line"/> segment intersects with another <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public static bool Intersects(Line left, Line right)
|
||||
{
|
||||
for (int i = 0; i < vertices.Count - 1; i++)
|
||||
{
|
||||
Vector2D vertexCurrent = vertices[i];
|
||||
Vector2D vertexNext = vertices[i];
|
||||
if (line.From == vertexCurrent && line.To == vertexNext) return true;
|
||||
if (line.From == vertexNext && line.To == vertexCurrent) return true;
|
||||
}
|
||||
int o1 = Vector2D.Orientation(left.From, left.To, right.From);
|
||||
int o2 = Vector2D.Orientation(left.From, left.To, right.To);
|
||||
int o3 = Vector2D.Orientation(right.From, right.To, left.From);
|
||||
int o4 = Vector2D.Orientation(right.From, right.To, left.To);
|
||||
|
||||
if (o1 != o2 && o3 != o4)
|
||||
return true;
|
||||
|
||||
if (o1 == 0 && OnSegment(left, right.From)) return true;
|
||||
if (o2 == 0 && OnSegment(left, right.To)) return true;
|
||||
if (o3 == 0 && OnSegment(right, left.From)) return true;
|
||||
if (o4 == 0 && OnSegment(right, left.To)) return true;
|
||||
|
||||
Vector2D vertexFirst = vertices[0];
|
||||
Vector2D vertexLast = vertices[^1];
|
||||
if (line.From == vertexFirst && line.To == vertexLast) return true;
|
||||
if (line.From == vertexLast && line.To == vertexFirst) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the point lies within the <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public static bool OnSegment(Line line, Vector2D point)
|
||||
{
|
||||
if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) &&
|
||||
point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether two <see cref="Line"/> segments intersect.
|
||||
/// </summary>
|
||||
public static bool Intersects(Line left, Line right, [NotNullWhen(returnValue: true)] out Vector2D? point)
|
||||
{
|
||||
point = null;
|
||||
|
||||
bool result = Intersects(left, right);
|
||||
|
||||
if (result)
|
||||
point = IntersectionPoint(left, right);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the point of intersection between two <see cref="Line"/> segments.
|
||||
/// </summary>
|
||||
public static Vector2D IntersectionPoint(Line left, Line right)
|
||||
=> Vector2D.Lerp(left.From, left.To, IntersectionParameterT(left, right));
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the parameter 't' representing the intersection point's position on the <see cref="Line"/> segment.
|
||||
/// </summary>
|
||||
public static float IntersectionParameterT(Line left, Line right)
|
||||
{
|
||||
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);
|
||||
@@ -81,12 +159,18 @@ public readonly struct Line(Vector2D From, Vector2D To)
|
||||
return numerator / denominator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linearly interpolates between the two endpoints of the <see cref="Line"/> segment using parameter 't'.
|
||||
/// </summary>
|
||||
public static Vector2D Lerp(Line line, float t)
|
||||
=> new Vector2D(
|
||||
=> new(
|
||||
line.From.X + (line.To.X - line.From.X) * t,
|
||||
line.From.Y + (line.To.Y - line.From.Y) * t
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the closest point on the <see cref="Line"/> segment to the specified point.
|
||||
/// </summary>
|
||||
public static Vector2D ClosestPointTo(Line line, Vector2D point)
|
||||
{
|
||||
// Convert edge points to vectors
|
||||
@@ -106,53 +190,20 @@ public readonly struct Line(Vector2D From, Vector2D To)
|
||||
return new Vector2D((float)closestX, (float)closestY);
|
||||
}
|
||||
|
||||
public static Vector2D IntersectionPoint(Line left, Line right)
|
||||
=> Vector2D.Lerp(left.From, left.To, IntersectionParameterT(left, right));
|
||||
|
||||
public static bool Intersects(Line left, Line right)
|
||||
{
|
||||
int o1 = Vector2D.Orientation(left.From, left.To, right.From);
|
||||
int o2 = Vector2D.Orientation(left.From, left.To, right.To);
|
||||
int o3 = Vector2D.Orientation(right.From, right.To, left.From);
|
||||
int o4 = Vector2D.Orientation(right.From, right.To, left.To);
|
||||
|
||||
if (o1 != o2 && o3 != o4)
|
||||
return true;
|
||||
|
||||
if (o1 == 0 && OnSegment(left, right.From)) return true;
|
||||
if (o2 == 0 && OnSegment(left, right.To)) return true;
|
||||
if (o3 == 0 && OnSegment(right, left.From)) return true;
|
||||
if (o4 == 0 && OnSegment(right, left.To)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool OnSegment(Line line, Vector2D point)
|
||||
{
|
||||
if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) &&
|
||||
point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Intersects(Line left, Line right, [NotNullWhen(returnValue: true)] out Vector2D? point)
|
||||
{
|
||||
point = null;
|
||||
|
||||
bool result = Intersects(left, right);
|
||||
|
||||
if (result)
|
||||
point = IntersectionPoint(left, right);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Line"/> segments are approximately equal.
|
||||
/// </summary>
|
||||
public static bool ApproximatelyEquals(Line left, Line right)
|
||||
=> left.From.ApproximatelyEquals(right.From) && left.To.ApproximatelyEquals(right.To);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the Line struct.
|
||||
/// </summary>
|
||||
public static class LineExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Line"/>s are approximately equal.
|
||||
/// </summary>
|
||||
public static bool ApproximatelyEquals(this Line left, Line right) => Line.ApproximatelyEquals(left, right);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user