using System.Numerics;
using Sandbox;
///
/// A struct describing an origin and direction
///
public struct Ray : IEquatable
{
private Vector3 _origin;
private Vector3 _direction;
///
/// Origin of the ray.
///
public Vector3 Position
{
readonly get => _origin;
set => _origin = value;
}
///
/// Direction of the ray.
///
public Vector3 Forward
{
readonly get => _direction;
set => _direction = value;
}
public Ray( Vector3 origin, Vector3 direction )
{
_origin = origin;
_direction = direction;
}
///
/// Convert a ray to be local to this transform
///
public readonly Ray ToLocal( in Transform tx )
{
var ray = this;
ray.Forward = tx.NormalToLocal( ray.Forward );
ray.Position = tx.PointToLocal( ray.Position );
return ray;
}
///
/// Convert a ray from being local to this transform
///
public readonly Ray ToWorld( in Transform tx )
{
var ray = this;
ray.Forward = tx.NormalToWorld( ray.Forward );
ray.Position = tx.PointToWorld( ray.Position );
return ray;
}
///
/// Returns a point on the ray at given distance.
///
/// How far from the the point should be.
/// The point at given distance.
public readonly Vector3 Project( float distance ) => Position + Forward * distance;
private const float SafeMagnitude = 1e7f;
///
/// Returns a point on the ray at given safe distance.
///
/// How far from the the point should be.
/// The point at given distance.
internal readonly Vector3 ProjectSafe( float distance )
{
distance = float.IsNaN( distance ) ? SafeMagnitude : distance;
return Position + Forward * distance.Clamp( -SafeMagnitude, SafeMagnitude );
}
#region equality
public static bool operator ==( Ray left, Ray right ) => left.Equals( right );
public static bool operator !=( Ray left, Ray right ) => !(left == right);
public readonly override bool Equals( object obj ) => obj is Ray o && Equals( o );
public readonly bool Equals( Ray o ) => (_origin, _direction) == (o._origin, o._direction);
public readonly override int GetHashCode() => HashCode.Combine( _origin, _direction );
#endregion
}