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();
}
}