< Summary

Information
Class: FixedMathSharp.FixedRay
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Primitives/FixedRay.cs
Line coverage
100%
Covered lines: 87
Uncovered lines: 0
Coverable lines: 87
Total lines: 226
Line coverage: 100%
Branch coverage
90%
Covered branches: 36
Total branches: 40
Branch coverage: 90%
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%11100%
Intersects(...)91.66%1212100%
Intersects(...)100%22100%
IntersectsBoxLike(...)87.5%88100%
ClipAxis(...)90%1010100%
IsNearlyZero(...)100%11100%
Deconstruct(...)100%11100%
op_Equality(...)100%11100%
op_Inequality(...)100%11100%
Equals(...)100%22100%
Equals(...)50%22100%
GetHashCode()100%11100%

File(s)

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

#LineLine coverage
 1using MemoryPack;
 2using System;
 3using System.Runtime.CompilerServices;
 4using System.Text.Json.Serialization;
 5
 6namespace FixedMathSharp;
 7
 8/// <summary>
 9/// Represents a ray with an origin and direction in three-dimensional space.
 10/// </summary>
 11/// <remarks>
 12/// Intersection methods return the ray parameter for the first forward hit. If <see cref="Direction"/> is normalized,
 13/// that parameter is also the distance from <see cref="Position"/>.
 14/// </remarks>
 15[Serializable]
 16[MemoryPackable]
 17public partial struct FixedRay : IEquatable<FixedRay>
 18{
 19    #region Fields
 20
 21    /// <summary>
 22    /// The origin of the ray.
 23    /// </summary>
 24    [JsonInclude]
 25    [MemoryPackOrder(0)]
 26    public Vector3d Position;
 27
 28    /// <summary>
 29    /// The direction of the ray.
 30    /// </summary>
 31    [JsonInclude]
 32    [MemoryPackOrder(1)]
 33    public Vector3d Direction;
 34
 35    #endregion
 36
 37    #region Constructors
 38
 39    /// <summary>
 40    /// Initializes a new ray with the specified origin and direction.
 41    /// </summary>
 42    [JsonConstructor]
 43    public FixedRay(Vector3d position, Vector3d direction)
 3344    {
 3345        Position = position;
 3346        Direction = direction;
 3347    }
 48
 49    #endregion
 50
 51    #region Methods
 52
 53    /// <summary>
 54    /// Finds the first forward intersection with the specified plane.
 55    /// </summary>
 56    public Fixed64? Intersects(FixedPlane plane)
 357    {
 358        Fixed64 denominator = plane.DotNormal(Direction);
 359        if (IsNearlyZero(denominator))
 160            return null;
 61
 262        Fixed64 t = -plane.DotCoordinate(Position) / denominator;
 263        return t < Fixed64.Zero ? null : t;
 364    }
 65
 66    /// <summary>
 67    /// Finds the first forward intersection with the specified bounding box.
 68    /// </summary>
 69    public Fixed64? Intersects(BoundingBox box)
 970    {
 971        return IntersectsBoxLike(box.Min, box.Max);
 972    }
 73
 74    /// <summary>
 75    /// Finds the first forward intersection with the specified bounding area.
 76    /// </summary>
 77    public Fixed64? Intersects(BoundingArea area)
 178    {
 179        return IntersectsBoxLike(area.Min, area.Max);
 180    }
 81
 82    /// <summary>
 83    /// Finds the first forward intersection with the specified bounding sphere.
 84    /// </summary>
 85    public Fixed64? Intersects(BoundingSphere sphere)
 786    {
 787        Fixed64 directionLengthSquared = Direction.SqrMagnitude;
 788        if (directionLengthSquared == Fixed64.Zero)
 289            return sphere.Contains(Position) ? Fixed64.Zero : null;
 90
 591        Vector3d offset = Position - sphere.Center;
 592        Fixed64 c = Vector3d.Dot(offset, offset) - sphere.SqrRadius;
 593        if (c <= Fixed64.Zero)
 194            return Fixed64.Zero;
 95
 496        Fixed64 b = Vector3d.Dot(offset, Direction);
 497        if (b > Fixed64.Zero)
 198            return null;
 99
 3100        Fixed64 discriminant = (b * b) - (directionLengthSquared * c);
 3101        if (discriminant < Fixed64.Zero)
 1102            return null;
 103
 2104        Fixed64 t = (-b - FixedMath.Sqrt(discriminant)) / directionLengthSquared;
 2105        return t < Fixed64.Zero ? null : t;
 7106    }
 107
 108    /// <summary>
 109    /// Finds the first forward intersection with the specified frustum.
 110    /// </summary>
 111    public Fixed64? Intersects(BoundingFrustum frustum)
 5112    {
 5113        if (frustum == null)
 1114            throw new ArgumentNullException(nameof(frustum));
 115
 4116        return frustum.Intersects(this);
 4117    }
 118
 119    private Fixed64? IntersectsBoxLike(Vector3d min, Vector3d max)
 10120    {
 10121        Fixed64 tMin = Fixed64.Zero;
 10122        Fixed64 tMax = Fixed64.MAX_VALUE;
 123
 10124        if (!ClipAxis(Position.x, Direction.x, min.x, max.x, ref tMin, ref tMax))
 2125            return null;
 126
 8127        if (!ClipAxis(Position.y, Direction.y, min.y, max.y, ref tMin, ref tMax))
 1128            return null;
 129
 7130        if (!ClipAxis(Position.z, Direction.z, min.z, max.z, ref tMin, ref tMax))
 2131            return null;
 132
 5133        return tMax < Fixed64.Zero ? null : tMin;
 10134    }
 135
 136    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 137    private static bool ClipAxis(
 138        Fixed64 position,
 139        Fixed64 direction,
 140        Fixed64 min,
 141        Fixed64 max,
 142        ref Fixed64 tMin,
 143        ref Fixed64 tMax)
 25144    {
 25145        if (IsNearlyZero(direction))
 17146            return position >= min && position <= max;
 147
 8148        Fixed64 t1 = (min - position) / direction;
 8149        Fixed64 t2 = (max - position) / direction;
 150
 8151        if (t1 > t2)
 1152        {
 1153            Fixed64 temp = t1;
 1154            t1 = t2;
 1155            t2 = temp;
 1156        }
 157
 8158        if (t1 > tMin)
 4159            tMin = t1;
 160
 8161        if (t2 < tMax)
 8162            tMax = t2;
 163
 8164        return tMin <= tMax;
 25165    }
 166
 167    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 168    internal static bool IsNearlyZero(Fixed64 value)
 51169    {
 51170        return value.Abs() <= Fixed64.Epsilon;
 51171    }
 172
 173    /// <summary>
 174    /// Deconstructs the ray into its origin and direction.
 175    /// </summary>
 176    public void Deconstruct(out Vector3d position, out Vector3d direction)
 1177    {
 1178        position = Position;
 1179        direction = Direction;
 1180    }
 181
 182    #endregion
 183
 184    #region Operators
 185
 186    /// <summary>
 187    /// Determines whether two rays are equal.
 188    /// </summary>
 189    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2190    public static bool operator ==(FixedRay left, FixedRay right) => left.Equals(right);
 191
 192    /// <summary>
 193    /// Determines whether two rays are not equal.
 194    /// </summary>
 195    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1196    public static bool operator !=(FixedRay left, FixedRay right) => !left.Equals(right);
 197
 198    #endregion
 199
 200    #region Equality
 201
 202    /// <inheritdoc/>
 203    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2204    public override bool Equals(object? obj) => obj is FixedRay other && Equals(other);
 205
 206    /// <inheritdoc/>
 207    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 208    public bool Equals(FixedRay other)
 8209    {
 8210        return Position.Equals(other.Position) && Direction.Equals(other.Direction);
 8211    }
 212
 213    /// <inheritdoc/>
 214    public override int GetHashCode()
 2215    {
 216        unchecked
 2217        {
 2218            int hash = 17;
 2219            hash = hash * 23 + Position.GetHashCode();
 2220            hash = hash * 23 + Direction.GetHashCode();
 2221            return hash;
 222        }
 2223    }
 224
 225    #endregion
 226}