< Summary

Line coverage
100%
Covered lines: 669
Uncovered lines: 0
Coverable lines: 669
Total lines: 1323
Line coverage: 100%
Branch coverage
100%
Covered branches: 156
Total branches: 156
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: GetCenteredCapsuleSupportAnchor(...)100%11100%
File 1: GetCenteredCapsuleSupportAnchor(...)100%11100%
File 1: GetCenteredCapsuleSupportAnchor(...)100%11100%
File 1: GetCenteredCylinderSupportAnchor(...)100%11100%
File 1: GetCenteredCylinderSupportAnchor(...)100%44100%
File 1: GetCenteredCylinderSupportAnchor(...)100%11100%
File 1: GetCenteredCylinderSupportAnchor(...)100%11100%
File 1: GetCenteredConeSupportAnchor(...)100%11100%
File 1: GetCenteredAxisSupportAnchor(...)100%1818100%
File 2: .cctor()100%11100%
File 2: GetIntervalSize(...)100%22100%
File 2: GetIntervalScope(...)100%22100%
File 2: GetExtentMagnitude(...)100%22100%
File 2: GetHalfSizeMagnitude(...)100%22100%
File 2: GetVolumeExpansionCost(...)100%22100%
File 2: GetIntervalVolume(...)100%11100%
File 2: CompareDistanceToRadiusSum(...)100%11100%
File 2: CompareDistanceToRadiusSum(...)100%11100%
File 2: ContainsCenteredExtent(...)100%66100%
File 2: TryGetDistance(...)100%11100%
File 2: TryGetDistance(...)100%11100%
File 2: InterpolateCoordinate(...)100%22100%
File 2: TryRoundDistance(...)100%88100%
File 2: GetSquaredRadiusSum(...)100%11100%
File 2: GetDifferenceDotProduct2D(...)100%11100%
File 2: GetDifferenceDotProduct3D(...)100%1212100%
File 2: IsSquaredLengthDegenerate(...)100%44100%
File 2: GetDifferenceCrossProduct2D(...)100%11100%
File 2: GetDifferenceCrossProduct3D(...)100%1212100%
File 2: GetSquaredMagnitude(...)100%11100%
File 2: IsQ128MagnitudeAtMostEpsilon(...)100%11100%
File 2: CompareSquaredDistance3D(...)100%11100%
File 2: GetTripleProductSign(...)100%11100%
File 2: IsSegmentDeterminantNearParallel(...)100%11100%
File 2: AccumulateDifferenceProduct(...)100%1212100%
File 2: GetRawCrossComponent(...)100%11100%
File 2: TrySubtractRaw(...)100%11100%
File 2: AccumulateRawProduct(...)100%1212100%
File 2: TryGetScaledMagnitudeCeiling(...)100%88100%
File 2: TryGetMagnitudeCeiling(...)100%66100%
File 2: TryGetMagnitudeCeiling(...)100%44100%
File 2: GetCanonicalAxisRotation(...)100%44100%
File 2: GetCenteredFiniteAxisBoundClippedToDomain(...)100%22100%
File 2: GetRationalBoundClippedToDomain(...)100%1414100%
File 2: GetRationalBoundClippedToDomain(...)100%1212100%
File 3: CompareDifferenceProjection(...)100%22100%
File 3: GetDifferenceProjectionWords(...)100%11100%
File 3: GetNonNegativeDifferenceProjectionParameter(...)100%22100%
File 3: GetNormalizedProjectionOnPlane(...)100%22100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WideGeometry.Anchors.cs

