using System; namespace TransportGame.Primitives { /// /// A line segment /// public struct LineSegment { #region Properties /// /// X coordinate of first point /// public float X0 { get; private set; } /// /// Y coordinate of first point /// public float Y0 { get; private set; } /// /// X coordinate of second point /// public float X1 { get; private set; } /// /// Y coordinate of second point /// public float Y1 { get; private set; } /// /// Gets the first point /// public Vector2 P0 { get { return new Vector2(X0, Y0); } } /// /// Gets the second point /// public Vector2 P1 { get { return new Vector2(X1, Y1); } } /// /// Gets the length of the segment /// public float Length { get { return (P1 - P0).Length; } } /// /// Gets the length squared of the segment /// public float LengthSq { get { return (P1 - P0).LengthSq; } } /// /// Gets the direction vector of the segment /// public Vector2 Direction { get { return (P1 - P0).Normalized; } } #endregion #region Constructors /// /// Initializes line segment /// /// First point /// Second point public LineSegment(Vector2 p0, Vector2 p1) : this() { X0 = p0.X; Y0 = p0.Y; X1 = p1.X; Y1 = p1.Y; } /// /// Initializes line segment /// /// X coordinate of first segment /// Y coordinate of first segment /// X coordinate of second segment /// Y coordinate of second segment public LineSegment(float x0, float y0, float x1, float y1) : this() { X0 = x0; Y0 = y0; X1 = x1; Y1 = y1; } #endregion #region Operations /// /// Calculates the intersection between two line segments. /// /// /// Ignores case where intersection is a line. /// /// First line segment /// Second line segment /// Intersection point, or null if segments don't intersect. 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; } /// /// Calculates the distance from a point p to a line segment /// /// Point /// Distance 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 /// /// Gets string representation of line segment /// /// public override string ToString() { return string.Format("({0}, {1})->({2}, {3})", X0, Y0, X1, Y1); } #endregion } }