< Summary

Line coverage
100%
Covered lines: 621
Uncovered lines: 0
Coverable lines: 621
Total lines: 1229
Line coverage: 100%
Branch coverage
100%
Covered branches: 126
Total branches: 126
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%11100%
File 1: GetCenteredCylinderSupportAnchor(...)100%11100%
File 1: GetCenteredConeSupportAnchor(...)100%11100%
File 1: GetCenteredConeSupportAnchor(...)100%11100%
File 1: GetCenteredAxisSupportAnchor(...)100%2020100%
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: TryGetMagnitudeCeiling(...)100%44100%
File 2: GetCanonicalAxisRotation(...)100%44100%
File 2: GetCenteredFiniteAxisBoundClippedToDomain(...)100%22100%
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) =>
 40137        GetCenteredAxisSupportAnchor(
 40138            center,
 40139            rotation,
 40140            localAxis,
 40141            axisLength,
 40142            radius,
 40143            worldDirection,
 40144            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) =>
 5554        GetCenteredAxisSupportAnchor(
 5555            center,
 5556            rotation,
 5557            localAxis,
 5558            axisLength,
 5559            radius,
 5560            worldDirection,
 5561            CenteredAxisSupportKind.Capsule,
 5562            axialSign);
 63
 64    internal static FixedPointAnchor GetCenteredCylinderSupportAnchor(
 65        Vector3d center,
 66        FixedQuaternion canonicalAxisRotation,
 67        Fixed64 axisLength,
 68        Fixed64 radius,
 69        Vector3d worldDirection) =>
 1070        GetCenteredAxisSupportAnchor(
 1071            center,
 1072            canonicalAxisRotation,
 1073            Vector3d.Up,
 1074            axisLength,
 1075            radius,
 1076            worldDirection,
 1077            CenteredAxisSupportKind.Cylinder);
 78
 79    internal static FixedPointAnchor GetCenteredCylinderSupportAnchor(
 80        Vector3d center,
 81        FixedQuaternion rotation,
 82        Vector3d localAxis,
 83        Fixed64 axisLength,
 84        Fixed64 radius,
 85        Vector3d worldDirection) =>
 225486        GetCenteredAxisSupportAnchor(
 225487            center,
 225488            rotation,
 225489            localAxis,
 225490            axisLength,
 225491            radius,
 225492            worldDirection,
 225493            CenteredAxisSupportKind.Cylinder);
 94
 95    internal static FixedPointAnchor GetCenteredCylinderSupportAnchor(
 96        Vector3d center,
 97        FixedQuaternion rotation,
 98        Vector3d localAxis,
 99        Fixed64 axisLength,
 100        Fixed64 radius,
 101        Vector3d worldDirection,
 102        int axialSign) =>
 2032103        GetCenteredAxisSupportAnchor(
 2032104            center,
 2032105            rotation,
 2032106            localAxis,
 2032107            axisLength,
 2032108            radius,
 2032109            worldDirection,
 2032110            CenteredAxisSupportKind.Cylinder,
 2032111            axialSign);
 112
 113    internal static FixedPointAnchor GetCenteredConeSupportAnchor(
 114        Vector3d center,
 115        FixedQuaternion canonicalAxisRotation,
 116        Fixed64 height,
 117        Fixed64 radius,
 118        Vector3d worldDirection) =>
 8119        GetCenteredAxisSupportAnchor(
 8120            center,
 8121            canonicalAxisRotation,
 8122            Vector3d.Up,
 8123            height,
 8124            radius,
 8125            worldDirection,
 8126            CenteredAxisSupportKind.Cone);
 127
 128    internal static FixedPointAnchor GetCenteredConeSupportAnchor(
 129        Vector3d center,
 130        FixedQuaternion rotation,
 131        Vector3d localAxis,
 132        Fixed64 height,
 133        Fixed64 radius,
 134        Vector3d worldDirection,
 135        bool apexSupport) =>
 6136        GetCenteredAxisSupportAnchor(
 6137            center,
 6138            rotation,
 6139            localAxis,
 6140            height,
 6141            radius,
 6142            worldDirection,
 6143            CenteredAxisSupportKind.Cone,
 6144            forcedConeApex: apexSupport);
 145
 146    private static FixedPointAnchor GetCenteredAxisSupportAnchor(
 147        Vector3d center,
 148        FixedQuaternion canonicalAxisRotation,
 149        Vector3d localAxis,
 150        Fixed64 axisLength,
 151        Fixed64 radius,
 152        Vector3d worldDirection,
 153        CenteredAxisSupportKind kind,
 154        int? forcedAxialSign = null,
 155        bool? forcedConeApex = null)
 156    {
 4772157        Vector3d localDirection = WideNormalization.GetNormalized(
 4772158            canonicalAxisRotation.Inverse().Rotate(worldDirection));
 4772159        Fixed64 halfLength = axisLength / Fixed64.Two;
 4772160        int axialSign = forcedAxialSign
 4772161            ?? WideOrientedBox.GetRotatedLocalProjectionSign(
 4772162                canonicalAxisRotation,
 4772163                localAxis,
 4772164                worldDirection);
 4772165        bool positiveAxis = axialSign > 0;
 4772166        Vector3d localPoint =
 4772167            localAxis * (positiveAxis ? halfLength : -halfLength);
 4772168        Fixed64 signedAxisLength = positiveAxis
 4772169            ? axisLength
 4772170            : -axisLength;
 171        Vector3d localDisplacement;
 172        Vector3d localRadialDirection;
 4772173        if (kind == CenteredAxisSupportKind.Capsule)
 174        {
 462175            if (axialSign == 0)
 176            {
 190177                localPoint = Vector3d.Zero;
 190178                signedAxisLength = Fixed64.Zero;
 179            }
 462180            localRadialDirection = localDirection;
 462181            localDisplacement = localDirection * radius;
 182        }
 183        else
 184        {
 4310185            if (kind == CenteredAxisSupportKind.Cylinder)
 186            {
 4296187                Fixed64 axialProjection =
 4296188                    Vector3d.Dot(localDirection, localAxis);
 4296189                localRadialDirection = WideNormalization.GetNormalized(
 4296190                    localDirection - (localAxis * axialProjection));
 191            }
 192            else
 193            {
 14194                Vector2d planarDirection = WideNormalization.GetNormalized(
 14195                    new Vector2d(localDirection.X, localDirection.Z));
 14196                if (planarDirection == Vector2d.Zero)
 3197                    planarDirection = Vector2d.Right;
 14198                localRadialDirection = new Vector3d(
 14199                    planarDirection.X,
 14200                    Fixed64.Zero,
 14201                    planarDirection.Y);
 202            }
 4310203            localDisplacement = localRadialDirection * radius;
 4310204            bool coneApex = forcedConeApex
 4310205                ?? WideFiniteAxisIntersection
 4310206                    .IsCenteredFiniteConeApexSupport(
 4310207                        Vector3d.Up,
 4310208                        axisLength,
 4310209                        radius,
 4310210                        localDirection);
 4310211            if (kind == CenteredAxisSupportKind.Cone
 4310212                && coneApex)
 213            {
 2214                signedAxisLength = axisLength;
 2215                localRadialDirection = Vector3d.Zero;
 2216                localDisplacement = Vector3d.Zero;
 217            }
 4308218            else if (kind == CenteredAxisSupportKind.Cone)
 219            {
 12220                signedAxisLength = -axisLength;
 12221                localPoint = new Vector3d(
 12222                    Fixed64.Zero,
 12223                    -halfLength,
 12224                    Fixed64.Zero);
 225            }
 226        }
 227
 4772228        FixedPointAnchorTerm3d exactLocalTerm =
 4772229            FixedPointAnchorTerm3d.CreateCenteredAxisSupport(
 4772230                localAxis,
 4772231                signedAxisLength,
 4772232                localRadialDirection,
 4772233                radius,
 4772234                localPoint,
 4772235                localDisplacement);
 4772236        return new FixedPointAnchor(
 4772237            center,
 4772238            canonicalAxisRotation,
 4772239            localPoint,
 4772240            localDisplacement,
 4772241            exactLocalTerm);
 242    }
 243}

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