#LineLine coverage
 1//=======================================================================
 2// WideGeometry.Anchors.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
 8namespace FixedMathSharp.Geometry;
 9
 10/// <content>
 11/// Exact scalar reductions for computing support anchors of centered axis-aligned shapes.
 12/// </content>
 13internal static partial class WideGeometry
 14{
 15    internal static FixedPointAnchor GetCenteredCapsuleSupportAnchor(
 16        Vector3d center,
 17        FixedQuaternion canonicalAxisRotation,
 18        Fixed64 axisLength,
 19        Fixed64 radius,
 20        Vector3d worldDirection) =>
 621        GetCenteredAxisSupportAnchor(
 622            center,
 623            canonicalAxisRotation,
 624            Vector3d.Up,
 625            axisLength,
 626            radius,
 627            worldDirection,
 628            CenteredAxisSupportKind.Capsule);
 29
 30    internal static FixedPointAnchor GetCenteredCapsuleSupportAnchor(
 31        Vector3d center,
 32        FixedQuaternion rotation,
 33        Vector3d localAxis,
 34        Fixed64 axisLength,
 35        Fixed64 radius,
 36        Vector3d worldDirection) =>
 55837        GetCenteredAxisSupportAnchor(
 55838            center,
 55839            rotation,
 55840            localAxis,
 55841            axisLength,
 55842            radius,
 55843            worldDirection,
 55844            CenteredAxisSupportKind.Capsule);
 45
 46    internal static FixedPointAnchor GetCenteredCapsuleSupportAnchor(
 47        Vector3d center,
 48        FixedQuaternion rotation,
 49        Vector3d localAxis,
 50        Fixed64 axisLength,
 51        Fixed64 radius,
 52        Vector3d worldDirection,
 53        int axialSign) =>
 99354        GetCenteredAxisSupportAnchor(
 99355            center,
 99356            rotation,
 99357            localAxis,
 99358            axisLength,
 99359            radius,
 99360            worldDirection,
 99361            CenteredAxisSupportKind.Capsule,
 99362            axialSign);
 63
 64    internal static FixedPointAnchor GetCenteredCylinderSupportAnchor(
 65        Vector3d center,
 66        FixedQuaternion canonicalAxisRotation,
 67        Fixed64 axisLength,
 68        Fixed64 radius,
 69        Vector3d worldDirection) =>
 2270        GetCenteredAxisSupportAnchor(
 2271            center,
 2272            canonicalAxisRotation,
 2273            Vector3d.Up,
 2274            axisLength,
 2275            radius,
 2276            worldDirection,
 2277            CenteredAxisSupportKind.Cylinder);
 78
 79    internal static FixedPointAnchor GetCenteredCylinderSupportAnchor(
 80        Vector3d center,
 81        FixedQuaternion canonicalAxisRotation,
 82        Fixed64 axisLength,
 83        Fixed64 radius,
 84        Vector3d worldDirection,
 85        bool preferAxialCenter)
 86    {
 1487        if (!preferAxialCenter)
 688            return GetCenteredCylinderSupportAnchor(
 689                center, canonicalAxisRotation, axisLength, radius, worldDirection);
 90
 891        int axialSign = WideOrientedBox.GetRotatedLocalProjectionSign(
 892            canonicalAxisRotation, Vector3d.Up, worldDirection);
 93        // A perpendicular support exposes the whole axial generator. A zero
 94        // effective length selects its midpoint without changing radial support.
 895        return GetCenteredAxisSupportAnchor(
 896            center,
 897            canonicalAxisRotation,
 898            Vector3d.Up,
 899            axialSign == 0 ? Fixed64.Zero : axisLength,
 8100            radius,
 8101            worldDirection,
 8102            CenteredAxisSupportKind.Cylinder,
 8103            forcedAxialSign: axialSign);
 104    }
 105
 106    internal static FixedPointAnchor GetCenteredCylinderSupportAnchor(
 107        Vector3d center,
 108        FixedQuaternion rotation,
 109        Vector3d localAxis,
 110        Fixed64 axisLength,
 111        Fixed64 radius,
 112        Vector3d worldDirection) =>
 2635113        GetCenteredAxisSupportAnchor(
 2635114            center,
 2635115            rotation,
 2635116            localAxis,
 2635117            axisLength,
 2635118            radius,
 2635119            worldDirection,
 2635120            CenteredAxisSupportKind.Cylinder);
 121
 122    internal static FixedPointAnchor GetCenteredCylinderSupportAnchor(
 123        Vector3d center,
 124        FixedQuaternion rotation,
 125        Vector3d localAxis,
 126        Fixed64 axisLength,
 127        Fixed64 radius,
 128        Vector3d worldDirection,
 129        int axialSign) =>
 2034130        GetCenteredAxisSupportAnchor(
 2034131            center,
 2034132            rotation,
 2034133            localAxis,
 2034134            axisLength,
 2034135            radius,
 2034136            worldDirection,
 2034137            CenteredAxisSupportKind.Cylinder,
 2034138            axialSign);
 139
 140    internal static FixedPointAnchor GetCenteredConeSupportAnchor(
 141        Vector3d center,
 142        FixedQuaternion canonicalAxisRotation,
 143        Fixed64 height,
 144        Fixed64 radius,
 145        Vector3d worldDirection) =>
 8146        GetCenteredAxisSupportAnchor(
 8147            center,
 8148            canonicalAxisRotation,
 8149            Vector3d.Up,
 8150            height,
 8151            radius,
 8152            worldDirection,
 8153            CenteredAxisSupportKind.Cone);
 154
 155    private static FixedPointAnchor GetCenteredAxisSupportAnchor(
 156        Vector3d center,
 157        FixedQuaternion canonicalAxisRotation,
 158        Vector3d localAxis,
 159        Fixed64 axisLength,
 160        Fixed64 radius,
 161        Vector3d worldDirection,
 162        CenteredAxisSupportKind kind,
 163        int? forcedAxialSign = null)
 164    {
 6264165        Vector3d localDirection = WideNormalization.GetNormalized(
 6264166            canonicalAxisRotation.Inverse().Rotate(worldDirection));
 6264167        Fixed64 halfLength = axisLength / Fixed64.Two;
 6264168        int axialSign = forcedAxialSign
 6264169            ?? WideOrientedBox.GetRotatedLocalProjectionSign(
 6264170                canonicalAxisRotation,
 6264171                localAxis,
 6264172                worldDirection);
 6264173        bool positiveAxis = axialSign > 0;
 6264174        Vector3d localPoint =
 6264175            localAxis * (positiveAxis ? halfLength : -halfLength);
 6264176        Fixed64 signedAxisLength = positiveAxis
 6264177            ? axisLength
 6264178            : -axisLength;
 179        Vector3d localDisplacement;
 180        Vector3d localRadialDirection;
 6264181        if (kind == CenteredAxisSupportKind.Capsule)
 182        {
 1557183            if (axialSign == 0)
 184            {
 552185                localPoint = Vector3d.Zero;
 552186                signedAxisLength = Fixed64.Zero;
 187            }
 1557188            localRadialDirection = localDirection;
 1557189            localDisplacement = localDirection * radius;
 190        }
 191        else
 192        {
 4707193            if (kind == CenteredAxisSupportKind.Cylinder)
 194            {
 4699195                Fixed64 axialProjection =
 4699196                    Vector3d.Dot(localDirection, localAxis);
 4699197                localRadialDirection = WideNormalization.GetNormalized(
 4699198                    localDirection - (localAxis * axialProjection));
 199            }
 200            else
 201            {
 8202                Vector2d planarDirection = WideNormalization.GetNormalized(
 8203                    new Vector2d(localDirection.X, localDirection.Z));
 8204                if (planarDirection == Vector2d.Zero)
 2205                    planarDirection = Vector2d.Right;
 8206                localRadialDirection = new Vector3d(
 8207                    planarDirection.X,
 8208                    Fixed64.Zero,
 8209                    planarDirection.Y);
 210            }
 4707211            localDisplacement = localRadialDirection * radius;
 4707212            bool coneApex = WideFiniteAxisIntersection
 4707213                    .IsCenteredFiniteConeApexSupport(
 4707214                        Vector3d.Up,
 4707215                        axisLength,
 4707216                        radius,
 4707217                        localDirection);
 4707218            if (kind == CenteredAxisSupportKind.Cone
 4707219                && coneApex)
 220            {
 1221                signedAxisLength = axisLength;
 1222                localRadialDirection = Vector3d.Zero;
 1223                localDisplacement = Vector3d.Zero;
 224            }
 4706225            else if (kind == CenteredAxisSupportKind.Cone)
 226            {
 7227                signedAxisLength = -axisLength;
 7228                localPoint = new Vector3d(
 7229                    Fixed64.Zero,
 7230                    -halfLength,
 7231                    Fixed64.Zero);
 232            }
 233        }
 234
 6264235        FixedPointAnchorTerm3d exactLocalTerm =
 6264236            FixedPointAnchorTerm3d.CreateCenteredAxisSupport(
 6264237                localAxis,
 6264238                signedAxisLength,
 6264239                localRadialDirection,
 6264240                radius,
 6264241                localPoint,
 6264242                localDisplacement);
 6264243        return new FixedPointAnchor(
 6264244            center,
 6264245            canonicalAxisRotation,
 6264246            localPoint,
 6264247            localDisplacement,
 6264248            exactLocalTerm);
 249    }
 250}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WideGeometry.cs

