< Summary

Information
Class: FixedMathSharp.Bounds.FixedRay2d
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Primitives/FixedRay2d.cs
Line coverage
100%
Covered lines: 48
Uncovered lines: 0
Coverable lines: 48
Total lines: 199
Line coverage: 100%
Branch coverage
89%
Covered branches: 25
Total branches: 28
Branch coverage: 89.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

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

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// FixedRay2d.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 two-dimensional fixed-point space.
 17/// </summary>
 18/// <remarks>
 19/// The direction is not normalized by construction. Intersection methods return
 20/// the ray parameter for the first forward hit; when <see cref="Direction"/> is
 21/// normalized, that parameter is also the distance from <see cref="Position"/>.
 22/// </remarks>
 23[Serializable]
 24[MemoryPackable]
 25public partial struct FixedRay2d : IEquatable<FixedRay2d>
 26{
 27    #region Fields
 28
 29    /// <summary>
 30    /// The origin of the ray.
 31    /// </summary>
 32    [JsonInclude]
 33    [MemoryPackOrder(0)]
 34    public Vector2d Position;
 35
 36    /// <summary>
 37    /// The direction of the ray.
 38    /// </summary>
 39    [JsonInclude]
 40    [MemoryPackOrder(1)]
 41    public Vector2d Direction;
 42
 43    #endregion
 44
 45    #region Constructors
 46
 47    /// <summary>
 48    /// Initializes a new ray with the specified origin and direction.
 49    /// </summary>
 50    [JsonConstructor]
 51    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 52    public FixedRay2d(Vector2d position, Vector2d direction)
 53    {
 2754        Position = position;
 2755        Direction = direction;
 2756    }
 57
 58    #endregion
 59
 60    #region Methods
 61
 62    /// <summary>
 63    /// Gets the point at the specified ray parameter.
 64    /// </summary>
 65    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 166    public Vector2d GetPoint(Fixed64 distance) => Position + (Direction * distance);
 67
 68    /// <summary>
 69    /// Finds the first forward intersection with the specified bounding area, including boundary-only contact.
 70    /// </summary>
 71    public Fixed64? Intersects(FixedBoundArea area)
 72    {
 1173        Fixed64 tMin = Fixed64.Zero;
 1174        Fixed64 tMax = Fixed64.MaxValue;
 75
 1176        if (!ClipAxis(Position.X, Direction.X, area.Min.X, area.Max.X, ref tMin, ref tMax))
 277            return null;
 78
 979        if (!ClipAxis(Position.Y, Direction.Y, area.Min.Y, area.Max.Y, ref tMin, ref tMax))
 180            return null;
 81
 882        return tMin;
 83    }
 84
 85    /// <summary>
 86    /// Finds the first forward intersection with the specified bounding circle, including boundary-only contact.
 87    /// </summary>
 88    public Fixed64? Intersects(FixedBoundCircle circle)
 89    {
 990        Fixed64 directionLengthSquared = Direction.MagnitudeSquared;
 991        if (directionLengthSquared == Fixed64.Zero)
 292            return circle.Contains(Position) ? Fixed64.Zero : null;
 93
 794        Vector2d offset = Position - circle.Center;
 795        Fixed64 c = Vector2d.Dot(offset, offset) - circle.RadiusSquared;
 796        if (c <= Fixed64.Zero)
 297            return Fixed64.Zero;
 98
 599        Fixed64 b = Vector2d.Dot(offset, Direction);
 5100        if (b > Fixed64.Zero)
 1101            return null;
 102
 4103        Fixed64 discriminant = (b * b) - (directionLengthSquared * c);
 4104        if (discriminant < Fixed64.Zero)
 1105            return null;
 106
 3107        return FixedMath.FastDiv(-b - FixedMath.Sqrt(discriminant), directionLengthSquared);
 108    }
 109
 110    /// <summary>
 111    /// Deconstructs the ray into origin and direction.
 112    /// </summary>
 113    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 114    public void Deconstruct(out Vector2d position, out Vector2d direction)
 115    {
 1116        position = Position;
 1117        direction = Direction;
 1118    }
 119
 120    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 121    private static bool ClipAxis(
 122        Fixed64 position,
 123        Fixed64 direction,
 124        Fixed64 min,
 125        Fixed64 max,
 126        ref Fixed64 tMin,
 127        ref Fixed64 tMax)
 128    {
 20129        if (IsNearlyZero(direction))
 10130            return position >= min && position <= max;
 131
 10132        Fixed64 t1 = (min - position) / direction;
 10133        Fixed64 t2 = (max - position) / direction;
 134
 10135        if (t1 > t2)
 2136            (t2, t1) = (t1, t2);
 137
 10138        if (t1 > tMin)
 6139            tMin = t1;
 140
 10141        if (t2 < tMax)
 9142            tMax = t2;
 143
 10144        return tMin <= tMax;
 145    }
 146
 147    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 148    internal static bool IsNearlyZero(Fixed64 value)
 149    {
 20150        return value.Abs() <= Fixed64.Epsilon;
 151    }
 152
 153    #endregion
 154
 155    #region Operators
 156
 157    /// <summary>
 158    /// Determines whether two rays are equal.
 159    /// </summary>
 160    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2161    public static bool operator ==(FixedRay2d left, FixedRay2d right) => left.Equals(right);
 162
 163    /// <summary>
 164    /// Determines whether two rays are not equal.
 165    /// </summary>
 166    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2167    public static bool operator !=(FixedRay2d left, FixedRay2d right) => !left.Equals(right);
 168
 169    #endregion
 170
 171    #region Equality
 172
 173    /// <inheritdoc />
 174    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 175    public bool Equals(FixedRay2d other)
 176    {
 7177        return Position == other.Position && Direction == other.Direction;
 178    }
 179
 180    /// <inheritdoc />
 181    public override bool Equals(object? obj)
 182    {
 1183        return obj is FixedRay2d other && Equals(other);
 184    }
 185
 186    /// <inheritdoc />
 187    public override int GetHashCode()
 188    {
 189        unchecked
 190        {
 2191            int hash = 17;
 2192            hash = (hash * 31) + Position.StateHash;
 2193            hash = (hash * 31) + Direction.StateHash;
 2194            return hash;
 195        }
 196    }
 197
 198    #endregion
 199}