#LineLine coverage
 1//=======================================================================
 2// WideGeometry.AxisFrame.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
 10namespace FixedMathSharp.Geometry;
 11
 12/// <summary>
 13/// Provides shared helper methods for computing support points, anchors, and axis-aligned
 14/// transformations used by GJK/EPA-based wide (batched) collision detection routines.
 15/// </summary>
 16internal static partial class WideGeometry
 17{
 118    internal static readonly Signed192 CenteredAxisDenominator =
 119        Signed192.Signed(FixedMath.ONE_L * 2L);
 20
 21    #region Nested Types
 22
 23    private enum CenteredAxisSupportKind
 24    {
 25        Capsule,
 26        Cylinder,
 27        Cone,
 28    }
 29
 30    #endregion
 31
 32    /// <summary>
 33    /// Returns the exact representable size of a normalized scalar interval.
 34    /// </summary>
 35    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 36    internal static Fixed64 GetIntervalSize(Fixed64 min, Fixed64 max)
 37    {
 6638        ulong span = unchecked((ulong)max.m_rawValue - (ulong)min.m_rawValue);
 6639        if (span > long.MaxValue)
 440            throw new System.OverflowException("The interval size is outside the representable Fixed64 range.");
 41
 6242        return Fixed64.FromRaw((long)span);
 43    }
 44
 45    /// <summary>
 46    /// Returns the smallest representable half-extent that contains both ends
 47    /// of a normalized scalar interval around its lattice midpoint.
 48    /// </summary>
 49    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 50    internal static Fixed64 GetIntervalScope(Fixed64 min, Fixed64 max)
 51    {
 5052        ulong span = unchecked((ulong)max.m_rawValue - (ulong)min.m_rawValue);
 5053        ulong scope = (span >> 1) + (span & 1UL);
 5054        if (scope > long.MaxValue)
 255            throw new System.OverflowException("The interval scope is outside the representable Fixed64 range.");
 56
 4857        return Fixed64.FromRaw((long)scope);
 58    }
 59
 60    /// <summary>
 61    /// Returns the representable absolute magnitude of a scalar extent.
 62    /// </summary>
 63    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 64    internal static Fixed64 GetExtentMagnitude(Fixed64 extent)
 65    {
 4766        if (extent == Fixed64.MinValue)
 267            throw new System.OverflowException("The extent magnitude is outside the representable Fixed64 range.");
 68
 4569        return extent.Abs();
 70    }
 71
 72    /// <summary>
 73    /// Returns the smallest scalar half-extent whose symmetric interval covers
 74    /// the requested size magnitude, including the minimum scalar input.
 75    /// </summary>
 76    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 77    internal static Fixed64 GetHalfSizeMagnitude(Fixed64 size)
 78    {
 44179        ulong magnitude = size.m_rawValue < 0L
 44180            ? unchecked(0UL - (ulong)size.m_rawValue)
 44181            : (ulong)size.m_rawValue;
 44182        ulong half = (magnitude >> 1) + (magnitude & 1UL);
 44183        return Fixed64.FromRaw((long)half);
 84    }
 85
 86    /// <summary>
 87    /// Returns an exact full-domain AABB union-volume growth metric.
 88    /// </summary>
 89    internal static long GetVolumeExpansionCost(
 90        Vector3d min,
 91        Vector3d max,
 92        Vector3d otherMin,
 93        Vector3d otherMax)
 94    {
 595        Signed192 volume = GetIntervalVolume(min, max);
 596        Vector3d unionMin = Vector3d.Min(min, otherMin);
 597        Vector3d unionMax = Vector3d.Max(max, otherMax);
 598        Signed192 unionVolume = GetIntervalVolume(unionMin, unionMax);
 599        Signed192 growth = WideArithmetic.SubtractSigned192(unionVolume, volume);
 100
 101        // Q32.32 axis spans produce a Q96.96 product. Shifting by 96 floors
 102        // the exact volume to integer world units. Any remaining bit above the
 103        // signed 63-bit result range maps to the public metric's upper bound.
 5104        if (growth.High > 0x0000_0000_7FFF_FFFFUL) // 2,147,483,647: highest 31-bit word that fits after the 96-bit shif
 1105            return long.MaxValue;
 106
 4107        ulong floor = (growth.High << 32) | (growth.Middle >> 32);
 4108        return (long)floor;
 109    }
 110
 111    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 112    private static Signed192 GetIntervalVolume(Vector3d min, Vector3d max)
 113    {
 10114        ulong x = unchecked((ulong)max.X.m_rawValue - (ulong)min.X.m_rawValue);
 10115        ulong y = unchecked((ulong)max.Y.m_rawValue - (ulong)min.Y.m_rawValue);
 10116        ulong z = unchecked((ulong)max.Z.m_rawValue - (ulong)min.Z.m_rawValue);
 10117        Fixed64.Multiply64To128(x, y, out ulong productHigh, out ulong productLow);
 10118        Fixed64.Multiply64To128(productLow, z, out ulong lowHigh, out ulong low);
 10119        Fixed64.Multiply64To128(productHigh, z, out ulong high, out ulong highLow);
 10120        return WideArithmetic.AddSigned192(
 10121            new Signed192(0UL, lowHigh, low),
 10122            new Signed192(high, highLow, 0UL));
 123    }
 124
 125    /// <summary>
 126    /// Compares an exact 2D distance with the exact sum of two non-negative radii.
 127    /// </summary>
 128    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 129    internal static int CompareDistanceToRadiusSum(
 130        Vector2d first,
 131        Vector2d second,
 132        Fixed64 firstRadius,
 133        Fixed64 secondRadius)
 134    {
 69135        Signed192 squaredDistance = GetDifferenceDotProduct2D(
 69136            first.X, second.X, first.Y, second.Y,
 69137            first.X, second.X, first.Y, second.Y);
 69138        return WideArithmetic.CompareMagnitude(
 69139            squaredDistance,
 69140            GetSquaredRadiusSum(firstRadius, secondRadius));
 141    }
 142
 143    /// <summary>
 144    /// Compares an exact 3D distance with the exact sum of two non-negative radii.
 145    /// </summary>
 146    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 147    internal static int CompareDistanceToRadiusSum(
 148        Vector3d first,
 149        Vector3d second,
 150        Fixed64 firstRadius,
 151        Fixed64 secondRadius)
 152    {
 390153        Signed192 squaredDistance = GetDifferenceDotProduct3D(
 390154            first.X, second.X, first.Y, second.Y, first.Z, second.Z,
 390155            first.X, second.X, first.Y, second.Y, first.Z, second.Z);
 390156        return WideArithmetic.CompareMagnitude(
 390157            squaredDistance,
 390158            GetSquaredRadiusSum(firstRadius, secondRadius));
 159    }
 160
 161    /// <summary>
 162    /// Returns whether an axis interval contains the centered extent of a non-negative radius.
 163    /// </summary>
 164    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 165    internal static bool ContainsCenteredExtent(
 166        Fixed64 min,
 167        Fixed64 max,
 168        Fixed64 center,
 169        Fixed64 radius)
 170    {
 16171        if (center < min || center > max)
 5172            return false;
 173
 11174        ulong radiusRaw = (ulong)radius.m_rawValue;
 11175        ulong minimumClearance = unchecked((ulong)center.m_rawValue - (ulong)min.m_rawValue);
 11176        ulong maximumClearance = unchecked((ulong)max.m_rawValue - (ulong)center.m_rawValue);
 11177        return minimumClearance >= radiusRaw && maximumClearance >= radiusRaw;
 178    }
 179
 180    /// <summary>
 181    /// Attempts to return the rounded distance between two 2D endpoints without
 182    /// narrowing their component differences.
 183    /// </summary>
 184    internal static bool TryGetDistance(Vector2d start, Vector2d end, out Fixed64 distance)
 185    {
 4186        Signed192 squaredDistance = GetDifferenceDotProduct2D(
 4187            end.X, start.X, end.Y, start.Y,
 4188            end.X, start.X, end.Y, start.Y);
 4189        return TryRoundDistance(squaredDistance, out distance);
 190    }
 191
 192    /// <summary>
 193    /// Attempts to return the rounded distance between two 3D endpoints without
 194    /// narrowing their component differences.
 195    /// </summary>
 196    internal static bool TryGetDistance(Vector3d start, Vector3d end, out Fixed64 distance)
 197    {
 24198        Signed192 squaredDistance = GetDifferenceDotProduct3D(
 24199            end.X, start.X, end.Y, start.Y, end.Z, start.Z,
 24200            end.X, start.X, end.Y, start.Y, end.Z, start.Z);
 24201        return TryRoundDistance(squaredDistance, out distance);
 202    }
 203
 204    /// <summary>
 205    /// Interpolates one coordinate from an exact nonnegative numerator and
 206    /// denominator with one final round-half-to-even conversion.
 207    /// </summary>
 208    internal static Fixed64 InterpolateCoordinate(
 209        Fixed64 start,
 210        Fixed64 end,
 211        Signed192 numerator,
 212        Signed192 denominator)
 213    {
 209214        if (start == end)
 60215            return start;
 216
 149217        Signed192 remaining = WideArithmetic.SubtractSigned192(denominator, numerator);
 149218        Signed320 weighted = WideArithmetic.AddSigned320(
 149219            WideArithmetic.MultiplySigned192(
 149220                Signed192.Signed(start.m_rawValue),
 149221                remaining),
 149222            WideArithmetic.MultiplySigned192(
 149223                Signed192.Signed(end.m_rawValue),
 149224                numerator));
 149225        return Fixed64.GetSignedRawRatio(weighted, denominator);
 226    }
 227
 228    private static bool TryRoundDistance(Signed192 squaredDistance, out Fixed64 distance)
 229    {
 28230        Signed192 root = WideArithmetic.GetFloorSquareRoot(
 28231            Signed320.ExtendValue(squaredDistance),
 28232            out Signed192 remainder);
 28233        WideArithmetic.GetMagnitude(root, out ulong high, out ulong middle, out ulong low);
 234        // A 2D/3D Fixed64 endpoint difference cannot produce a distance root
 235        // beyond the middle word; only its representable low-word limit varies.
 28236        if (middle != 0UL || low > (ulong)long.MaxValue)
 237        {
 3238            distance = Fixed64.MaxValue;
 3239            return false;
 240        }
 241
 242        // For integer n = root^2 + remainder, sqrt(n) rounds upward exactly
 243        // when remainder is at least root + 1. A half-way tie is impossible.
 25244        if (WideArithmetic.CompareMagnitude(remainder, root) > 0)
 245        {
 11246            if (low == (ulong)long.MaxValue)
 247            {
 1248                distance = Fixed64.MaxValue;
 1249                return false;
 250            }
 251
 10252            low++;
 253        }
 254
 24255        distance = Fixed64.FromRaw((long)low);
 24256        return true;
 257    }
 258
 259    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 260    private static Signed192 GetSquaredRadiusSum(Fixed64 firstRadius, Fixed64 secondRadius)
 261    {
 459262        ulong radiusSum = unchecked((ulong)firstRadius.m_rawValue + (ulong)secondRadius.m_rawValue);
 459263        Fixed64.Multiply64To128(radiusSum, radiusSum, out ulong middle, out ulong low);
 459264        return new Signed192(0UL, middle, low);
 265    }
 266
 267    /// <summary>
 268    /// Returns the exact dot product of two two-dimensional endpoint differences.
 269    /// </summary>
 270    internal static Signed192 GetDifferenceDotProduct2D(
 271        Fixed64 leftEndX,
 272        Fixed64 leftStartX,
 273        Fixed64 leftEndY,
 274        Fixed64 leftStartY,
 275        Fixed64 rightEndX,
 276        Fixed64 rightStartX,
 277        Fixed64 rightEndY,
 278        Fixed64 rightStartY)
 279    {
 248792280        ulong high = 0UL;
 248792281        ulong middle = 0UL;
 248792282        ulong low = 0UL;
 248792283        AccumulateDifferenceProduct(
 248792284            leftEndX.m_rawValue,
 248792285            leftStartX.m_rawValue,
 248792286            rightEndX.m_rawValue,
 248792287            rightStartX.m_rawValue,
 248792288            ref high,
 248792289            ref middle,
 248792290            ref low);
 248792291        AccumulateDifferenceProduct(
 248792292            leftEndY.m_rawValue,
 248792293            leftStartY.m_rawValue,
 248792294            rightEndY.m_rawValue,
 248792295            rightStartY.m_rawValue,
 248792296            ref high,
 248792297            ref middle,
 248792298            ref low);
 248792299        return new Signed192(high, middle, low);
 300    }
 301
 302    /// <summary>
 303    /// Returns the exact dot product of two three-dimensional endpoint differences.
 304    /// </summary>
 305    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 306    internal static Signed192 GetDifferenceDotProduct3D(
 307        Fixed64 leftEndX,
 308        Fixed64 leftStartX,
 309        Fixed64 leftEndY,
 310        Fixed64 leftStartY,
 311        Fixed64 leftEndZ,
 312        Fixed64 leftStartZ,
 313        Fixed64 rightEndX,
 314        Fixed64 rightStartX,
 315        Fixed64 rightEndY,
 316        Fixed64 rightStartY,
 317        Fixed64 rightEndZ,
 318        Fixed64 rightStartZ)
 319    {
 30585320        if (TrySubtractRaw(leftEndX.m_rawValue, leftStartX.m_rawValue, out long leftX)
 30585321            && TrySubtractRaw(leftEndY.m_rawValue, leftStartY.m_rawValue, out long leftY)
 30585322            && TrySubtractRaw(leftEndZ.m_rawValue, leftStartZ.m_rawValue, out long leftZ)
 30585323            && TrySubtractRaw(rightEndX.m_rawValue, rightStartX.m_rawValue, out long rightX)
 30585324            && TrySubtractRaw(rightEndY.m_rawValue, rightStartY.m_rawValue, out long rightY)
 30585325            && TrySubtractRaw(rightEndZ.m_rawValue, rightStartZ.m_rawValue, out long rightZ))
 326        {
 30187327            ulong narrowHigh = 0UL;
 30187328            ulong narrowMiddle = 0UL;
 30187329            ulong narrowLow = 0UL;
 30187330            AccumulateRawProduct(leftX, rightX, false, ref narrowHigh, ref narrowMiddle, ref narrowLow);
 30187331            AccumulateRawProduct(leftY, rightY, false, ref narrowHigh, ref narrowMiddle, ref narrowLow);
 30187332            AccumulateRawProduct(leftZ, rightZ, false, ref narrowHigh, ref narrowMiddle, ref narrowLow);
 30187333            return new Signed192(narrowHigh, narrowMiddle, narrowLow);
 334        }
 335
 398336        ulong high = 0UL;
 398337        ulong middle = 0UL;
 398338        ulong low = 0UL;
 398339        AccumulateDifferenceProduct(
 398340            leftEndX.m_rawValue,
 398341            leftStartX.m_rawValue,
 398342            rightEndX.m_rawValue,
 398343            rightStartX.m_rawValue,
 398344            ref high,
 398345            ref middle,
 398346            ref low);
 398347        AccumulateDifferenceProduct(
 398348            leftEndY.m_rawValue,
 398349            leftStartY.m_rawValue,
 398350            rightEndY.m_rawValue,
 398351            rightStartY.m_rawValue,
 398352            ref high,
 398353            ref middle,
 398354            ref low);
 398355        AccumulateDifferenceProduct(
 398356            leftEndZ.m_rawValue,
 398357            leftStartZ.m_rawValue,
 398358            rightEndZ.m_rawValue,
 398359            rightStartZ.m_rawValue,
 398360            ref high,
 398361            ref middle,
 398362            ref low);
 398363        return new Signed192(high, middle, low);
 364    }
 365
 366    /// <summary>
 367    /// Returns whether an exact squared direction rounds to zero in Q32.32.
 368    /// </summary>
 369    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 370    internal static bool IsSquaredLengthDegenerate(Signed192 value) =>
 287371        value.High == 0UL
 287372        && value.Middle == 0UL
 287373        && value.Low <= (1UL << (FixedMath.SHIFT_AMOUNT_I - 1));
 374
 375    /// <summary>
 376    /// Returns the exact 2D cross product of two endpoint differences.
 377    /// </summary>
 378    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 379    internal static Signed192 GetDifferenceCrossProduct2D(
 380        Fixed64 leftEndX,
 381        Fixed64 leftStartX,
 382        Fixed64 leftEndY,
 383        Fixed64 leftStartY,
 384        Fixed64 rightEndX,
 385        Fixed64 rightStartX,
 386        Fixed64 rightEndY,
 387        Fixed64 rightStartY)
 388    {
 4730389        ulong high = 0UL;
 4730390        ulong middle = 0UL;
 4730391        ulong low = 0UL;
 4730392        AccumulateDifferenceProduct(
 4730393            leftEndX.m_rawValue,
 4730394            leftStartX.m_rawValue,
 4730395            rightEndY.m_rawValue,
 4730396            rightStartY.m_rawValue,
 4730397            ref high,
 4730398            ref middle,
 4730399            ref low);
 4730400        AccumulateDifferenceProduct(
 4730401            leftEndY.m_rawValue,
 4730402            leftStartY.m_rawValue,
 4730403            rightStartX.m_rawValue,
 4730404            rightEndX.m_rawValue,
 4730405            ref high,
 4730406            ref middle,
 4730407            ref low);
 4730408        return new Signed192(high, middle, low);
 409    }
 410
 411    /// <summary>
 412    /// Returns all three exact components of a 3D endpoint-difference cross product.
 413    /// </summary>
 414    internal static void GetDifferenceCrossProduct3D(
 415        Fixed64 leftEndX,
 416        Fixed64 leftStartX,
 417        Fixed64 leftEndY,
 418        Fixed64 leftStartY,
 419        Fixed64 leftEndZ,
 420        Fixed64 leftStartZ,
 421        Fixed64 rightEndX,
 422        Fixed64 rightStartX,
 423        Fixed64 rightEndY,
 424        Fixed64 rightStartY,
 425        Fixed64 rightEndZ,
 426        Fixed64 rightStartZ,
 427        out Signed192 x,
 428        out Signed192 y,
 429        out Signed192 z)
 430    {
 3673431        if (TrySubtractRaw(leftEndX.m_rawValue, leftStartX.m_rawValue, out long leftX)
 3673432            && TrySubtractRaw(leftEndY.m_rawValue, leftStartY.m_rawValue, out long leftY)
 3673433            && TrySubtractRaw(leftEndZ.m_rawValue, leftStartZ.m_rawValue, out long leftZ)
 3673434            && TrySubtractRaw(rightEndX.m_rawValue, rightStartX.m_rawValue, out long rightX)
 3673435            && TrySubtractRaw(rightEndY.m_rawValue, rightStartY.m_rawValue, out long rightY)
 3673436            && TrySubtractRaw(rightEndZ.m_rawValue, rightStartZ.m_rawValue, out long rightZ))
 437        {
 3497438            x = GetRawCrossComponent(leftY, leftZ, rightZ, rightY);
 3497439            y = GetRawCrossComponent(leftZ, leftX, rightX, rightZ);
 3497440            z = GetRawCrossComponent(leftX, leftY, rightY, rightX);
 3497441            return;
 442        }
 443
 176444        x = GetDifferenceCrossProduct2D(
 176445            leftEndY, leftStartY, leftEndZ, leftStartZ,
 176446            rightEndY, rightStartY, rightEndZ, rightStartZ);
 176447        y = GetDifferenceCrossProduct2D(
 176448            leftEndZ, leftStartZ, leftEndX, leftStartX,
 176449            rightEndZ, rightStartZ, rightEndX, rightStartX);
 176450        z = GetDifferenceCrossProduct2D(
 176451            leftEndX, leftStartX, leftEndY, leftStartY,
 176452            rightEndX, rightStartX, rightEndY, rightStartY);
 176453    }
 454
 455    /// <summary>
 456    /// Returns the exact nonnegative squared magnitude of three wide components.
 457    /// </summary>
 458    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 459    internal static Signed320 GetSquaredMagnitude(
 460        Signed192 x,
 461        Signed192 y,
 462        Signed192 z,
 463        out Signed320 xSquare,
 464        out Signed320 ySquare,
 465        out Signed320 zSquare)
 466    {
 10481467        xSquare = WideArithmetic.MultiplySigned192(x, x);
 10481468        ySquare = WideArithmetic.MultiplySigned192(y, y);
 10481469        zSquare = WideArithmetic.MultiplySigned192(z, z);
 10481470        return WideArithmetic.AddSigned320(WideArithmetic.AddSigned320(xSquare, ySquare), zSquare);
 471    }
 472
 473    /// <summary>
 474    /// Applies the inclusive public epsilon threshold to an exact Q128.128 magnitude.
 475    /// </summary>
 476    internal static bool IsQ128MagnitudeAtMostEpsilon(Signed320 value)
 477    {
 943478        WideArithmetic.GetMagnitude(
 943479            value,
 943480            out ulong word4,
 943481            out ulong word3,
 943482            out ulong word2,
 943483            out ulong word1,
 943484            out ulong word0);
 943485        ulong epsilonRaw = (ulong)Fixed64.Epsilon.m_rawValue;
 943486        return WideArithmetic.CompareUnsigned(
 943487            word4,
 943488            word3,
 943489            word2,
 943490            word1,
 943491            word0,
 943492            0UL,
 943493            0UL,
 943494            epsilonRaw >> 32,
 943495            epsilonRaw << 32,
 943496            0UL) <= 0;
 497    }
 498
 499    /// <summary>
 500    /// Compares exact squared distances between two pairs of 3D points.
 501    /// </summary>
 502    internal static int CompareSquaredDistance3D(
 503        Fixed64 leftStartX,
 504        Fixed64 leftEndX,
 505        Fixed64 leftStartY,
 506        Fixed64 leftEndY,
 507        Fixed64 leftStartZ,
 508        Fixed64 leftEndZ,
 509        Fixed64 rightStartX,
 510        Fixed64 rightEndX,
 511        Fixed64 rightStartY,
 512        Fixed64 rightEndY,
 513        Fixed64 rightStartZ,
 514        Fixed64 rightEndZ)
 515    {
 104516        Signed192 left = GetDifferenceDotProduct3D(
 104517            leftStartX, leftEndX, leftStartY, leftEndY, leftStartZ, leftEndZ,
 104518            leftStartX, leftEndX, leftStartY, leftEndY, leftStartZ, leftEndZ);
 104519        Signed192 right = GetDifferenceDotProduct3D(
 104520            rightStartX, rightEndX, rightStartY, rightEndY, rightStartZ, rightEndZ,
 104521            rightStartX, rightEndX, rightStartY, rightEndY, rightStartZ, rightEndZ);
 104522        return WideArithmetic.CompareMagnitude(left, right);
 523    }
 524
 525    /// <summary>
 526    /// Returns the exact sign of the scalar triple product of three raw
 527    /// three-component vectors.
 528    /// </summary>
 529    internal static int GetTripleProductSign(
 530        Fixed64 firstX,
 531        Fixed64 firstY,
 532        Fixed64 firstZ,
 533        Fixed64 secondX,
 534        Fixed64 secondY,
 535        Fixed64 secondZ,
 536        Fixed64 thirdX,
 537        Fixed64 thirdY,
 538        Fixed64 thirdZ)
 539    {
 614540        Signed192 minorX = GetDifferenceCrossProduct2D(
 614541            secondY, Fixed64.Zero, secondZ, Fixed64.Zero,
 614542            thirdY, Fixed64.Zero, thirdZ, Fixed64.Zero);
 614543        Signed192 minorY = GetDifferenceCrossProduct2D(
 614544            secondZ, Fixed64.Zero, secondX, Fixed64.Zero,
 614545            thirdZ, Fixed64.Zero, thirdX, Fixed64.Zero);
 614546        Signed192 minorZ = GetDifferenceCrossProduct2D(
 614547            secondX, Fixed64.Zero, secondY, Fixed64.Zero,
 614548            thirdX, Fixed64.Zero, thirdY, Fixed64.Zero);
 614549        Signed320 tripleProduct = WideArithmetic.AddSigned320(
 614550            WideArithmetic.AddSigned320(
 614551                WideArithmetic.MultiplySigned192(Signed192.Signed(firstX.m_rawValue), minorX),
 614552                WideArithmetic.MultiplySigned192(Signed192.Signed(firstY.m_rawValue), minorY)),
 614553            WideArithmetic.MultiplySigned192(Signed192.Signed(firstZ.m_rawValue), minorZ));
 614554        return tripleProduct.Sign;
 555    }
 556
 557    /// <summary>
 558    /// Applies the public 3D segment near-parallel threshold to an exact Q128.128 determinant.
 559    /// </summary>
 560    internal static bool IsSegmentDeterminantNearParallel(Signed320 determinant)
 561    {
 61562        WideArithmetic.GetMagnitude(
 61563            determinant,
 61564            out ulong word4,
 61565            out ulong word3,
 61566            out ulong word2,
 61567            out ulong word1,
 61568            out ulong word0);
 61569        ulong epsilonRaw = (ulong)Fixed64.Epsilon.m_rawValue;
 61570        return WideArithmetic.CompareUnsigned(
 61571            word4,
 61572            word3,
 61573            word2,
 61574            word1,
 61575            word0,
 61576            0UL,
 61577            0UL,
 61578            epsilonRaw >> 32,
 61579            epsilonRaw << 32,
 61580            0UL) < 0;
 581    }
 582
 583    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 584    internal static void AccumulateDifferenceProduct(
 585        long candidate,
 586        long current,
 587        long directionEnd,
 588        long directionStart,
 589        ref ulong sumHigh,
 590        ref ulong sumMiddle,
 591        ref ulong sumLow)
 592    {
 509047593        if (candidate == current || directionEnd == directionStart)
 229294594            return;
 595
 279753596        bool negativeDifference = candidate < current;
 279753597        ulong differenceMagnitude = negativeDifference
 279753598            ? unchecked((ulong)current - (ulong)candidate)
 279753599            : unchecked((ulong)candidate - (ulong)current);
 279753600        bool negativeDirection = directionEnd < directionStart;
 279753601        ulong directionMagnitude = negativeDirection
 279753602            ? unchecked((ulong)directionStart - (ulong)directionEnd)
 279753603            : unchecked((ulong)directionEnd - (ulong)directionStart);
 279753604        bool negativeProduct = negativeDifference != negativeDirection;
 605
 279753606        Fixed64.Multiply64To128(
 279753607            differenceMagnitude,
 279753608            directionMagnitude,
 279753609            out ulong productMiddle,
 279753610            out ulong productLow);
 611
 279753612        ulong productHigh = 0UL;
 279753613        if (negativeProduct)
 614        {
 63606615            productLow = unchecked(~productLow + 1UL);
 63606616            productMiddle = unchecked(~productMiddle + (productLow == 0UL ? 1UL : 0UL));
 63606617            productHigh = ulong.MaxValue;
 618        }
 619
 279753620        ulong previousLow = sumLow;
 279753621        sumLow = unchecked(sumLow + productLow);
 279753622        ulong carry = sumLow < previousLow ? 1UL : 0UL;
 623
 279753624        ulong addMiddle = unchecked(productMiddle + carry);
 279753625        ulong carryHigh = addMiddle < productMiddle ? 1UL : 0UL;
 279753626        ulong previousMiddle = sumMiddle;
 279753627        sumMiddle = unchecked(sumMiddle + addMiddle);
 279753628        if (sumMiddle < previousMiddle)
 8123629            carryHigh = 1UL;
 630
 279753631        sumHigh = unchecked(sumHigh + productHigh + carryHigh);
 279753632    }
 633
 634    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 635    private static Signed192 GetRawCrossComponent(
 636        long leftFirst,
 637        long leftSecond,
 638        long rightFirst,
 639        long rightSecond)
 640    {
 10491641        ulong high = 0UL;
 10491642        ulong middle = 0UL;
 10491643        ulong low = 0UL;
 10491644        AccumulateRawProduct(leftFirst, rightFirst, false, ref high, ref middle, ref low);
 10491645        AccumulateRawProduct(leftSecond, rightSecond, true, ref high, ref middle, ref low);
 10491646        return new Signed192(high, middle, low);
 647    }
 648
 649    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 650    private static bool TrySubtractRaw(long end, long start, out long difference)
 651    {
 202993652        difference = unchecked(end - start);
 202993653        return ((end ^ start) & (end ^ difference)) >= 0L;
 654    }
 655
 656    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 657    private static void AccumulateRawProduct(
 658        long left,
 659        long right,
 660        bool subtract,
 661        ref ulong sumHigh,
 662        ref ulong sumMiddle,
 663        ref ulong sumLow)
 664    {
 111543665        if (left == 0L || right == 0L)
 74817666            return;
 667
 36726668        ulong leftMagnitude = left < 0L ? unchecked(0UL - (ulong)left) : (ulong)left;
 36726669        ulong rightMagnitude = right < 0L ? unchecked(0UL - (ulong)right) : (ulong)right;
 36726670        bool negativeProduct = (left < 0L) != (right < 0L) != subtract;
 36726671        Fixed64.Multiply64To128(leftMagnitude, rightMagnitude, out ulong productMiddle, out ulong productLow);
 672
 36726673        ulong productHigh = 0UL;
 36726674        if (negativeProduct)
 675        {
 14269676            productLow = unchecked(~productLow + 1UL);
 14269677            productMiddle = unchecked(~productMiddle + (productLow == 0UL ? 1UL : 0UL));
 14269678            productHigh = ulong.MaxValue;
 679        }
 680
 36726681        ulong previousLow = sumLow;
 36726682        sumLow = unchecked(sumLow + productLow);
 36726683        ulong carry = sumLow < previousLow ? 1UL : 0UL;
 684
 36726685        ulong addMiddle = unchecked(productMiddle + carry);
 36726686        ulong carryHigh = addMiddle < productMiddle ? 1UL : 0UL;
 36726687        ulong previousMiddle = sumMiddle;
 36726688        sumMiddle = unchecked(sumMiddle + addMiddle);
 36726689        if (sumMiddle < previousMiddle)
 2244690            carryHigh = 1UL;
 691
 36726692        sumHigh = unchecked(sumHigh + productHigh + carryHigh);
 36726693    }
 694
 695    internal static bool TryGetMagnitudeCeiling(
 696        Fixed64 x,
 697        Fixed64 y,
 698        Fixed64 z,
 699        out Fixed64 magnitude)
 700    {
 5701        Signed192 rawX = Signed192.Signed(x.m_rawValue);
 5702        Signed192 rawY = Signed192.Signed(y.m_rawValue);
 5703        Signed192 rawZ = Signed192.Signed(z.m_rawValue);
 5704        Signed320 squaredMagnitude = WideArithmetic.AddSigned320(
 5705            WideArithmetic.AddSigned320(
 5706                WideArithmetic.MultiplySigned192(rawX, rawX),
 5707                WideArithmetic.MultiplySigned192(rawY, rawY)),
 5708            WideArithmetic.MultiplySigned192(rawZ, rawZ));
 5709        Signed192 root = WideArithmetic.GetFloorSquareRoot(
 5710            squaredMagnitude,
 5711            out Signed192 remainder);
 5712        if (!remainder.IsZero)
 713        {
 3714            root = WideArithmetic.AddSigned192(
 3715                root,
 3716                Signed192.Signed(1L));
 717        }
 718
 5719        if ((root.High | root.Middle | (root.Low >> 63)) != 0UL)
 720        {
 1721            magnitude = default;
 1722            return false;
 723        }
 724
 4725        magnitude = Fixed64.FromRaw((long)root.Low);
 4726        return true;
 727    }
 728
 729    internal static FixedQuaternion GetCanonicalAxisRotation(
 730        Vector3d normalizedAxis)
 731    {
 28732        if (normalizedAxis == Vector3d.Up)
 2733            return FixedQuaternion.Identity;
 26734        if (normalizedAxis == Vector3d.Down)
 735        {
 2736            return FixedQuaternion.FromAxisAngle(
 2737                Vector3d.Right,
 2738                Fixed64.Pi);
 739        }
 740
 24741        return new FixedQuaternion(
 24742            normalizedAxis.Z,
 24743            Fixed64.Zero,
 24744            -normalizedAxis.X,
 24745            Fixed64.One + normalizedAxis.Y).Normalized;
 746    }
 747
 748    /// <summary>
 749    /// Returns one outward-rounded endpoint of a centered finite-axis extent,
 750    /// clipped to the representable scalar domain.
 751    /// </summary>
 752    internal static Fixed64 GetCenteredFiniteAxisBoundClippedToDomain(
 753        Fixed64 center,
 754        Fixed64 axisComponent,
 755        Fixed64 fullAxisLength,
 756        Fixed64 radialExtent,
 757        bool minimum)
 758    {
 1928759        Signed320 centerNumerator = WideArithmetic.MultiplySigned192(
 1928760            Signed192.Signed(center.m_rawValue),
 1928761            CenteredAxisDenominator);
 1928762        Signed320 extentNumerator = WideArithmetic.AddSigned320(
 1928763            WideArithmetic.MultiplySigned192(
 1928764                Signed192.Signed(axisComponent.Abs().m_rawValue),
 1928765                Signed192.Signed(fullAxisLength.m_rawValue)),
 1928766            WideArithmetic.MultiplySigned192(
 1928767                Signed192.Signed(radialExtent.m_rawValue),
 1928768                CenteredAxisDenominator));
 1928769        Signed320 numerator = minimum
 1928770            ? WideArithmetic.SubtractSigned320(centerNumerator, extentNumerator)
 1928771            : WideArithmetic.AddSigned320(centerNumerator, extentNumerator);
 772
 1928773        return GetRationalBoundClippedToDomain(
 1928774            numerator,
 1928775            CenteredAxisDenominator,
 1928776            minimum);
 777    }
 778
 779    internal static Fixed64 GetRationalBoundClippedToDomain(
 780        Signed320 numerator,
 781        Signed192 denominator,
 782        bool minimum)
 783    {
 1960784        Signed320 minimumNumerator = WideArithmetic.MultiplySigned192(
 1960785            Signed192.Signed(Fixed64.MinValue.m_rawValue),
 1960786            denominator);
 1960787        Signed320 maximumNumerator = WideArithmetic.MultiplySigned192(
 1960788            Signed192.Signed(Fixed64.MaxValue.m_rawValue),
 1960789            denominator);
 790
 791        // Clip the exact endpoint before round-to-even so the subsequent
 792        // one-unit outward correction cannot cross the scalar domain.
 1960793        if (WideArithmetic.SubtractSigned320(
 1960794                numerator,
 1960795                minimumNumerator).Sign < 0)
 796        {
 8797            return Fixed64.MinValue;
 798        }
 1952799        if (WideArithmetic.SubtractSigned320(
 1952800                numerator,
 1952801                maximumNumerator).Sign > 0)
 802        {
 10803            return Fixed64.MaxValue;
 804        }
 805
 1942806        Fixed64 bound = Fixed64.GetSignedRawRatio(
 1942807            numerator,
 1942808            denominator);
 1942809        Signed320 represented = WideArithmetic.MultiplySigned192(
 1942810            Signed192.Signed(bound.m_rawValue),
 1942811            denominator);
 1942812        int comparison = WideArithmetic.SubtractSigned320(represented, numerator).Sign;
 1942813        if (minimum && comparison > 0)
 8814            return Fixed64.FromRaw(bound.m_rawValue - 1L);
 1934815        if (!minimum && comparison < 0)
 9816            return Fixed64.FromRaw(bound.m_rawValue + 1L);
 1925817        return bound;
 818    }
 819}

/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    {
 19105        Signed192 numerator = GetDifferenceDotProduct3D(
 19106            target.X, source.X,
 19107            target.Y, source.Y,
 19108            target.Z, source.Z,
 19109            direction.X, Fixed64.Zero,
 19110            direction.Y, Fixed64.Zero,
 19111            direction.Z, Fixed64.Zero);
 19112        if (numerator.Sign <= 0)
 2113            return Fixed64.Zero;
 114
 17115        Signed192 denominator = GetDifferenceDotProduct3D(
 17116            direction.X, Fixed64.Zero,
 17117            direction.Y, Fixed64.Zero,
 17118            direction.Z, Fixed64.Zero,
 17119            direction.X, Fixed64.Zero,
 17120            direction.Y, Fixed64.Zero,
 17121            direction.Z, Fixed64.Zero);
 17122        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.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)
GetCenteredConeSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,System.Boolean)
GetCenteredAxisSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideGeometry/CenteredAxisSupportKind,System.Nullable`1<System.Int32>,System.Nullable`1<System.Boolean>)
.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&)
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.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)