#LineLine coverage
 1//=======================================================================
 2// WideGeometry.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 System.Runtime.CompilerServices;
 9
 10using System;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <summary>
 15/// Provides shared helper methods for computing support points, anchors, and axis-aligned
 16/// transformations used by GJK/EPA-based wide (batched) collision detection routines.
 17/// </summary>
 18internal static partial class WideGeometry
 19{
 120    internal static readonly Signed192 CenteredAxisDenominator =
 121        Signed192.Signed(FixedMath.ONE_L * 2L);
 22
 23    #region Nested Types
 24
 25    private enum CenteredAxisSupportKind
 26    {
 27        Capsule,
 28        Cylinder,
 29        Cone,
 30    }
 31
 32    #endregion
 33
 34    /// <summary>
 35    /// Returns the exact representable size of a normalized scalar interval.
 36    /// </summary>
 37    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 38    internal static Fixed64 GetIntervalSize(Fixed64 min, Fixed64 max)
 39    {
 6640        ulong span = unchecked((ulong)max.m_rawValue - (ulong)min.m_rawValue);
 6641        if (span > long.MaxValue)
 442            throw new System.OverflowException("The interval size is outside the representable Fixed64 range.");
 43
 6244        return Fixed64.FromRaw((long)span);
 45    }
 46
 47    /// <summary>
 48    /// Returns the smallest representable half-extent that contains both ends
 49    /// of a normalized scalar interval around its lattice midpoint.
 50    /// </summary>
 51    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 52    internal static Fixed64 GetIntervalScope(Fixed64 min, Fixed64 max)
 53    {
 5054        ulong span = unchecked((ulong)max.m_rawValue - (ulong)min.m_rawValue);
 5055        ulong scope = (span >> 1) + (span & 1UL);
 5056        if (scope > long.MaxValue)
 257            throw new System.OverflowException("The interval scope is outside the representable Fixed64 range.");
 58
 4859        return Fixed64.FromRaw((long)scope);
 60    }
 61
 62    /// <summary>
 63    /// Returns the representable absolute magnitude of a scalar extent.
 64    /// </summary>
 65    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 66    internal static Fixed64 GetExtentMagnitude(Fixed64 extent)
 67    {
 4768        if (extent == Fixed64.MinValue)
 269            throw new System.OverflowException("The extent magnitude is outside the representable Fixed64 range.");
 70
 4571        return extent.Abs();
 72    }
 73
 74    /// <summary>
 75    /// Returns the smallest scalar half-extent whose symmetric interval covers
 76    /// the requested size magnitude, including the minimum scalar input.
 77    /// </summary>
 78    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 79    internal static Fixed64 GetHalfSizeMagnitude(Fixed64 size)
 80    {
 44181        ulong magnitude = size.m_rawValue < 0L
 44182            ? unchecked(0UL - (ulong)size.m_rawValue)
 44183            : (ulong)size.m_rawValue;
 44184        ulong half = (magnitude >> 1) + (magnitude & 1UL);
 44185        return Fixed64.FromRaw((long)half);
 86    }
 87
 88    /// <summary>
 89    /// Returns an exact full-domain AABB union-volume growth metric.
 90    /// </summary>
 91    internal static long GetVolumeExpansionCost(
 92        Vector3d min,
 93        Vector3d max,
 94        Vector3d otherMin,
 95        Vector3d otherMax)
 96    {
 597        Signed192 volume = GetIntervalVolume(min, max);
 598        Vector3d unionMin = Vector3d.Min(min, otherMin);
 599        Vector3d unionMax = Vector3d.Max(max, otherMax);
 5100        Signed192 unionVolume = GetIntervalVolume(unionMin, unionMax);
 5101        Signed192 growth = WideArithmetic.SubtractSigned192(unionVolume, volume);
 102
 103        // Q32.32 axis spans produce a Q96.96 product. Shifting by 96 floors
 104        // the exact volume to integer world units. Any remaining bit above the
 105        // signed 63-bit result range maps to the public metric's upper bound.
 5106        if (growth.High > 0x0000_0000_7FFF_FFFFUL) // 2,147,483,647: highest 31-bit word that fits after the 96-bit shif
 1107            return long.MaxValue;
 108
 4109        ulong floor = (growth.High << 32) | (growth.Middle >> 32);
 4110        return (long)floor;
 111    }
 112
 113    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 114    private static Signed192 GetIntervalVolume(Vector3d min, Vector3d max)
 115    {
 10116        ulong x = unchecked((ulong)max.X.m_rawValue - (ulong)min.X.m_rawValue);
 10117        ulong y = unchecked((ulong)max.Y.m_rawValue - (ulong)min.Y.m_rawValue);
 10118        ulong z = unchecked((ulong)max.Z.m_rawValue - (ulong)min.Z.m_rawValue);
 10119        Fixed64.Multiply64To128(x, y, out ulong productHigh, out ulong productLow);
 10120        Fixed64.Multiply64To128(productLow, z, out ulong lowHigh, out ulong low);
 10121        Fixed64.Multiply64To128(productHigh, z, out ulong high, out ulong highLow);
 10122        return WideArithmetic.AddSigned192(
 10123            new Signed192(0UL, lowHigh, low),
 10124            new Signed192(high, highLow, 0UL));
 125    }
 126
 127    /// <summary>
 128    /// Compares an exact 2D distance with the exact sum of two non-negative radii.
 129    /// </summary>
 130    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 131    internal static int CompareDistanceToRadiusSum(
 132        Vector2d first,
 133        Vector2d second,
 134        Fixed64 firstRadius,
 135        Fixed64 secondRadius)
 136    {
 69137        Signed192 squaredDistance = GetDifferenceDotProduct2D(
 69138            first.X, second.X, first.Y, second.Y,
 69139            first.X, second.X, first.Y, second.Y);
 69140        return WideArithmetic.CompareMagnitude(
 69141            squaredDistance,
 69142            GetSquaredRadiusSum(firstRadius, secondRadius));
 143    }
 144
 145    /// <summary>
 146    /// Compares an exact 3D distance with the exact sum of two non-negative radii.
 147    /// </summary>
 148    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 149    internal static int CompareDistanceToRadiusSum(
 150        Vector3d first,
 151        Vector3d second,
 152        Fixed64 firstRadius,
 153        Fixed64 secondRadius)
 154    {
 428155        Signed192 squaredDistance = GetDifferenceDotProduct3D(
 428156            first.X, second.X, first.Y, second.Y, first.Z, second.Z,
 428157            first.X, second.X, first.Y, second.Y, first.Z, second.Z);
 428158        return WideArithmetic.CompareMagnitude(
 428159            squaredDistance,
 428160            GetSquaredRadiusSum(firstRadius, secondRadius));
 161    }
 162
 163    /// <summary>
 164    /// Returns whether an axis interval contains the centered extent of a non-negative radius.
 165    /// </summary>
 166    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 167    internal static bool ContainsCenteredExtent(
 168        Fixed64 min,
 169        Fixed64 max,
 170        Fixed64 center,
 171        Fixed64 radius)
 172    {
 16173        if (center < min || center > max)
 5174            return false;
 175
 11176        ulong radiusRaw = (ulong)radius.m_rawValue;
 11177        ulong minimumClearance = unchecked((ulong)center.m_rawValue - (ulong)min.m_rawValue);
 11178        ulong maximumClearance = unchecked((ulong)max.m_rawValue - (ulong)center.m_rawValue);
 11179        return minimumClearance >= radiusRaw && maximumClearance >= radiusRaw;
 180    }
 181
 182    /// <summary>
 183    /// Attempts to return the rounded distance between two 2D endpoints without
 184    /// narrowing their component differences.
 185    /// </summary>
 186    internal static bool TryGetDistance(Vector2d start, Vector2d end, out Fixed64 distance)
 187    {
 4188        Signed192 squaredDistance = GetDifferenceDotProduct2D(
 4189            end.X, start.X, end.Y, start.Y,
 4190            end.X, start.X, end.Y, start.Y);
 4191        return TryRoundDistance(squaredDistance, out distance);
 192    }
 193
 194    /// <summary>
 195    /// Attempts to return the rounded distance between two 3D endpoints without
 196    /// narrowing their component differences.
 197    /// </summary>
 198    internal static bool TryGetDistance(Vector3d start, Vector3d end, out Fixed64 distance)
 199    {
 24200        Signed192 squaredDistance = GetDifferenceDotProduct3D(
 24201            end.X, start.X, end.Y, start.Y, end.Z, start.Z,
 24202            end.X, start.X, end.Y, start.Y, end.Z, start.Z);
 24203        return TryRoundDistance(squaredDistance, out distance);
 204    }
 205
 206    /// <summary>
 207    /// Interpolates one coordinate from an exact nonnegative numerator and
 208    /// denominator with one final round-half-to-even conversion.
 209    /// </summary>
 210    internal static Fixed64 InterpolateCoordinate(
 211        Fixed64 start,
 212        Fixed64 end,
 213        Signed192 numerator,
 214        Signed192 denominator)
 215    {
 461216        if (start == end)
 105217            return start;
 218
 356219        Signed192 remaining = WideArithmetic.SubtractSigned192(denominator, numerator);
 356220        Signed320 weighted = WideArithmetic.AddSigned320(
 356221            WideArithmetic.MultiplySigned192(
 356222                Signed192.Signed(start.m_rawValue),
 356223                remaining),
 356224            WideArithmetic.MultiplySigned192(
 356225                Signed192.Signed(end.m_rawValue),
 356226                numerator));
 356227        return Fixed64.GetSignedRawRatio(weighted, denominator);
 228    }
 229
 230    private static bool TryRoundDistance(Signed192 squaredDistance, out Fixed64 distance)
 231    {
 28232        Signed192 root = WideArithmetic.GetFloorSquareRoot(
 28233            Signed320.ExtendValue(squaredDistance),
 28234            out Signed192 remainder);
 28235        WideArithmetic.GetMagnitude(root, out ulong high, out ulong middle, out ulong low);
 236        // A 2D/3D Fixed64 endpoint difference cannot produce a distance root
 237        // beyond the middle word; only its representable low-word limit varies.
 28238        if (middle != 0UL || low > (ulong)long.MaxValue)
 239        {
 3240            distance = Fixed64.MaxValue;
 3241            return false;
 242        }
 243
 244        // For integer n = root^2 + remainder, sqrt(n) rounds upward exactly
 245        // when remainder is at least root + 1. A half-way tie is impossible.
 25246        if (WideArithmetic.CompareMagnitude(remainder, root) > 0)
 247        {
 11248            if (low == (ulong)long.MaxValue)
 249            {
 1250                distance = Fixed64.MaxValue;
 1251                return false;
 252            }
 253
 10254            low++;
 255        }
 256
 24257        distance = Fixed64.FromRaw((long)low);
 24258        return true;
 259    }
 260
 261    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 262    private static Signed192 GetSquaredRadiusSum(Fixed64 firstRadius, Fixed64 secondRadius)
 263    {
 497264        ulong radiusSum = unchecked((ulong)firstRadius.m_rawValue + (ulong)secondRadius.m_rawValue);
 497265        Fixed64.Multiply64To128(radiusSum, radiusSum, out ulong middle, out ulong low);
 497266        return new Signed192(0UL, middle, low);
 267    }
 268
 269    /// <summary>
 270    /// Returns the exact dot product of two two-dimensional endpoint differences.
 271    /// </summary>
 272    internal static Signed192 GetDifferenceDotProduct2D(
 273        Fixed64 leftEndX,
 274        Fixed64 leftStartX,
 275        Fixed64 leftEndY,
 276        Fixed64 leftStartY,
 277        Fixed64 rightEndX,
 278        Fixed64 rightStartX,
 279        Fixed64 rightEndY,
 280        Fixed64 rightStartY)
 281    {
 258341282        ulong high = 0UL;
 258341283        ulong middle = 0UL;
 258341284        ulong low = 0UL;
 258341285        AccumulateDifferenceProduct(
 258341286            leftEndX.m_rawValue,
 258341287            leftStartX.m_rawValue,
 258341288            rightEndX.m_rawValue,
 258341289            rightStartX.m_rawValue,
 258341290            ref high,
 258341291            ref middle,
 258341292            ref low);
 258341293        AccumulateDifferenceProduct(
 258341294            leftEndY.m_rawValue,
 258341295            leftStartY.m_rawValue,
 258341296            rightEndY.m_rawValue,
 258341297            rightStartY.m_rawValue,
 258341298            ref high,
 258341299            ref middle,
 258341300            ref low);
 258341301        return new Signed192(high, middle, low);
 302    }
 303
 304    /// <summary>
 305    /// Returns the exact dot product of two three-dimensional endpoint differences.
 306    /// </summary>
 307    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 308    internal static Signed192 GetDifferenceDotProduct3D(
 309        Fixed64 leftEndX,
 310        Fixed64 leftStartX,
 311        Fixed64 leftEndY,
 312        Fixed64 leftStartY,
 313        Fixed64 leftEndZ,
 314        Fixed64 leftStartZ,
 315        Fixed64 rightEndX,
 316        Fixed64 rightStartX,
 317        Fixed64 rightEndY,
 318        Fixed64 rightStartY,
 319        Fixed64 rightEndZ,
 320        Fixed64 rightStartZ)
 321    {
 45718322        if (TrySubtractRaw(leftEndX.m_rawValue, leftStartX.m_rawValue, out long leftX)
 45718323            && TrySubtractRaw(leftEndY.m_rawValue, leftStartY.m_rawValue, out long leftY)
 45718324            && TrySubtractRaw(leftEndZ.m_rawValue, leftStartZ.m_rawValue, out long leftZ)
 45718325            && TrySubtractRaw(rightEndX.m_rawValue, rightStartX.m_rawValue, out long rightX)
 45718326            && TrySubtractRaw(rightEndY.m_rawValue, rightStartY.m_rawValue, out long rightY)
 45718327            && TrySubtractRaw(rightEndZ.m_rawValue, rightStartZ.m_rawValue, out long rightZ))
 328        {
 45337329            ulong narrowHigh = 0UL;
 45337330            ulong narrowMiddle = 0UL;
 45337331            ulong narrowLow = 0UL;
 45337332            AccumulateRawProduct(leftX, rightX, false, ref narrowHigh, ref narrowMiddle, ref narrowLow);
 45337333            AccumulateRawProduct(leftY, rightY, false, ref narrowHigh, ref narrowMiddle, ref narrowLow);
 45337334            AccumulateRawProduct(leftZ, rightZ, false, ref narrowHigh, ref narrowMiddle, ref narrowLow);
 45337335            return new Signed192(narrowHigh, narrowMiddle, narrowLow);
 336        }
 337
 381338        ulong high = 0UL;
 381339        ulong middle = 0UL;
 381340        ulong low = 0UL;
 381341        AccumulateDifferenceProduct(
 381342            leftEndX.m_rawValue,
 381343            leftStartX.m_rawValue,
 381344            rightEndX.m_rawValue,
 381345            rightStartX.m_rawValue,
 381346            ref high,
 381347            ref middle,
 381348            ref low);
 381349        AccumulateDifferenceProduct(
 381350            leftEndY.m_rawValue,
 381351            leftStartY.m_rawValue,
 381352            rightEndY.m_rawValue,
 381353            rightStartY.m_rawValue,
 381354            ref high,
 381355            ref middle,
 381356            ref low);
 381357        AccumulateDifferenceProduct(
 381358            leftEndZ.m_rawValue,
 381359            leftStartZ.m_rawValue,
 381360            rightEndZ.m_rawValue,
 381361            rightStartZ.m_rawValue,
 381362            ref high,
 381363            ref middle,
 381364            ref low);
 381365        return new Signed192(high, middle, low);
 366    }
 367
 368    /// <summary>
 369    /// Returns whether an exact squared direction rounds to zero in Q32.32.
 370    /// </summary>
 371    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 372    internal static bool IsSquaredLengthDegenerate(Signed192 value) =>
 287373        value.High == 0UL
 287374        && value.Middle == 0UL
 287375        && value.Low <= (1UL << (FixedMath.SHIFT_AMOUNT_I - 1));
 376
 377    /// <summary>
 378    /// Returns the exact 2D cross product of two endpoint differences.
 379    /// </summary>
 380    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 381    internal static Signed192 GetDifferenceCrossProduct2D(
 382        Fixed64 leftEndX,
 383        Fixed64 leftStartX,
 384        Fixed64 leftEndY,
 385        Fixed64 leftStartY,
 386        Fixed64 rightEndX,
 387        Fixed64 rightStartX,
 388        Fixed64 rightEndY,
 389        Fixed64 rightStartY)
 390    {
 7270391        ulong high = 0UL;
 7270392        ulong middle = 0UL;
 7270393        ulong low = 0UL;
 7270394        AccumulateDifferenceProduct(
 7270395            leftEndX.m_rawValue,
 7270396            leftStartX.m_rawValue,
 7270397            rightEndY.m_rawValue,
 7270398            rightStartY.m_rawValue,
 7270399            ref high,
 7270400            ref middle,
 7270401            ref low);
 7270402        AccumulateDifferenceProduct(
 7270403            leftEndY.m_rawValue,
 7270404            leftStartY.m_rawValue,
 7270405            rightStartX.m_rawValue,
 7270406            rightEndX.m_rawValue,
 7270407            ref high,
 7270408            ref middle,
 7270409            ref low);
 7270410        return new Signed192(high, middle, low);
 411    }
 412
 413    /// <summary>
 414    /// Returns all three exact components of a 3D endpoint-difference cross product.
 415    /// </summary>
 416    internal static void GetDifferenceCrossProduct3D(
 417        Fixed64 leftEndX,
 418        Fixed64 leftStartX,
 419        Fixed64 leftEndY,
 420        Fixed64 leftStartY,
 421        Fixed64 leftEndZ,
 422        Fixed64 leftStartZ,
 423        Fixed64 rightEndX,
 424        Fixed64 rightStartX,
 425        Fixed64 rightEndY,
 426        Fixed64 rightStartY,
 427        Fixed64 rightEndZ,
 428        Fixed64 rightStartZ,
 429        out Signed192 x,
 430        out Signed192 y,
 431        out Signed192 z)
 432    {
 23084433        if (TrySubtractRaw(leftEndX.m_rawValue, leftStartX.m_rawValue, out long leftX)
 23084434            && TrySubtractRaw(leftEndY.m_rawValue, leftStartY.m_rawValue, out long leftY)
 23084435            && TrySubtractRaw(leftEndZ.m_rawValue, leftStartZ.m_rawValue, out long leftZ)
 23084436            && TrySubtractRaw(rightEndX.m_rawValue, rightStartX.m_rawValue, out long rightX)
 23084437            && TrySubtractRaw(rightEndY.m_rawValue, rightStartY.m_rawValue, out long rightY)
 23084438            && TrySubtractRaw(rightEndZ.m_rawValue, rightStartZ.m_rawValue, out long rightZ))
 439        {
 22984440            x = GetRawCrossComponent(leftY, leftZ, rightZ, rightY);
 22984441            y = GetRawCrossComponent(leftZ, leftX, rightX, rightZ);
 22984442            z = GetRawCrossComponent(leftX, leftY, rightY, rightX);
 22984443            return;
 444        }
 445
 100446        x = GetDifferenceCrossProduct2D(
 100447            leftEndY, leftStartY, leftEndZ, leftStartZ,
 100448            rightEndY, rightStartY, rightEndZ, rightStartZ);
 100449        y = GetDifferenceCrossProduct2D(
 100450            leftEndZ, leftStartZ, leftEndX, leftStartX,
 100451            rightEndZ, rightStartZ, rightEndX, rightStartX);
 100452        z = GetDifferenceCrossProduct2D(
 100453            leftEndX, leftStartX, leftEndY, leftStartY,
 100454            rightEndX, rightStartX, rightEndY, rightStartY);
 100455    }
 456
 457    /// <summary>
 458    /// Returns the exact nonnegative squared magnitude of three wide components.
 459    /// </summary>
 460    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 461    internal static Signed320 GetSquaredMagnitude(
 462        Signed192 x,
 463        Signed192 y,
 464        Signed192 z,
 465        out Signed320 xSquare,
 466        out Signed320 ySquare,
 467        out Signed320 zSquare)
 468    {
 23276469        xSquare = WideArithmetic.MultiplySigned192(x, x);
 23276470        ySquare = WideArithmetic.MultiplySigned192(y, y);
 23276471        zSquare = WideArithmetic.MultiplySigned192(z, z);
 23276472        return WideArithmetic.AddSigned320(WideArithmetic.AddSigned320(xSquare, ySquare), zSquare);
 473    }
 474
 475    /// <summary>
 476    /// Applies the inclusive public epsilon threshold to an exact Q128.128 magnitude.
 477    /// </summary>
 478    internal static bool IsQ128MagnitudeAtMostEpsilon(Signed320 value)
 479    {
 2457480        WideArithmetic.GetMagnitude(
 2457481            value,
 2457482            out ulong word4,
 2457483            out ulong word3,
 2457484            out ulong word2,
 2457485            out ulong word1,
 2457486            out ulong word0);
 2457487        ulong epsilonRaw = (ulong)Fixed64.Epsilon.m_rawValue;
 2457488        return WideArithmetic.CompareUnsigned(
 2457489            word4,
 2457490            word3,
 2457491            word2,
 2457492            word1,
 2457493            word0,
 2457494            0UL,
 2457495            0UL,
 2457496            epsilonRaw >> 32,
 2457497            epsilonRaw << 32,
 2457498            0UL) <= 0;
 499    }
 500
 501    /// <summary>
 502    /// Compares exact squared distances between two pairs of 3D points.
 503    /// </summary>
 504    internal static int CompareSquaredDistance3D(
 505        Fixed64 leftStartX,
 506        Fixed64 leftEndX,
 507        Fixed64 leftStartY,
 508        Fixed64 leftEndY,
 509        Fixed64 leftStartZ,
 510        Fixed64 leftEndZ,
 511        Fixed64 rightStartX,
 512        Fixed64 rightEndX,
 513        Fixed64 rightStartY,
 514        Fixed64 rightEndY,
 515        Fixed64 rightStartZ,
 516        Fixed64 rightEndZ)
 517    {
 104518        Signed192 left = GetDifferenceDotProduct3D(
 104519            leftStartX, leftEndX, leftStartY, leftEndY, leftStartZ, leftEndZ,
 104520            leftStartX, leftEndX, leftStartY, leftEndY, leftStartZ, leftEndZ);
 104521        Signed192 right = GetDifferenceDotProduct3D(
 104522            rightStartX, rightEndX, rightStartY, rightEndY, rightStartZ, rightEndZ,
 104523            rightStartX, rightEndX, rightStartY, rightEndY, rightStartZ, rightEndZ);
 104524        return WideArithmetic.CompareMagnitude(left, right);
 525    }
 526
 527    /// <summary>
 528    /// Returns the exact sign of the scalar triple product of three raw
 529    /// three-component vectors.
 530    /// </summary>
 531    internal static int GetTripleProductSign(
 532        Fixed64 firstX,
 533        Fixed64 firstY,
 534        Fixed64 firstZ,
 535        Fixed64 secondX,
 536        Fixed64 secondY,
 537        Fixed64 secondZ,
 538        Fixed64 thirdX,
 539        Fixed64 thirdY,
 540        Fixed64 thirdZ)
 541    {
 898542        Signed192 minorX = GetDifferenceCrossProduct2D(
 898543            secondY, Fixed64.Zero, secondZ, Fixed64.Zero,
 898544            thirdY, Fixed64.Zero, thirdZ, Fixed64.Zero);
 898545        Signed192 minorY = GetDifferenceCrossProduct2D(
 898546            secondZ, Fixed64.Zero, secondX, Fixed64.Zero,
 898547            thirdZ, Fixed64.Zero, thirdX, Fixed64.Zero);
 898548        Signed192 minorZ = GetDifferenceCrossProduct2D(
 898549            secondX, Fixed64.Zero, secondY, Fixed64.Zero,
 898550            thirdX, Fixed64.Zero, thirdY, Fixed64.Zero);
 898551        Signed320 tripleProduct = WideArithmetic.AddSigned320(
 898552            WideArithmetic.AddSigned320(
 898553                WideArithmetic.MultiplySigned192(Signed192.Signed(firstX.m_rawValue), minorX),
 898554                WideArithmetic.MultiplySigned192(Signed192.Signed(firstY.m_rawValue), minorY)),
 898555            WideArithmetic.MultiplySigned192(Signed192.Signed(firstZ.m_rawValue), minorZ));
 898556        return tripleProduct.Sign;
 557    }
 558
 559    /// <summary>
 560    /// Applies the public 3D segment near-parallel threshold to an exact Q128.128 determinant.
 561    /// </summary>
 562    internal static bool IsSegmentDeterminantNearParallel(Signed320 determinant)
 563    {
 61564        WideArithmetic.GetMagnitude(
 61565            determinant,
 61566            out ulong word4,
 61567            out ulong word3,
 61568            out ulong word2,
 61569            out ulong word1,
 61570            out ulong word0);
 61571        ulong epsilonRaw = (ulong)Fixed64.Epsilon.m_rawValue;
 61572        return WideArithmetic.CompareUnsigned(
 61573            word4,
 61574            word3,
 61575            word2,
 61576            word1,
 61577            word0,
 61578            0UL,
 61579            0UL,
 61580            epsilonRaw >> 32,
 61581            epsilonRaw << 32,
 61582            0UL) < 0;
 583    }
 584
 585    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 586    internal static void AccumulateDifferenceProduct(
 587        long candidate,
 588        long current,
 589        long directionEnd,
 590        long directionStart,
 591        ref ulong sumHigh,
 592        ref ulong sumMiddle,
 593        ref ulong sumLow)
 594    {
 534374595        if (candidate == current || directionEnd == directionStart)
 233315596            return;
 597
 301059598        bool negativeDifference = candidate < current;
 301059599        ulong differenceMagnitude = negativeDifference
 301059600            ? unchecked((ulong)current - (ulong)candidate)
 301059601            : unchecked((ulong)candidate - (ulong)current);
 301059602        bool negativeDirection = directionEnd < directionStart;
 301059603        ulong directionMagnitude = negativeDirection
 301059604            ? unchecked((ulong)directionStart - (ulong)directionEnd)
 301059605            : unchecked((ulong)directionEnd - (ulong)directionStart);
 301059606        bool negativeProduct = negativeDifference != negativeDirection;
 607
 301059608        Fixed64.Multiply64To128(
 301059609            differenceMagnitude,
 301059610            directionMagnitude,
 301059611            out ulong productMiddle,
 301059612            out ulong productLow);
 613
 301059614        ulong productHigh = 0UL;
 301059615        if (negativeProduct)
 616        {
 66993617            productLow = unchecked(~productLow + 1UL);
 66993618            productMiddle = unchecked(~productMiddle + (productLow == 0UL ? 1UL : 0UL));
 66993619            productHigh = ulong.MaxValue;
 620        }
 621
 301059622        ulong previousLow = sumLow;
 301059623        sumLow = unchecked(sumLow + productLow);
 301059624        ulong carry = sumLow < previousLow ? 1UL : 0UL;
 625
 301059626        ulong addMiddle = unchecked(productMiddle + carry);
 301059627        ulong carryHigh = addMiddle < productMiddle ? 1UL : 0UL;
 301059628        ulong previousMiddle = sumMiddle;
 301059629        sumMiddle = unchecked(sumMiddle + addMiddle);
 301059630        if (sumMiddle < previousMiddle)
 10729631            carryHigh = 1UL;
 632
 301059633        sumHigh = unchecked(sumHigh + productHigh + carryHigh);
 301059634    }
 635
 636    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 637    private static Signed192 GetRawCrossComponent(
 638        long leftFirst,
 639        long leftSecond,
 640        long rightFirst,
 641        long rightSecond)
 642    {
 68952643        ulong high = 0UL;
 68952644        ulong middle = 0UL;
 68952645        ulong low = 0UL;
 68952646        AccumulateRawProduct(leftFirst, rightFirst, false, ref high, ref middle, ref low);
 68952647        AccumulateRawProduct(leftSecond, rightSecond, true, ref high, ref middle, ref low);
 68952648        return new Signed192(high, middle, low);
 649    }
 650
 651    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 652    private static bool TrySubtractRaw(long end, long start, out long difference)
 653    {
 410719654        difference = unchecked(end - start);
 410719655        return ((end ^ start) & (end ^ difference)) >= 0L;
 656    }
 657
 658    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 659    private static void AccumulateRawProduct(
 660        long left,
 661        long right,
 662        bool subtract,
 663        ref ulong sumHigh,
 664        ref ulong sumMiddle,
 665        ref ulong sumLow)
 666    {
 273915667        if (left == 0L || right == 0L)
 181079668            return;
 669
 92836670        ulong leftMagnitude = left < 0L ? unchecked(0UL - (ulong)left) : (ulong)left;
 92836671        ulong rightMagnitude = right < 0L ? unchecked(0UL - (ulong)right) : (ulong)right;
 92836672        bool negativeProduct = (left < 0L) != (right < 0L) != subtract;
 92836673        Fixed64.Multiply64To128(leftMagnitude, rightMagnitude, out ulong productMiddle, out ulong productLow);
 674
 92836675        ulong productHigh = 0UL;
 92836676        if (negativeProduct)
 677        {
 31507678            productLow = unchecked(~productLow + 1UL);
 31507679            productMiddle = unchecked(~productMiddle + (productLow == 0UL ? 1UL : 0UL));
 31507680            productHigh = ulong.MaxValue;
 681        }
 682
 92836683        ulong previousLow = sumLow;
 92836684        sumLow = unchecked(sumLow + productLow);
 92836685        ulong carry = sumLow < previousLow ? 1UL : 0UL;
 686
 92836687        ulong addMiddle = unchecked(productMiddle + carry);
 92836688        ulong carryHigh = addMiddle < productMiddle ? 1UL : 0UL;
 92836689        ulong previousMiddle = sumMiddle;
 92836690        sumMiddle = unchecked(sumMiddle + addMiddle);
 92836691        if (sumMiddle < previousMiddle)
 6063692            carryHigh = 1UL;
 693
 92836694        sumHigh = unchecked(sumHigh + productHigh + carryHigh);
 92836695    }
 696
 697    /// <summary>
 698    /// Returns the outward Q32.32 norm of componentwise products, retaining exact
 699    /// products until the final ceiling. Returns false for an unrepresentable norm.
 700    /// </summary>
 701    internal static bool TryGetScaledMagnitudeCeiling(
 702        Vector3d vector,
 703        Vector3d scale,
 704        out Fixed64 magnitude)
 705    {
 109706        magnitude = default;
 109707        Signed192 x = Fixed64.GetExactRawProduct(vector.X, scale.X);
 109708        Signed192 y = Fixed64.GetExactRawProduct(vector.Y, scale.Y);
 109709        Signed192 z = Fixed64.GetExactRawProduct(vector.Z, scale.Z);
 109710        Signed320 squared = GetSquaredMagnitude(x, y, z, out _, out _, out _);
 109711        Signed192 root = WideArithmetic.GetFloorSquareRoot(squared, out Signed192 remainder);
 712
 713        // Each Q64 product has magnitude <= 2^126, so the three squares sum to
 714        // less than 2^254 and root.High is zero. Divide the Q64 root by 2^32.
 109715        if ((root.Middle >> 31) != 0UL)
 46716            return false;
 717
 63718        ulong raw = (root.Middle << 32) | (root.Low >> 32);
 63719        if ((root.Low & uint.MaxValue) != 0UL || !remainder.IsZero)
 55720            raw++;
 63721        if (raw > long.MaxValue)
 1722            return false;
 723
 62724        magnitude = Fixed64.FromRaw((long)raw);
 62725        return true;
 726    }
 727
 728    /// <summary>Ceils the norm of exact integer coordinates divided by a positive divisor into raw Fixed64 units.</summ
 729    internal static bool TryGetMagnitudeCeiling(Signed192 x, Signed192 y, Signed192 z,
 730        Signed192 divisor, out Fixed64 magnitude)
 731    {
 13732        if (divisor.Sign <= 0) throw new ArgumentOutOfRangeException(nameof(divisor));
 733        // Three full 192-bit squares and their sum fit the existing 576-bit owner.
 9734        Signed576 squared = WideArithmetic.AddSigned576(WideArithmetic.AddSigned576(Square(x), Square(y)), Square(z));
 9735        Signed576 denominator = Square(divisor);
 18736        Span<ulong> numeratorWords = stackalloc ulong[9], denominatorWords = stackalloc ulong[9];
 18737        WideArithmetic.GetMagnitude(squared, numeratorWords); WideArithmetic.GetMagnitude(denominator, denominatorWords)
 9738        ulong floor = WideArithmetic.GetRatioFloorSquareRoot(numeratorWords, denominatorWords, long.MaxValue);
 9739        Signed576 threshold = WideArithmetic.MultiplySigned576(denominator, Signed192.Signed((long)floor));
 9740        threshold = WideArithmetic.MultiplySigned576(threshold, Signed192.Signed((long)floor));
 9741        int order = WideArithmetic.CompareNonNegative(squared, threshold);
 13742        if (order > 0 && floor == long.MaxValue) { magnitude = default; return false; }
 7743        magnitude = Fixed64.FromRaw((long)(floor + (order > 0 ? 1UL : 0UL)));
 7744        return true;
 745
 746        static Signed576 Square(Signed192 value) => WideArithmetic.MultiplySigned576(
 747            Signed576.ExtendValue(Signed320.ExtendValue(value)), value);
 748    }
 749
 750    internal static bool TryGetMagnitudeCeiling(
 751        Fixed64 x,
 752        Fixed64 y,
 753        Fixed64 z,
 754        out Fixed64 magnitude)
 755    {
 5756        Signed192 rawX = Signed192.Signed(x.m_rawValue);
 5757        Signed192 rawY = Signed192.Signed(y.m_rawValue);
 5758        Signed192 rawZ = Signed192.Signed(z.m_rawValue);
 5759        Signed320 squaredMagnitude = WideArithmetic.AddSigned320(
 5760            WideArithmetic.AddSigned320(
 5761                WideArithmetic.MultiplySigned192(rawX, rawX),
 5762                WideArithmetic.MultiplySigned192(rawY, rawY)),
 5763            WideArithmetic.MultiplySigned192(rawZ, rawZ));
 5764        Signed192 root = WideArithmetic.GetFloorSquareRoot(
 5765            squaredMagnitude,
 5766            out Signed192 remainder);
 5767        if (!remainder.IsZero)
 768        {
 3769            root = WideArithmetic.AddSigned192(
 3770                root,
 3771                Signed192.Signed(1L));
 772        }
 773
 5774        if ((root.High | root.Middle | (root.Low >> 63)) != 0UL)
 775        {
 1776            magnitude = default;
 1777            return false;
 778        }
 779
 4780        magnitude = Fixed64.FromRaw((long)root.Low);
 4781        return true;
 782    }
 783
 784    internal static FixedQuaternion GetCanonicalAxisRotation(
 785        Vector3d normalizedAxis)
 786    {
 28787        if (normalizedAxis == Vector3d.Up)
 2788            return FixedQuaternion.Identity;
 26789        if (normalizedAxis == Vector3d.Down)
 790        {
 2791            return FixedQuaternion.FromAxisAngle(
 2792                Vector3d.Right,
 2793                Fixed64.Pi);
 794        }
 795
 24796        return new FixedQuaternion(
 24797            normalizedAxis.Z,
 24798            Fixed64.Zero,
 24799            -normalizedAxis.X,
 24800            Fixed64.One + normalizedAxis.Y).Normalized;
 801    }
 802
 803    /// <summary>
 804    /// Returns one outward-rounded endpoint of a centered finite-axis extent,
 805    /// clipped to the representable scalar domain.
 806    /// </summary>
 807    internal static Fixed64 GetCenteredFiniteAxisBoundClippedToDomain(
 808        Fixed64 center,
 809        Fixed64 axisComponent,
 810        Fixed64 fullAxisLength,
 811        Fixed64 radialExtent,
 812        bool minimum)
 813    {
 1928814        Signed320 centerNumerator = WideArithmetic.MultiplySigned192(
 1928815            Signed192.Signed(center.m_rawValue),
 1928816            CenteredAxisDenominator);
 1928817        Signed320 extentNumerator = WideArithmetic.AddSigned320(
 1928818            WideArithmetic.MultiplySigned192(
 1928819                Signed192.Signed(axisComponent.Abs().m_rawValue),
 1928820                Signed192.Signed(fullAxisLength.m_rawValue)),
 1928821            WideArithmetic.MultiplySigned192(
 1928822                Signed192.Signed(radialExtent.m_rawValue),
 1928823                CenteredAxisDenominator));
 1928824        Signed320 numerator = minimum
 1928825            ? WideArithmetic.SubtractSigned320(centerNumerator, extentNumerator)
 1928826            : WideArithmetic.AddSigned320(centerNumerator, extentNumerator);
 827
 1928828        return GetRationalBoundClippedToDomain(
 1928829            numerator,
 1928830            CenteredAxisDenominator,
 1928831            minimum);
 832    }
 833
 834    /// <summary>
 835    /// Materializes a rational raw bound outwards, clipping at the scalar faces.
 836    /// Numerator magnitudes stay below 570 bits and nonzero denominator
 837    /// magnitudes below 510 bits, so scalar boundary products and signed
 838    /// differences fit the 576-bit owner.
 839    /// </summary>
 840    internal static Fixed64 GetRationalBoundClippedToDomain(
 841        Signed576 numerator,
 842        Signed576 denominator,
 843        bool minimum)
 844    {
 1104845        if (denominator.Sign < 0)
 846        {
 112847            numerator = WideArithmetic.SubtractSigned576(default, numerator);
 112848            denominator = WideArithmetic.SubtractSigned576(default, denominator);
 849        }
 1104850        Signed576 minimumNumerator = WideArithmetic.MultiplySigned576(denominator, Fixed64.MinValue.m_rawValue);
 1104851        Signed576 maximumNumerator = WideArithmetic.MultiplySigned576(denominator, Fixed64.MaxValue.m_rawValue);
 1104852        if (WideArithmetic.SubtractSigned576(numerator, minimumNumerator).Sign < 0)
 48853            return Fixed64.MinValue;
 1056854        if (WideArithmetic.SubtractSigned576(numerator, maximumNumerator).Sign > 0)
 48855            return Fixed64.MaxValue;
 1008856        _ = Fixed64.TryGetSignedRawRatio(numerator, denominator, out Fixed64 bound);
 1008857        Signed576 represented = WideArithmetic.MultiplySigned576(denominator, bound.m_rawValue);
 1008858        int comparison = WideArithmetic.SubtractSigned576(represented, numerator).Sign;
 1008859        if (minimum && comparison > 0)
 214860            return Fixed64.FromRaw(bound.m_rawValue - 1L);
 794861        if (!minimum && comparison < 0)
 194862            return Fixed64.FromRaw(bound.m_rawValue + 1L);
 600863        return bound;
 864    }
 865
 866    internal static Fixed64 GetRationalBoundClippedToDomain(
 867        Signed320 numerator,
 868        Signed192 denominator,
 869        bool minimum)
 870    {
 1960871        Signed320 minimumNumerator = WideArithmetic.MultiplySigned192(
 1960872            Signed192.Signed(Fixed64.MinValue.m_rawValue),
 1960873            denominator);
 1960874        Signed320 maximumNumerator = WideArithmetic.MultiplySigned192(
 1960875            Signed192.Signed(Fixed64.MaxValue.m_rawValue),
 1960876            denominator);
 877
 878        // Clip the exact endpoint before round-to-even so the subsequent
 879        // one-unit outward correction cannot cross the scalar domain.
 1960880        if (WideArithmetic.SubtractSigned320(
 1960881                numerator,
 1960882                minimumNumerator).Sign < 0)
 883        {
 8884            return Fixed64.MinValue;
 885        }
 1952886        if (WideArithmetic.SubtractSigned320(
 1952887                numerator,
 1952888                maximumNumerator).Sign > 0)
 889        {
 10890            return Fixed64.MaxValue;
 891        }
 892
 1942893        Fixed64 bound = Fixed64.GetSignedRawRatio(
 1942894            numerator,
 1942895            denominator);
 1942896        Signed320 represented = WideArithmetic.MultiplySigned192(
 1942897            Signed192.Signed(bound.m_rawValue),
 1942898            denominator);
 1942899        int comparison = WideArithmetic.SubtractSigned320(represented, numerator).Sign;
 1942900        if (minimum && comparison > 0)
 8901            return Fixed64.FromRaw(bound.m_rawValue - 1L);
 1934902        if (!minimum && comparison < 0)
 9903            return Fixed64.FromRaw(bound.m_rawValue + 1L);
 1925904        return bound;
 905    }
 906}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WideGeometry.Projection.cs

