179 lines
4.6 KiB
C#
179 lines
4.6 KiB
C#
|
using System;
|
|||
|
|
|||
|
namespace TransportGame.Primitives
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// A line segment
|
|||
|
/// </summary>
|
|||
|
public struct LineSegment
|
|||
|
{
|
|||
|
#region Properties
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// X coordinate of first point
|
|||
|
/// </summary>
|
|||
|
public float X0 { get; private set; }
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Y coordinate of first point
|
|||
|
/// </summary>
|
|||
|
public float Y0 { get; private set; }
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// X coordinate of second point
|
|||
|
/// </summary>
|
|||
|
public float X1 { get; private set; }
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Y coordinate of second point
|
|||
|
/// </summary>
|
|||
|
public float Y1 { get; private set; }
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the first point
|
|||
|
/// </summary>
|
|||
|
public Vector2 P0
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return new Vector2(X0, Y0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the second point
|
|||
|
/// </summary>
|
|||
|
public Vector2 P1
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return new Vector2(X1, Y1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the length of the segment
|
|||
|
/// </summary>
|
|||
|
public float Length
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return (P1 - P0).Length;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the length squared of the segment
|
|||
|
/// </summary>
|
|||
|
public float LengthSq
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return (P1 - P0).LengthSq;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets the direction vector of the segment
|
|||
|
/// </summary>
|
|||
|
public Vector2 Direction
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return (P1 - P0).Normalized;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Constructors
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Initializes line segment
|
|||
|
/// </summary>
|
|||
|
/// <param name="p0">First point</param>
|
|||
|
/// <param name="p1">Second point</param>
|
|||
|
public LineSegment(Vector2 p0, Vector2 p1)
|
|||
|
: this()
|
|||
|
{
|
|||
|
X0 = p0.X; Y0 = p0.Y;
|
|||
|
X1 = p1.X; Y1 = p1.Y;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Initializes line segment
|
|||
|
/// </summary>
|
|||
|
/// <param name="x0">X coordinate of first segment</param>
|
|||
|
/// <param name="y0">Y coordinate of first segment</param>
|
|||
|
/// <param name="x1">X coordinate of second segment</param>
|
|||
|
/// <param name="y1">Y coordinate of second segment</param>
|
|||
|
public LineSegment(float x0, float y0, float x1, float y1)
|
|||
|
: this()
|
|||
|
{
|
|||
|
X0 = x0; Y0 = y0;
|
|||
|
X1 = x1; Y1 = y1;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Operations
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Calculates the intersection between two line segments.
|
|||
|
/// </summary>
|
|||
|
/// <remarks>
|
|||
|
/// Ignores case where intersection is a line.
|
|||
|
/// </remarks>
|
|||
|
/// <param name="a">First line segment</param>
|
|||
|
/// <param name="b">Second line segment</param>
|
|||
|
/// <returns>Intersection point, or null if segments don't intersect.</returns>
|
|||
|
public static Vector2? Intersect(LineSegment a, LineSegment b)
|
|||
|
{
|
|||
|
float s1x = a.X1 - a.X0, s1y = a.Y1 - a.Y0;
|
|||
|
float s2x = b.X1 - b.X0, s2y = b.Y1 - b.Y0;
|
|||
|
|
|||
|
float det = (-s2x * s1y + s1x * s2y);
|
|||
|
|
|||
|
// Avoid division by zero
|
|||
|
// Note: this is an edge case, the vectors might be parallel or colliniar
|
|||
|
if (det == 0) return null;
|
|||
|
|
|||
|
float s = (-s1y * (a.X0 - b.X0) + s1x * (a.Y0 - b.Y0)) / det;
|
|||
|
float t = (s2x * (a.Y0 - b.Y0) - s2y * (a.X0 - b.X0)) / det;
|
|||
|
|
|||
|
// Collision detected
|
|||
|
if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
|
|||
|
return new Vector2(a.X0 + t * s1x, a.Y0 + t * s1y);
|
|||
|
|
|||
|
// No collision
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Calculates the distance from a point p to a line segment
|
|||
|
/// </summary>
|
|||
|
/// <param name="p">Point</param>
|
|||
|
/// <returns>Distance</returns>
|
|||
|
public float Distance(Vector2 p)
|
|||
|
{
|
|||
|
float det = (Y1 - Y0) * p.X - (X1 - X0) * p.Y + X1 * Y0 - Y1 * X0;
|
|||
|
return Math.Abs(det) / Length;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region ToString
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets string representation of line segment
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
public override string ToString()
|
|||
|
{
|
|||
|
return string.Format("({0}, {1})->({2}, {3})", X0, Y0, X1, Y1);
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|