using System; using System.Diagnostics; using Microsoft.Xna.Framework; namespace MonoGame.Extended { // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 3.5; A Math and Geometry Primer - Lines, Rays, and Segments. pg 53-54 /// /// A two dimensional ray defined by a starting and a direction . /// /// /// [DebuggerDisplay("{DebugDisplayString,nq}")] public struct Ray2 : IEquatable, IEquatableByRef { /// /// The starting of this . /// public Vector2 Position; /// /// The direction of this . /// public Vector2 Direction; /// /// Initializes a new instance of the structure from the specified position and direction. /// /// The starting point. /// The direction vector. public Ray2(Vector2 position, Vector2 direction) { Position = position; Direction = direction; } /// /// Determines whether this intersects with a specified . /// /// The bounding rectangle. /// /// When this method returns, contains the distance along the ray to the first intersection /// point with the , if an intersection was found; otherwise, /// . /// This parameter is passed uninitialized. /// /// /// When this method returns, contains the distance along the ray to the second intersection /// point with the , if an intersection was found; otherwise, /// . /// This parameter is passed uninitialized. /// /// /// true if this intersects with ; otherwise, /// false. /// public bool Intersects(BoundingRectangle boundingRectangle, out float rayNearDistance, out float rayFarDistance) { // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 5.3; Basic Primitive Tests - Intersecting Lines, Rays, and (Directed Segments). pg 179-181 var minimum = boundingRectangle.Center - boundingRectangle.HalfExtents; var maximum = boundingRectangle.Center + boundingRectangle.HalfExtents; // Set to the smallest possible value so the algorithm can find the first hit along the ray var minimumDistanceAlongRay = float.MinValue; // Set to the maximum possible value so the algorithm can find the last hit along the ray var maximumDistanceAlongRay = float.MaxValue; // For all relevant slabs which in this case is two. // The first, horizontal, slab. if (!PrimitivesHelper.IntersectsSlab(Position.X, Direction.X, minimum.X, maximum.X, ref minimumDistanceAlongRay, ref maximumDistanceAlongRay)) { rayNearDistance = rayFarDistance = float.NaN; return false; } // The second, vertical, slab. if (!PrimitivesHelper.IntersectsSlab(Position.Y, Direction.Y, minimum.Y, maximum.Y, ref minimumDistanceAlongRay, ref maximumDistanceAlongRay)) { rayNearDistance = rayFarDistance = float.NaN; return false; } // Ray intersects the 2 slabs. rayNearDistance = minimumDistanceAlongRay < 0 ? 0 : minimumDistanceAlongRay; rayFarDistance = maximumDistanceAlongRay; return true; } /// /// Compares two structures. The result specifies whether the values of the /// /// and fields of the two structures are equal. /// /// The first ray. /// The second ray. /// /// true if the and /// fields of the two /// structures are equal; otherwise, false. /// public static bool operator ==(Ray2 first, Ray2 second) { return first.Equals(ref second); } /// /// Indicates whether this is equal to another . /// /// The ray. /// /// true if this is equal to the parameter; otherwise, /// false. /// public bool Equals(Ray2 ray) { return Equals(ref ray); } /// /// Indicates whether this is equal to another . /// /// The ray. /// /// true if this is equal to the ; otherwise, /// false. /// public bool Equals(ref Ray2 ray) { // ReSharper disable CompareOfFloatsByEqualityOperator return (ray.Position == Position) && (ray.Direction == Direction); // ReSharper restore CompareOfFloatsByEqualityOperator } /// /// Returns a value indicating whether this is equal to a specified object. /// /// The object to make the comparison with. /// /// true if this is equal to ; otherwise, false. /// public override bool Equals(object obj) { if (obj is Ray2) return Equals((Ray2) obj); return false; } /// /// Compares two structures. The result specifies whether the values of the /// /// and fields of the two structures are unequal. /// /// The first ray. /// The second ray. /// /// true if the and /// fields of the two /// structures are unequal; otherwise, false. /// public static bool operator !=(Ray2 first, Ray2 second) { return !(first == second); } /// /// Returns a hash code of this suitable for use in hashing algorithms and data /// structures like a hash table. /// /// /// A hash code of this . /// public override int GetHashCode() { unchecked { return (Position.GetHashCode()*397) ^ Direction.GetHashCode(); } } /// /// Returns a that represents this . /// /// /// A that represents this . /// public override string ToString() { return $"Position: {Position}, Direction: {Direction}"; } internal string DebugDisplayString => ToString(); } }