#LineLine coverage
 1//=======================================================================
 2// WideGeometry.Projection.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
 8namespace FixedMathSharp.Geometry;
 9
 10/// <content>
 11/// Wide-precision projection helpers: exact difference projections, dot-product based
 12/// projection parameters, and plane projections computed without narrowing intermediate results.
 13/// </content>
 14internal static partial class WideGeometry
 15{
 16    /// <summary>
 17    /// Compares the exact projection of three component differences.
 18    /// </summary>
 19    internal static int CompareDifferenceProjection(
 20        Fixed64 candidateX,
 21        Fixed64 currentX,
 22        Fixed64 directionX,
 23        Fixed64 candidateY,
 24        Fixed64 currentY,
 25        Fixed64 directionY,
 26        Fixed64 candidateZ,
 27        Fixed64 currentZ,
 28        Fixed64 directionZ)
 29    {
 1130        GetDifferenceProjectionWords(
 1131            candidateX,
 1132            currentX,
 1133            directionX,
 1134            candidateY,
 1135            currentY,
 1136            directionY,
 1137            candidateZ,
 1138            currentZ,
 1139            directionZ,
 1140            out ulong sumHigh,
 1141            out ulong sumMiddle,
 1142            out ulong sumLow);
 43
 1144        if ((sumHigh & (1UL << 63)) != 0UL)
 445            return -1;
 46
 747        return (sumHigh | sumMiddle | sumLow) == 0UL ? 0 : 1;
 48    }
 49
 50    /// <summary>
 51    /// Returns the exact projection words of three component differences.
 52    /// </summary>
 53    internal static void GetDifferenceProjectionWords(
 54        Fixed64 candidateX,
 55        Fixed64 currentX,
 56        Fixed64 directionX,
 57        Fixed64 candidateY,
 58        Fixed64 currentY,
 59        Fixed64 directionY,
 60        Fixed64 candidateZ,
 61        Fixed64 currentZ,
 62        Fixed64 directionZ,
 63        out ulong sumHigh,
 64        out ulong sumMiddle,
 65        out ulong sumLow)
 66    {
 1967        sumHigh = 0UL;
 1968        sumMiddle = 0UL;
 1969        sumLow = 0UL;
 1970        AccumulateDifferenceProduct(
 1971            candidateX.m_rawValue,
 1972            currentX.m_rawValue,
 1973            directionX.m_rawValue,
 1974            0L,
 1975            ref sumHigh,
 1976            ref sumMiddle,
 1977            ref sumLow);
 1978        AccumulateDifferenceProduct(
 1979            candidateY.m_rawValue,
 1980            currentY.m_rawValue,
 1981            directionY.m_rawValue,
 1982            0L,
 1983            ref sumHigh,
 1984            ref sumMiddle,
 1985            ref sumLow);
 1986        AccumulateDifferenceProduct(
 1987            candidateZ.m_rawValue,
 1988            currentZ.m_rawValue,
 1989            directionZ.m_rawValue,
 1990            0L,
 1991            ref sumHigh,
 1992            ref sumMiddle,
 1993            ref sumLow);
 1994    }
 95
 96    /// <summary>
 97    /// Returns max(0, dot(target - source, direction) / dot(direction, direction))
 98    /// without narrowing either dot product first.
 99    /// </summary>
 100    internal static Fixed64 GetNonNegativeDifferenceProjectionParameter(
 101        Vector3d target,
 102        Vector3d source,
 103        Vector3d direction)
 104    {
 90105        Signed192 numerator = GetDifferenceDotProduct3D(
 90106            target.X, source.X,
 90107            target.Y, source.Y,
 90108            target.Z, source.Z,
 90109            direction.X, Fixed64.Zero,
 90110            direction.Y, Fixed64.Zero,
 90111            direction.Z, Fixed64.Zero);
 90112        if (numerator.Sign <= 0)
 2113            return Fixed64.Zero;
 114
 88115        Signed192 denominator = GetDifferenceDotProduct3D(
 88116            direction.X, Fixed64.Zero,
 88117            direction.Y, Fixed64.Zero,
 88118            direction.Z, Fixed64.Zero,
 88119            direction.X, Fixed64.Zero,
 88120            direction.Y, Fixed64.Zero,
 88121            direction.Z, Fixed64.Zero);
 88122        return Fixed64.GetSignedRatio(numerator, denominator);
 123    }
 124
 125    /// <summary>
 126    /// Returns normalize(q * vector - normal * dot(vector, normal)), where
 127    /// q is the exact squared length of the normal.
 128    /// </summary>
 129    internal static Vector3d GetNormalizedProjectionOnPlane(
 130        Vector3d vector,
 131        Vector3d normal)
 132    {
 5133        Signed192 q = GetDifferenceDotProduct3D(
 5134            normal.X, Fixed64.Zero,
 5135            normal.Y, Fixed64.Zero,
 5136            normal.Z, Fixed64.Zero,
 5137            normal.X, Fixed64.Zero,
 5138            normal.Y, Fixed64.Zero,
 5139            normal.Z, Fixed64.Zero);
 5140        if (q.Sign == 0)
 1141            return WideNormalization.GetNormalized(vector);
 142
 4143        Signed192 projection = GetDifferenceDotProduct3D(
 4144            vector.X, Fixed64.Zero,
 4145            vector.Y, Fixed64.Zero,
 4146            vector.Z, Fixed64.Zero,
 4147            normal.X, Fixed64.Zero,
 4148            normal.Y, Fixed64.Zero,
 4149            normal.Z, Fixed64.Zero);
 4150        Signed192 x = Signed192.Signed(vector.X.m_rawValue);
 4151        Signed192 y = Signed192.Signed(vector.Y.m_rawValue);
 4152        Signed192 z = Signed192.Signed(vector.Z.m_rawValue);
 4153        Signed192 nx = Signed192.Signed(normal.X.m_rawValue);
 4154        Signed192 ny = Signed192.Signed(normal.Y.m_rawValue);
 4155        Signed192 nz = Signed192.Signed(normal.Z.m_rawValue);
 4156        return WideNormalization.GetNormalized(
 4157            WideArithmetic.SubtractSigned320(
 4158                WideArithmetic.MultiplySigned192(q, x),
 4159                WideArithmetic.MultiplySigned192(nx, projection)),
 4160            WideArithmetic.SubtractSigned320(
 4161                WideArithmetic.MultiplySigned192(q, y),
 4162                WideArithmetic.MultiplySigned192(ny, projection)),
 4163            WideArithmetic.SubtractSigned320(
 4164                WideArithmetic.MultiplySigned192(q, z),
 4165                WideArithmetic.MultiplySigned192(nz, projection)));
 166    }
 167}

