< Summary

Information
Class: FixedMathSharp.Bounds.FixedRay
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Primitives/FixedRay.cs
Line coverage
100%
Covered lines: 59
Uncovered lines: 0
Coverable lines: 59
Total lines: 223
Line coverage: 100%
Branch coverage
100%
Covered branches: 34
Total branches: 34
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Intersects(...)100%44100%
Intersects(...)100%11100%
Intersects(...)100%1010100%
Intersects(...)100%11100%
IntersectsBoxLike(...)100%66100%
ClipAxis(...)100%1010100%
IsNearlyZero(...)100%11100%
Deconstruct(...)100%11100%
op_Equality(...)100%11100%
op_Inequality(...)100%11100%
Equals(...)100%22100%
Equals(...)100%22100%
GetHashCode()100%11100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Primitives/FixedRay.cs

#LineLine coverage
 1//=======================================================================
 2// FixedRay.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using MemoryPack;
 9using System;
 10using System.Runtime.CompilerServices;
 11using System.Text.Json.Serialization;
 12
 13namespace FixedMathSharp.Bounds;
 14
 15/// <summary>
 16/// Represents a ray with an origin and direction in three-dimensional space.
 17/// </summary>
 18/// <remarks>
 19/// Intersection methods return the ray parameter for the first forward hit. If <see cref="Direction"/> is normalized,
 20/// that parameter is also the distance from <see cref="Position"/>.
 21/// </remarks>
 22[Serializable]
 23[MemoryPackable]
 24public partial struct FixedRay : IEquatable<FixedRay>
 25{
 26    #region Fields
 27
 28    /// <summary>
 29    /// The origin of the ray.
 30    /// </summary>
 31    [JsonInclude]
 32    [MemoryPackOrder(0)]
 33    public Vector3d Position;
 34
 35    /// <summary>
 36    /// The direction of the ray.
 37    /// </summary>
 38    [JsonInclude]
 39    [MemoryPackOrder(1)]
 40    public Vector3d Direction;
 41
 42    #endregion
 43
 44    #region Constructors
 45
 46    /// <summary>
 47    /// Initializes a new ray with the specified origin and direction.
 48    /// </summary>
 49    [JsonConstructor]
 50    public FixedRay(Vector3d position, Vector3d direction)
 51    {
 3852        Position = position;
 3853        Direction = direction;
 3854    }
 55
 56    #endregion
 57
 58    #region Methods
 59
 60    /// <summary>
 61    /// Finds the first forward intersection with the specified plane.
 62    /// </summary>
 63    public Fixed64? Intersects(FixedPlane plane)
 64    {
 365        Fixed64 denominator = plane.DotNormal(Direction);
 366        if (IsNearlyZero(denominator))
 167            return null;
 68
 269        Fixed64 t = -plane.DotCoordinate(Position) / denominator;
 270        return t < Fixed64.Zero ? null : t;
 71    }
 72
 73    /// <summary>
 74    /// Finds the first forward intersection with the specified bounding box.
 75    /// </summary>
 76    public Fixed64? Intersects(FixedBoundBox box)
 77    {
 1278        return IntersectsBoxLike(box.Min, box.Max);
 79    }
 80
 81    /// <summary>
 82    /// Finds the first forward intersection with the specified bounding sphere.
 83    /// </summary>
 84    public Fixed64? Intersects(FixedBoundSphere sphere)
 85    {
 886        Fixed64 directionLengthSquared = Direction.MagnitudeSquared;
 887        if (directionLengthSquared == Fixed64.Zero)
 288            return sphere.Contains(Position) ? Fixed64.Zero : null;
 89
 690        Vector3d offset = Position - sphere.Center;
 691        Fixed64 c = Vector3d.Dot(offset, offset) - sphere.RadiusSquared;
 692        if (c <= Fixed64.Zero)
 193            return Fixed64.Zero;
 94
 595        Fixed64 b = Vector3d.Dot(offset, Direction);
 596        if (b > Fixed64.Zero)
 197            return null;
 98
 499        Fixed64 discriminant = (b * b) - (directionLengthSquared * c);
 4100        if (discriminant < Fixed64.Zero)
 1101            return null;
 102
 3103        Fixed64 t = FixedMath.FastDiv(-b - FixedMath.Sqrt(discriminant), directionLengthSquared);
 3104        return t;
 105    }
 106
 107    /// <summary>
 108    /// Finds the first forward intersection with the specified frustum.
 109    /// </summary>
 110    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 111    public Fixed64? Intersects(FixedBoundFrustum frustum)
 112    {
 4113        return frustum.Intersects(this);
 114    }
 115
 116    private Fixed64? IntersectsBoxLike(Vector3d min, Vector3d max)
 117    {
 12118        Fixed64 tMin = Fixed64.Zero;
 12119        Fixed64 tMax = Fixed64.MaxValue;
 120
 12121        if (!ClipAxis(Position.X, Direction.X, min.X, max.X, ref tMin, ref tMax))
 2122            return null;
 123
 10124        if (!ClipAxis(Position.Y, Direction.Y, min.Y, max.Y, ref tMin, ref tMax))
 2125            return null;
 126
 8127        if (!ClipAxis(Position.Z, Direction.Z, min.Z, max.Z, ref tMin, ref tMax))
 2128            return null;
 129
 6130        return tMin;
 131    }
 132
 133    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 134    private static bool ClipAxis(
 135        Fixed64 position,
 136        Fixed64 direction,
 137        Fixed64 min,
 138        Fixed64 max,
 139        ref Fixed64 tMin,
 140        ref Fixed64 tMax)
 141    {
 30142        if (IsNearlyZero(direction))
 19143            return position >= min && position <= max;
 144
 11145        Fixed64 t1 = (min - position) / direction;
 11146        Fixed64 t2 = (max - position) / direction;
 147
 11148        if (t1 > t2)
 149        {
 1150            Fixed64 temp = t1;
 1151            t1 = t2;
 1152            t2 = temp;
 153        }
 154
 11155        if (t1 > tMin)
 6156            tMin = t1;
 157
 11158        if (t2 < tMax)
 10159            tMax = t2;
 160
 11161        return tMin <= tMax;
 162    }
 163
 164    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 165    internal static bool IsNearlyZero(Fixed64 value)
 166    {
 64167        return value.Abs() <= Fixed64.Epsilon;
 168    }
 169
 170    /// <summary>
 171    /// Deconstructs the ray into its origin and direction.
 172    /// </summary>
 173    public void Deconstruct(out Vector3d position, out Vector3d direction)
 174    {
 1175        position = Position;
 1176        direction = Direction;
 1177    }
 178
 179    #endregion
 180
 181    #region Operators
 182
 183    /// <summary>
 184    /// Determines whether two rays are equal.
 185    /// </summary>
 186    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2187    public static bool operator ==(FixedRay left, FixedRay right) => left.Equals(right);
 188
 189    /// <summary>
 190    /// Determines whether two rays are not equal.
 191    /// </summary>
 192    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1193    public static bool operator !=(FixedRay left, FixedRay right) => !left.Equals(right);
 194
 195    #endregion
 196
 197    #region Equality
 198
 199    /// <inheritdoc/>
 200    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2201    public override bool Equals(object? obj) => obj is FixedRay other && Equals(other);
 202
 203    /// <inheritdoc/>
 204    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 205    public bool Equals(FixedRay other)
 206    {
 9207        return Position.Equals(other.Position) && Direction.Equals(other.Direction);
 208    }
 209
 210    /// <inheritdoc/>
 211    public override int GetHashCode()
 212    {
 213        unchecked
 214        {
 2215            int hash = 17;
 2216            hash = hash * 23 + Position.GetHashCode();
 2217            hash = hash * 23 + Direction.GetHashCode();
 2218            return hash;
 219        }
 220    }
 221
 222    #endregion
 223}