Methods/Properties

GetCenteredCapsuleSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d)
GetCenteredCapsuleSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d)
GetCenteredCapsuleSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,System.Int32)
GetCenteredCylinderSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d)
GetCenteredCylinderSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,System.Boolean)
GetCenteredCylinderSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d)
GetCenteredCylinderSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,System.Int32)
GetCenteredConeSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d)
GetCenteredAxisSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideGeometry/CenteredAxisSupportKind,System.Nullable`1<System.Int32>)
.cctor()
GetIntervalSize(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetIntervalScope(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetExtentMagnitude(FixedMathSharp.Fixed64)
GetHalfSizeMagnitude(FixedMathSharp.Fixed64)
GetVolumeExpansionCost(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetIntervalVolume(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
CompareDistanceToRadiusSum(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CompareDistanceToRadiusSum(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
ContainsCenteredExtent(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TryGetDistance(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64&)
TryGetDistance(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64&)
InterpolateCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
TryRoundDistance(FixedMathSharp.Signed192,FixedMathSharp.Fixed64&)
GetSquaredRadiusSum(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetDifferenceDotProduct2D(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetDifferenceDotProduct3D(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
IsSquaredLengthDegenerate(FixedMathSharp.Signed192)
GetDifferenceCrossProduct2D(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetDifferenceCrossProduct3D(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetSquaredMagnitude(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
IsQ128MagnitudeAtMostEpsilon(FixedMathSharp.Signed320)
CompareSquaredDistance3D(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetTripleProductSign(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
IsSegmentDeterminantNearParallel(FixedMathSharp.Signed320)
AccumulateDifferenceProduct(System.Int64,System.Int64,System.Int64,System.Int64,System.UInt64&,System.UInt64&,System.UInt64&)
GetRawCrossComponent(System.Int64,System.Int64,System.Int64,System.Int64)
TrySubtractRaw(System.Int64,System.Int64,System.Int64&)
AccumulateRawProduct(System.Int64,System.Int64,System.Boolean,System.UInt64&,System.UInt64&,System.UInt64&)
TryGetScaledMagnitudeCeiling(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64&)
TryGetMagnitudeCeiling(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64&)
TryGetMagnitudeCeiling(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
GetCanonicalAxisRotation(FixedMathSharp.Vector3d)
GetCenteredFiniteAxisBoundClippedToDomain(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean)
GetRationalBoundClippedToDomain(FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Boolean)
GetRationalBoundClippedToDomain(FixedMathSharp.Signed320,FixedMathSharp.Signed192,System.Boolean)
CompareDifferenceProjection(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetDifferenceProjectionWords(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.UInt64&,System.UInt64&,System.UInt64&)
GetNonNegativeDifferenceProjectionParameter(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetNormalizedProjectionOnPlane(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)