< Summary

Line coverage
100%
Covered lines: 1950
Uncovered lines: 0
Coverable lines: 1950
Total lines: 2718
Line coverage: 100%
Branch coverage
100%
Covered branches: 230
Total branches: 230
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: TryGetCoulombLineResponse(...)100%1212100%
File 1: TryGetCoulombDiskResponse(...)100%44100%
File 1: TryGetCoulombDiskResponse(...)100%44100%
File 1: TryGetCoulombDiskResponseCore(...)100%2626100%
File 1: AreCoulombDiskInputsValid(...)100%11100%
File 1: TryGetCompletedNormalAccumulatorRatio(...)100%1616100%
File 1: GetBilateralImpulseRatio(...)100%1010100%
File 1: GetFrictionLimit(...)100%11100%
File 1: AddFixedToRatio(...)100%44100%
File 1: SubtractFixedFromRatio(...)100%44100%
File 1: CompareRatios(...)100%11100%
File 1: IsVectorWithinLimit(...)100%11100%
File 1: AddSignedMagnitudes(...)100%44100%
File 1: TryGetSignedRatioOverSquareRoot(...)100%1414100%
File 1: CompareRatioOverSquareRoot(...)100%11100%
File 1: CompareRatioOverSquareRoot(...)100%11100%
File 1: HaveMatchingParticipants(...)100%11100%
File 2: IsRadialProjectionEqualToFixed(...)100%44100%
File 2: TryGetSignedRadicalAndRationalSum(...)100%2222100%
File 2: CompareSignedRadicalAndRationalSumToMagnitude(...)100%11100%
File 2: CompareSignedRadicalAndRationalSumToMagnitude(...)100%11100%
File 2: GetWeightedFixedSum(...)100%11100%
File 2: GetWeightedSignedWideSum(...)100%11100%
File 2: GetProductSign(...)100%11100%
File 2: TrimMagnitude(...)100%44100%
File 2: TryGetDiskVelocityDeltas(...)100%11100%
File 2: TryGetDiskLinearVelocityDelta(...)100%22100%
File 2: TryGetDiskLinearComponent(...)100%66100%
File 2: TryGetDiskAngularVelocityDelta(...)100%22100%
File 2: TryGetDiskAngularComponent(...)100%44100%
File 2: GetWeightedSignedSum(...)100%88100%
File 3: TryGetNormalResponse(...)100%11100%
File 3: TryGetAccumulatedNormalResponse(...)100%11100%
File 3: TryGetNormalResponseCore(...)100%4242100%
File 3: CreateZeroResponse(...)100%11100%
File 3: GetEffectiveMassRatio(...)100%88100%
File 3: BuildImpulseRatio(...)100%11100%
File 3: ResolveUnilateralImpulse(...)100%1212100%
File 3: TryGetLinearVelocityDelta(...)100%88100%
File 3: TryGetLinearComponent(...)100%22100%
File 3: TryGetAngularVelocityDelta(...)100%44100%
File 3: TryGetAngularComponent(...)100%22100%
File 3: GetRawDot(...)100%11100%
File 3: SetNonNegativeRatio(...)100%22100%
File 3: SetUnsignedSum(...)100%11100%
File 3: SetMagnitude(...)100%11100%
File 3: SetMagnitude(...)100%11100%
File 3: SetMagnitude(...)100%11100%
File 3: SetMagnitude(...)100%11100%
File 3: SetMagnitude(...)100%11100%
File 3: Multiply3(...)100%11100%
File 3: Multiply4(...)100%11100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/CollisionHandling/Response/Exact/ExactContactResponseKernel.Coulomb.cs

#LineLine coverage
 1//=======================================================================
 2// ExactContactResponseKernel.Coulomb.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Runtime.CompilerServices;
 10
 11using FixedMathSharp;
 12using FixedMathSharp.Geometry;
 13
 14namespace Gravitas.CollisionHandling;
 15
 16/// <content>
 17/// Owns exact line and disk Coulomb-friction policy and materialization.
 18/// </content>
 19internal static partial class ExactContactResponseKernel
 20{
 21    private const int MaxCoulombWords = MaxResponseWords * 2;
 22    private const int MaxCoulombSquareWords = MaxCoulombWords * 2;
 23    // Normal-response ratios use fewer than 46 active words. A common tangent
 24    // denominator therefore uses fewer than 92, its squared magnitude fewer
 25    // than 185 including carry, and the largest radial comparison fewer than
 26    // 307. The remaining words prevent silent product truncation.
 27    private const int MaxCoulombComparisonWords = 320;
 28
 29    [MethodImpl(MethodImplOptions.NoInlining)]
 30    internal static bool TryGetCoulombLineResponse(
 31        in ExactNormalConstraint3D normalConstraint,
 32        in ExactContactResponseOperand3D firstTangent,
 33        in ExactContactResponseOperand3D secondTangent,
 34        Vector3d tangent,
 35        Fixed64 accumulatedTangentImpulse,
 36        Fixed64 staticFriction,
 37        Fixed64 dynamicFriction,
 38        out ExactCoulombResponse3D response)
 39    {
 5940        response = default;
 5941        bool inputsValid =
 5942            staticFriction >= Fixed64.Zero
 5943            & dynamicFriction >= Fixed64.Zero
 5944            & tangent.IsNormalized();
 5945        if (!inputsValid)
 346            return false;
 47
 5648        bool constraintValid =
 5649            FixedMath.Abs(Vector3d.Dot(
 5650                normalConstraint.Normal,
 5651                tangent)) <= Fixed64.Epsilon
 5652            & HaveMatchingParticipants(
 5653                normalConstraint.First,
 5654                firstTangent)
 5655            & HaveMatchingParticipants(
 5656                normalConstraint.Second,
 5657                secondTangent);
 5658        if (!constraintValid)
 259            return false;
 60
 5461        Span<ulong> normalNumerator = stackalloc ulong[MaxResponseWords];
 5462        Span<ulong> normalDenominator = stackalloc ulong[MaxResponseWords];
 5463        Span<ulong> tangentNumerator = stackalloc ulong[MaxResponseWords];
 5464        Span<ulong> tangentDenominator = stackalloc ulong[MaxResponseWords];
 5465        if (!TryGetCompletedNormalAccumulatorRatio(
 5466                normalConstraint,
 5467                normalNumerator,
 5468                normalDenominator))
 169            return false;
 5370        GetBilateralImpulseRatio(
 5371            firstTangent,
 5372            secondTangent,
 5373            tangent,
 5374            Fixed64.Zero,
 5375            tangentNumerator,
 5376            tangentDenominator,
 5377            out int tangentSign);
 78
 5379        Span<ulong> desiredNumerator = stackalloc ulong[MaxResponseWords];
 5380        AddFixedToRatio(
 5381            tangentNumerator,
 5382            tangentDenominator,
 5383            tangentSign,
 5384            accumulatedTangentImpulse,
 5385            desiredNumerator,
 5386            out int desiredSign);
 87
 5388        Span<ulong> staticNumerator = stackalloc ulong[MaxResponseWords];
 5389        Span<ulong> staticDenominator = stackalloc ulong[MaxResponseWords];
 5390        GetFrictionLimit(
 5391            normalNumerator,
 5392            normalDenominator,
 5393            staticFriction,
 5394            staticNumerator,
 5395            staticDenominator);
 96
 5397        Span<ulong> appliedNumerator = stackalloc ulong[MaxCoulombWords];
 5398        Span<ulong> appliedDenominator = stackalloc ulong[MaxCoulombWords];
 99        int appliedSign;
 53100        Span<ulong> accumulatedNumerator = stackalloc ulong[MaxCoulombWords];
 53101        Span<ulong> accumulatedDenominator = stackalloc ulong[MaxCoulombWords];
 102        int accumulatedSign;
 53103        appliedNumerator.Clear();
 53104        appliedDenominator.Clear();
 53105        accumulatedNumerator.Clear();
 53106        accumulatedDenominator.Clear();
 53107        Span<ulong> clampedNumerator = stackalloc ulong[MaxCoulombWords];
 53108        Span<ulong> clampedDenominator = stackalloc ulong[MaxResponseWords];
 53109        if (CompareRatios(
 53110                desiredNumerator,
 53111                tangentDenominator,
 53112                staticNumerator,
 53113                staticDenominator) <= 0)
 114        {
 37115            tangentNumerator.CopyTo(appliedNumerator);
 37116            tangentDenominator.CopyTo(appliedDenominator);
 37117            appliedSign = tangentSign;
 37118            desiredNumerator.CopyTo(accumulatedNumerator);
 37119            tangentDenominator.CopyTo(accumulatedDenominator);
 37120            accumulatedSign = desiredSign;
 121        }
 122        else
 123        {
 16124            GetFrictionLimit(
 16125                normalNumerator,
 16126                normalDenominator,
 16127                dynamicFriction,
 16128                clampedNumerator,
 16129                clampedDenominator);
 16130            clampedNumerator.CopyTo(accumulatedNumerator);
 16131            clampedDenominator.CopyTo(accumulatedDenominator);
 16132            accumulatedSign = WideArithmetic.IsZeroMagnitude(
 16133                clampedNumerator)
 16134                ? 0
 16135                : desiredSign;
 16136            SubtractFixedFromRatio(
 16137                clampedNumerator,
 16138                clampedDenominator,
 16139                accumulatedSign,
 16140                accumulatedTangentImpulse,
 16141                appliedNumerator,
 16142                appliedDenominator,
 16143                out appliedSign);
 144        }
 145
 53146        bool resolved = TryGetLinearVelocityDelta(
 53147            firstTangent.LinearImpulseAxis,
 53148            firstTangent.InverseMass,
 53149            appliedNumerator,
 53150            appliedDenominator,
 53151            appliedSign,
 53152            out Vector3d firstLinear);
 53153        resolved &= TryGetAngularVelocityDelta(
 53154            firstTangent.Lever,
 53155            -tangent,
 53156            firstTangent.InverseInertia,
 53157            appliedNumerator,
 53158            appliedDenominator,
 53159            appliedSign,
 53160            out Vector3d firstAngular);
 53161        resolved &= TryGetLinearVelocityDelta(
 53162            secondTangent.LinearImpulseAxis,
 53163            secondTangent.InverseMass,
 53164            appliedNumerator,
 53165            appliedDenominator,
 53166            appliedSign,
 53167            out Vector3d secondLinear);
 53168        resolved &= TryGetAngularVelocityDelta(
 53169            secondTangent.Lever,
 53170            tangent,
 53171            secondTangent.InverseInertia,
 53172            appliedNumerator,
 53173            appliedDenominator,
 53174            appliedSign,
 53175            out Vector3d secondAngular);
 53176        if (!resolved)
 3177            return false;
 178
 50179        bool hasAccumulatedProjection = Fixed64.TryGetSignedRawRatio(
 50180            accumulatedNumerator,
 50181            accumulatedDenominator,
 50182            accumulatedSign < 0,
 50183            out Fixed64 accumulatedProjection);
 50184        response = new ExactCoulombResponse3D(
 50185            !WideArithmetic.IsZeroMagnitude(appliedNumerator),
 50186            firstLinear,
 50187            firstAngular,
 50188            secondLinear,
 50189            secondAngular,
 50190            hasAccumulatedProjection,
 50191            accumulatedProjection,
 50192            hasSecondaryAccumulatedImpulse: false,
 50193            secondaryAccumulatedImpulse: default);
 50194        return true;
 195    }
 196
 197    [MethodImpl(MethodImplOptions.NoInlining)]
 198    internal static bool TryGetCoulombDiskResponse(
 199        Vector3d normal,
 200        Fixed64 completedNormalImpulse,
 201        in ExactContactResponseOperand3D primaryFirst,
 202        in ExactContactResponseOperand3D primarySecond,
 203        Vector3d primaryTangent,
 204        Fixed64 accumulatedPrimaryTangentImpulse,
 205        in ExactContactResponseOperand3D secondaryFirst,
 206        in ExactContactResponseOperand3D secondarySecond,
 207        Vector3d secondaryTangent,
 208        Fixed64 accumulatedSecondaryTangentImpulse,
 209        Fixed64 staticFriction,
 210        Fixed64 dynamicFriction,
 211        out ExactCoulombResponse3D response)
 212    {
 386213        response = default;
 386214        if (completedNormalImpulse < Fixed64.Zero
 386215            || !AreCoulombDiskInputsValid(
 386216                normal,
 386217                primaryFirst,
 386218                primarySecond,
 386219                primaryTangent,
 386220                secondaryFirst,
 386221                secondarySecond,
 386222                secondaryTangent,
 386223                staticFriction,
 386224                dynamicFriction))
 225        {
 2226            return false;
 227        }
 228
 384229        Span<ulong> normalNumerator = stackalloc ulong[MaxResponseWords];
 384230        Span<ulong> normalDenominator = stackalloc ulong[MaxResponseWords];
 384231        SetMagnitude(completedNormalImpulse, normalNumerator);
 384232        normalDenominator.Clear();
 384233        normalDenominator[0] = 1UL;
 384234        return TryGetCoulombDiskResponseCore(
 384235            normalNumerator,
 384236            normalDenominator,
 384237            primaryFirst,
 384238            primarySecond,
 384239            primaryTangent,
 384240            accumulatedPrimaryTangentImpulse,
 384241            secondaryFirst,
 384242            secondarySecond,
 384243            secondaryTangent,
 384244            accumulatedSecondaryTangentImpulse,
 384245            staticFriction,
 384246            dynamicFriction,
 384247            Fixed64.Epsilon,
 384248            out response);
 249    }
 250
 251    [MethodImpl(MethodImplOptions.NoInlining)]
 252    internal static bool TryGetCoulombDiskResponse(
 253        in ExactNormalConstraint3D normalConstraint,
 254        in ExactContactResponseOperand3D primaryFirst,
 255        in ExactContactResponseOperand3D primarySecond,
 256        Vector3d primaryTangent,
 257        Fixed64 accumulatedPrimaryTangentImpulse,
 258        in ExactContactResponseOperand3D secondaryFirst,
 259        in ExactContactResponseOperand3D secondarySecond,
 260        Vector3d secondaryTangent,
 261        Fixed64 accumulatedSecondaryTangentImpulse,
 262        Fixed64 staticFriction,
 263        Fixed64 dynamicFriction,
 264        out ExactCoulombResponse3D response)
 265    {
 59266        response = default;
 59267        bool inputsValid = AreCoulombDiskInputsValid(
 59268                normalConstraint.Normal,
 59269                primaryFirst,
 59270                primarySecond,
 59271                primaryTangent,
 59272                secondaryFirst,
 59273                secondarySecond,
 59274                secondaryTangent,
 59275                staticFriction,
 59276                dynamicFriction)
 59277            & HaveMatchingParticipants(
 59278                normalConstraint.First,
 59279                primaryFirst)
 59280            & HaveMatchingParticipants(
 59281                normalConstraint.Second,
 59282                primarySecond)
 59283            & HaveMatchingParticipants(primaryFirst, secondaryFirst)
 59284            & HaveMatchingParticipants(primarySecond, secondarySecond);
 59285        if (!inputsValid)
 3286            return false;
 287
 56288        Span<ulong> normalNumerator = stackalloc ulong[MaxResponseWords];
 56289        Span<ulong> normalDenominator = stackalloc ulong[MaxResponseWords];
 56290        if (!TryGetCompletedNormalAccumulatorRatio(
 56291                normalConstraint,
 56292                normalNumerator,
 56293                normalDenominator))
 1294            return false;
 295
 55296        return TryGetCoulombDiskResponseCore(
 55297            normalNumerator,
 55298            normalDenominator,
 55299            primaryFirst,
 55300            primarySecond,
 55301            primaryTangent,
 55302            accumulatedPrimaryTangentImpulse,
 55303            secondaryFirst,
 55304            secondarySecond,
 55305            secondaryTangent,
 55306            accumulatedSecondaryTangentImpulse,
 55307            staticFriction,
 55308            dynamicFriction,
 55309            Fixed64.Zero,
 55310            out response);
 311    }
 312
 313    private static bool TryGetCoulombDiskResponseCore(
 314        ReadOnlySpan<ulong> normalNumerator,
 315        ReadOnlySpan<ulong> normalDenominator,
 316        in ExactContactResponseOperand3D primaryFirst,
 317        in ExactContactResponseOperand3D primarySecond,
 318        Vector3d primaryTangent,
 319        Fixed64 accumulatedPrimaryTangentImpulse,
 320        in ExactContactResponseOperand3D secondaryFirst,
 321        in ExactContactResponseOperand3D secondarySecond,
 322        Vector3d secondaryTangent,
 323        Fixed64 accumulatedSecondaryTangentImpulse,
 324        Fixed64 staticFriction,
 325        Fixed64 dynamicFriction,
 326        Fixed64 velocityDeadzone,
 327        out ExactCoulombResponse3D response)
 328    {
 439329        response = default;
 439330        Span<ulong> primaryNumerator = stackalloc ulong[MaxResponseWords];
 439331        Span<ulong> primaryDenominator = stackalloc ulong[MaxResponseWords];
 439332        Span<ulong> secondaryNumerator = stackalloc ulong[MaxResponseWords];
 439333        Span<ulong> secondaryDenominator = stackalloc ulong[MaxResponseWords];
 439334        GetBilateralImpulseRatio(
 439335            primaryFirst,
 439336            primarySecond,
 439337            primaryTangent,
 439338            velocityDeadzone,
 439339            primaryNumerator,
 439340            primaryDenominator,
 439341            out int primarySign);
 439342        GetBilateralImpulseRatio(
 439343            secondaryFirst,
 439344            secondarySecond,
 439345            secondaryTangent,
 439346            velocityDeadzone,
 439347            secondaryNumerator,
 439348            secondaryDenominator,
 439349            out int secondarySign);
 350
 439351        Span<ulong> desiredPrimaryNumerator =
 439352            stackalloc ulong[MaxResponseWords];
 439353        Span<ulong> desiredSecondaryNumerator =
 439354            stackalloc ulong[MaxResponseWords];
 439355        AddFixedToRatio(
 439356            primaryNumerator,
 439357            primaryDenominator,
 439358            primarySign,
 439359            accumulatedPrimaryTangentImpulse,
 439360            desiredPrimaryNumerator,
 439361            out int desiredPrimarySign);
 439362        AddFixedToRatio(
 439363            secondaryNumerator,
 439364            secondaryDenominator,
 439365            secondarySign,
 439366            accumulatedSecondaryTangentImpulse,
 439367            desiredSecondaryNumerator,
 439368            out int desiredSecondarySign);
 369
 439370        Span<ulong> commonDenominator = stackalloc ulong[MaxCoulombWords];
 439371        Span<ulong> primaryAtCommon = stackalloc ulong[MaxCoulombWords];
 439372        Span<ulong> secondaryAtCommon = stackalloc ulong[MaxCoulombWords];
 439373        WideArithmetic.MultiplyMagnitudes(
 439374            primaryDenominator,
 439375            secondaryDenominator,
 439376            commonDenominator);
 439377        WideArithmetic.MultiplyMagnitudes(
 439378            desiredPrimaryNumerator,
 439379            secondaryDenominator,
 439380            primaryAtCommon);
 439381        WideArithmetic.MultiplyMagnitudes(
 439382            desiredSecondaryNumerator,
 439383            primaryDenominator,
 439384            secondaryAtCommon);
 385
 439386        Span<ulong> magnitudeSquared = stackalloc ulong[MaxCoulombSquareWords];
 439387        Span<ulong> square = stackalloc ulong[MaxCoulombSquareWords];
 439388        WideArithmetic.MultiplyMagnitudes(
 439389            primaryAtCommon,
 439390            primaryAtCommon,
 439391            magnitudeSquared);
 439392        WideArithmetic.MultiplyMagnitudes(
 439393            secondaryAtCommon,
 439394            secondaryAtCommon,
 439395            square);
 439396        WideArithmetic.AddMagnitudeInto(square, magnitudeSquared);
 397
 439398        Span<ulong> staticNumerator = stackalloc ulong[MaxResponseWords];
 439399        Span<ulong> staticDenominator = stackalloc ulong[MaxResponseWords];
 439400        GetFrictionLimit(
 439401            normalNumerator,
 439402            normalDenominator,
 439403            staticFriction,
 439404            staticNumerator,
 439405            staticDenominator);
 439406        bool withinStaticLimit = IsVectorWithinLimit(
 439407            magnitudeSquared,
 439408            commonDenominator,
 439409            staticNumerator,
 439410            staticDenominator);
 411
 439412        Span<ulong> dynamicNumerator = stackalloc ulong[MaxResponseWords];
 439413        Span<ulong> dynamicDenominator = stackalloc ulong[MaxResponseWords];
 439414        if (!withinStaticLimit)
 415        {
 225416            GetFrictionLimit(
 225417                normalNumerator,
 225418                normalDenominator,
 225419                dynamicFriction,
 225420                dynamicNumerator,
 225421                dynamicDenominator);
 422        }
 423
 439424        bool useDynamicProjection =
 439425            !withinStaticLimit
 439426            && !WideArithmetic.IsZeroMagnitude(magnitudeSquared)
 439427            && !WideArithmetic.IsZeroMagnitude(dynamicNumerator);
 428        bool hasAppliedImpulse;
 429        bool resolved;
 430        Vector3d firstLinear;
 431        Vector3d firstAngular;
 432        Vector3d secondLinear;
 433        Vector3d secondAngular;
 439434        if (useDynamicProjection)
 435        {
 217436            hasAppliedImpulse =
 217437                !IsRadialProjectionEqualToFixed(
 217438                    primaryAtCommon,
 217439                    desiredPrimarySign,
 217440                    dynamicNumerator,
 217441                    dynamicDenominator,
 217442                    magnitudeSquared,
 217443                    accumulatedPrimaryTangentImpulse)
 217444                || !IsRadialProjectionEqualToFixed(
 217445                    secondaryAtCommon,
 217446                    desiredSecondarySign,
 217447                    dynamicNumerator,
 217448                    dynamicDenominator,
 217449                    magnitudeSquared,
 217450                    accumulatedSecondaryTangentImpulse);
 217451            resolved = TryGetDiskVelocityDeltas(
 217452                primaryFirst,
 217453                primarySecond,
 217454                secondaryFirst,
 217455                secondarySecond,
 217456                primaryTangent,
 217457                secondaryTangent,
 217458                primaryAtCommon,
 217459                desiredPrimarySign,
 217460                secondaryAtCommon,
 217461                desiredSecondarySign,
 217462                commonDenominator,
 217463                rational: false,
 217464                dynamicNumerator,
 217465                dynamicDenominator,
 217466                magnitudeSquared,
 217467                accumulatedPrimaryTangentImpulse,
 217468                accumulatedSecondaryTangentImpulse,
 217469                out firstLinear,
 217470                out firstAngular,
 217471                out secondLinear,
 217472                out secondAngular);
 473        }
 474        else
 475        {
 222476            Span<ulong> zero = stackalloc ulong[MaxCoulombWords];
 222477            Span<ulong> appliedPrimaryNumerator =
 222478                stackalloc ulong[MaxCoulombWords];
 222479            Span<ulong> appliedDenominator =
 222480                stackalloc ulong[MaxCoulombWords];
 222481            Span<ulong> appliedSecondaryNumerator =
 222482                stackalloc ulong[MaxCoulombWords];
 222483            zero.Clear();
 222484            SubtractFixedFromRatio(
 222485                withinStaticLimit ? primaryAtCommon : zero,
 222486                commonDenominator,
 222487                withinStaticLimit ? desiredPrimarySign : 0,
 222488                accumulatedPrimaryTangentImpulse,
 222489                appliedPrimaryNumerator,
 222490                appliedDenominator,
 222491                out int appliedPrimarySign);
 222492            SubtractFixedFromRatio(
 222493                withinStaticLimit ? secondaryAtCommon : zero,
 222494                commonDenominator,
 222495                withinStaticLimit ? desiredSecondarySign : 0,
 222496                accumulatedSecondaryTangentImpulse,
 222497                appliedSecondaryNumerator,
 222498                appliedDenominator,
 222499                out int appliedSecondarySign);
 222500            hasAppliedImpulse =
 222501                appliedPrimarySign != 0
 222502                || appliedSecondarySign != 0;
 222503            resolved = TryGetDiskVelocityDeltas(
 222504                primaryFirst,
 222505                primarySecond,
 222506                secondaryFirst,
 222507                secondarySecond,
 222508                primaryTangent,
 222509                secondaryTangent,
 222510                appliedPrimaryNumerator,
 222511                appliedPrimarySign,
 222512                appliedSecondaryNumerator,
 222513                appliedSecondarySign,
 222514                appliedDenominator,
 222515                rational: true,
 222516                dynamicNumerator,
 222517                dynamicDenominator,
 222518                magnitudeSquared,
 222519                Fixed64.Zero,
 222520                Fixed64.Zero,
 222521                out firstLinear,
 222522                out firstAngular,
 222523                out secondLinear,
 222524                out secondAngular);
 525        }
 439526        if (!resolved)
 6527            return false;
 528
 529        bool hasPrimaryProjection;
 530        bool hasSecondaryProjection;
 531        Fixed64 primaryProjection;
 532        Fixed64 secondaryProjection;
 433533        if (withinStaticLimit)
 534        {
 213535            hasPrimaryProjection = Fixed64.TryGetSignedRawRatio(
 213536                primaryAtCommon,
 213537                commonDenominator,
 213538                desiredPrimarySign < 0,
 213539                out primaryProjection);
 213540            hasSecondaryProjection = Fixed64.TryGetSignedRawRatio(
 213541                secondaryAtCommon,
 213542                commonDenominator,
 213543                desiredSecondarySign < 0,
 213544                out secondaryProjection);
 545        }
 220546        else if (useDynamicProjection)
 547        {
 214548            Span<ulong> projectedNumerator =
 214549                stackalloc ulong[MaxCoulombWords + MaxResponseWords];
 214550            WideArithmetic.MultiplyMagnitudes(
 214551                primaryAtCommon,
 214552                dynamicNumerator,
 214553                projectedNumerator);
 214554            hasPrimaryProjection = TryGetSignedRatioOverSquareRoot(
 214555                projectedNumerator,
 214556                dynamicDenominator,
 214557                magnitudeSquared,
 214558                desiredPrimarySign < 0,
 214559                out primaryProjection);
 214560            WideArithmetic.MultiplyMagnitudes(
 214561                secondaryAtCommon,
 214562                dynamicNumerator,
 214563                projectedNumerator);
 214564            hasSecondaryProjection = TryGetSignedRatioOverSquareRoot(
 214565                projectedNumerator,
 214566                dynamicDenominator,
 214567                magnitudeSquared,
 214568                desiredSecondarySign < 0,
 214569                out secondaryProjection);
 570        }
 571        else
 572        {
 6573            hasPrimaryProjection = true;
 6574            hasSecondaryProjection = true;
 6575            primaryProjection = Fixed64.Zero;
 6576            secondaryProjection = Fixed64.Zero;
 577        }
 578
 433579        response = new ExactCoulombResponse3D(
 433580            hasAppliedImpulse,
 433581            firstLinear,
 433582            firstAngular,
 433583            secondLinear,
 433584            secondAngular,
 433585            hasPrimaryProjection,
 433586            primaryProjection,
 433587            hasSecondaryProjection,
 433588            secondaryProjection);
 433589        return true;
 590    }
 591
 592    private static bool AreCoulombDiskInputsValid(
 593        Vector3d normal,
 594        in ExactContactResponseOperand3D primaryFirst,
 595        in ExactContactResponseOperand3D primarySecond,
 596        Vector3d primaryTangent,
 597        in ExactContactResponseOperand3D secondaryFirst,
 598        in ExactContactResponseOperand3D secondarySecond,
 599        Vector3d secondaryTangent,
 600        Fixed64 staticFriction,
 601        Fixed64 dynamicFriction) =>
 444602        staticFriction >= Fixed64.Zero
 444603        & dynamicFriction >= Fixed64.Zero
 444604        & primaryFirst.Lever.Denominator.Sign != 0
 444605        & primarySecond.Lever.Denominator.Sign != 0
 444606        & primaryFirst.InverseMass >= Fixed64.Zero
 444607        & primarySecond.InverseMass >= Fixed64.Zero
 444608        & normal.IsNormalized()
 444609        & primaryTangent.IsNormalized()
 444610        & secondaryTangent.IsNormalized()
 444611        & FixedMath.Abs(Vector3d.Dot(
 444612            primaryTangent,
 444613            secondaryTangent)) <= Fixed64.Epsilon
 444614        & FixedMath.Abs(Vector3d.Dot(
 444615            normal,
 444616            primaryTangent)) <= Fixed64.Epsilon
 444617        & FixedMath.Abs(Vector3d.Dot(
 444618            normal,
 444619            secondaryTangent)) <= Fixed64.Epsilon
 444620        & HaveMatchingParticipants(primaryFirst, secondaryFirst)
 444621        & HaveMatchingParticipants(primarySecond, secondarySecond);
 622
 623    private static bool TryGetCompletedNormalAccumulatorRatio(
 624        in ExactNormalConstraint3D constraint,
 625        Span<ulong> numerator,
 626        Span<ulong> denominator)
 627    {
 110628        numerator.Clear();
 110629        denominator.Clear();
 110630        ExactContactResponseOperand3D first = constraint.First;
 110631        ExactContactResponseOperand3D second = constraint.Second;
 110632        bool inputsValid =
 110633            first.Lever.Denominator.Sign != 0
 110634            & second.Lever.Denominator.Sign != 0
 110635            & constraint.Restitution >= Fixed64.Zero
 110636            & constraint.RestitutionVelocityThreshold >= Fixed64.Zero
 110637            & constraint.AccumulatedImpulse >= Fixed64.Zero
 110638            & constraint.PositiveImpulseScale >= Fixed64.Zero
 110639            & constraint.NegativeImpulseScale >= Fixed64.Zero
 110640            & first.InverseMass >= Fixed64.Zero
 110641            & second.InverseMass >= Fixed64.Zero
 110642            & constraint.Normal.IsNormalized();
 110643        if (!inputsValid)
 2644            return false;
 645
 108646        ExactLever3D.GetRelativePointVelocityRatio(
 108647            first.LinearVelocity,
 108648            first.AngularVelocity,
 108649            first.Lever,
 108650            second.LinearVelocity,
 108651            second.AngularVelocity,
 108652            second.Lever,
 108653            constraint.Normal,
 108654            out Signed832 velocityNumerator,
 108655            out Signed832 velocityDenominator);
 656
 108657        Span<ulong> effectiveNumerator = stackalloc ulong[MaxResponseWords];
 108658        Span<ulong> effectiveDenominator = stackalloc ulong[MaxResponseWords];
 108659        GetEffectiveMassRatio(
 108660            first,
 108661            second,
 108662            constraint.Normal,
 108663            effectiveNumerator,
 108664            effectiveDenominator);
 108665        int velocitySign =
 108666            velocityNumerator.Sign * velocityDenominator.Sign;
 108667        if (velocitySign == 0
 108668            || WideArithmetic.IsZeroMagnitude(effectiveNumerator))
 669        {
 12670            SetMagnitude(constraint.AccumulatedImpulse, numerator);
 12671            denominator[0] = 1UL;
 12672            return true;
 673        }
 674
 96675        bool hasVelocityProjection = Fixed64.TryGetSignedRawRatio(
 96676            velocityNumerator,
 96677            velocityDenominator,
 96678            0,
 96679            out Fixed64 velocityProjection);
 96680        bool applyRestitution = velocitySign < 0
 96681            & (!hasVelocityProjection
 96682                | velocityProjection
 96683                    < -constraint.RestitutionVelocityThreshold);
 96684        Fixed64 scale = velocitySign < 0
 96685            ? constraint.PositiveImpulseScale
 96686            : constraint.NegativeImpulseScale;
 96687        Span<ulong> impulseNumerator = stackalloc ulong[MaxResponseWords];
 96688        Span<ulong> impulseDenominator = stackalloc ulong[MaxResponseWords];
 96689        BuildImpulseRatio(
 96690            velocityNumerator,
 96691            velocityDenominator,
 96692            effectiveNumerator,
 96693            effectiveDenominator,
 96694            applyRestitution ? constraint.Restitution : Fixed64.Zero,
 96695            scale,
 96696            impulseNumerator,
 96697            impulseDenominator);
 698
 96699        Span<ulong> accumulatorMagnitude =
 96700            stackalloc ulong[MaxResponseWords];
 96701        Span<ulong> accumulatorAtImpulseDenominator =
 96702            stackalloc ulong[MaxResponseWords];
 96703        SetMagnitude(constraint.AccumulatedImpulse, accumulatorMagnitude);
 96704        WideArithmetic.MultiplyMagnitudes(
 96705            accumulatorMagnitude,
 96706            impulseDenominator,
 96707            accumulatorAtImpulseDenominator);
 96708        int impulseSign = -velocitySign;
 96709        if (impulseSign < 0
 96710            && WideArithmetic.CompareMagnitudeEqualLength(
 96711                impulseNumerator,
 96712                accumulatorAtImpulseDenominator) >= 0)
 713        {
 1714            denominator[0] = 1UL;
 1715            return true;
 716        }
 717
 95718        accumulatorAtImpulseDenominator.CopyTo(numerator);
 95719        if (impulseSign > 0)
 93720            WideArithmetic.AddMagnitudeInto(impulseNumerator, numerator);
 721        else
 2722            WideArithmetic.SubtractEqualMagnitudes(
 2723                accumulatorAtImpulseDenominator,
 2724                impulseNumerator,
 2725                numerator);
 95726        impulseDenominator.CopyTo(denominator);
 95727        return true;
 728    }
 729
 730    private static void GetBilateralImpulseRatio(
 731        in ExactContactResponseOperand3D first,
 732        in ExactContactResponseOperand3D second,
 733        Vector3d tangent,
 734        Fixed64 velocityDeadzone,
 735        Span<ulong> numerator,
 736        Span<ulong> denominator,
 737        out int sign)
 738    {
 931739        numerator.Clear();
 931740        denominator.Clear();
 931741        sign = 0;
 931742        ExactLever3D.GetRelativePointVelocityRatio(
 931743            first.LinearVelocity,
 931744            first.AngularVelocity,
 931745            first.Lever,
 931746            second.LinearVelocity,
 931747            second.AngularVelocity,
 931748            second.Lever,
 931749            tangent,
 931750            out Signed832 velocityNumerator,
 931751            out Signed832 velocityDenominator);
 752
 931753        Span<ulong> effectiveNumerator = stackalloc ulong[MaxResponseWords];
 931754        Span<ulong> effectiveDenominator = stackalloc ulong[MaxResponseWords];
 931755        GetEffectiveMassRatio(
 931756            first,
 931757            second,
 931758            tangent,
 931759            effectiveNumerator,
 931760            effectiveDenominator);
 931761        int velocitySign =
 931762            velocityNumerator.Sign * velocityDenominator.Sign;
 931763        bool suppressVelocity = velocityDeadzone != Fixed64.Zero
 931764            && Fixed64.TryGetSignedRawRatio(
 931765                velocityNumerator,
 931766                velocityDenominator,
 931767                0,
 931768                out Fixed64 velocityProjection)
 931769            && velocityProjection >= -velocityDeadzone
 931770            && velocityProjection <= velocityDeadzone;
 931771        if (velocitySign == 0
 931772            || suppressVelocity
 931773            || WideArithmetic.IsZeroMagnitude(effectiveNumerator))
 774        {
 467775            denominator[0] = 1UL;
 467776            return;
 777        }
 778
 464779        BuildImpulseRatio(
 464780            velocityNumerator,
 464781            velocityDenominator,
 464782            effectiveNumerator,
 464783            effectiveDenominator,
 464784            Fixed64.Zero,
 464785            Fixed64.One,
 464786            numerator,
 464787        denominator);
 464788        sign = -velocitySign;
 464789    }
 790
 791    private static void GetFrictionLimit(
 792        ReadOnlySpan<ulong> normalNumerator,
 793        ReadOnlySpan<ulong> normalDenominator,
 794        Fixed64 friction,
 795        Span<ulong> numerator,
 796        Span<ulong> denominator)
 797    {
 733798        Span<ulong> frictionMagnitude =
 733799            stackalloc ulong[3];
 733800        Span<ulong> fixedScale =
 733801            stackalloc ulong[1];
 733802        SetMagnitude(friction, frictionMagnitude);
 733803        fixedScale.Clear();
 733804        fixedScale[0] = (ulong)FixedMath.ONE_L;
 733805        WideArithmetic.MultiplyMagnitudes(
 733806            normalNumerator,
 733807            frictionMagnitude,
 733808            numerator);
 733809        WideArithmetic.MultiplyMagnitudes(
 733810            normalDenominator,
 733811            fixedScale,
 733812            denominator);
 733813    }
 814
 815    private static void AddFixedToRatio(
 816        ReadOnlySpan<ulong> ratioNumerator,
 817        ReadOnlySpan<ulong> ratioDenominator,
 818        int ratioSign,
 819        Fixed64 value,
 820        Span<ulong> resultNumerator,
 821        out int resultSign)
 822    {
 931823        Span<ulong> valueMagnitude = stackalloc ulong[3];
 931824        Span<ulong> valueAtDenominator =
 931825            stackalloc ulong[MaxResponseWords];
 931826        SetMagnitude(value, valueMagnitude);
 931827        WideArithmetic.MultiplyMagnitudes(
 931828            valueMagnitude,
 931829            ratioDenominator,
 931830            valueAtDenominator);
 931831        AddSignedMagnitudes(
 931832            ratioNumerator,
 931833            ratioSign,
 931834            valueAtDenominator,
 931835            value == Fixed64.Zero ? 0 : value < Fixed64.Zero ? -1 : 1,
 931836            resultNumerator,
 931837            out resultSign);
 931838    }
 839
 840    private static void SubtractFixedFromRatio(
 841        ReadOnlySpan<ulong> ratioNumerator,
 842        ReadOnlySpan<ulong> ratioDenominator,
 843        int ratioSign,
 844        Fixed64 value,
 845        Span<ulong> resultNumerator,
 846        Span<ulong> resultDenominator,
 847        out int resultSign)
 848    {
 460849        Span<ulong> valueMagnitude = stackalloc ulong[3];
 460850        Span<ulong> valueAtDenominator =
 460851            stackalloc ulong[MaxCoulombWords];
 460852        SetMagnitude(value, valueMagnitude);
 460853        WideArithmetic.MultiplyMagnitudes(
 460854            valueMagnitude,
 460855            ratioDenominator,
 460856            valueAtDenominator);
 460857        AddSignedMagnitudes(
 460858            ratioNumerator,
 460859            ratioSign,
 460860            valueAtDenominator,
 460861            value == Fixed64.Zero ? 0 : value < Fixed64.Zero ? 1 : -1,
 460862            resultNumerator,
 460863            out resultSign);
 460864        resultDenominator.Clear();
 460865        ratioDenominator.CopyTo(resultDenominator);
 460866    }
 867
 868    private static int CompareRatios(
 869        ReadOnlySpan<ulong> firstNumerator,
 870        ReadOnlySpan<ulong> firstDenominator,
 871        ReadOnlySpan<ulong> secondNumerator,
 872        ReadOnlySpan<ulong> secondDenominator)
 873    {
 53874        Span<ulong> first = stackalloc ulong[MaxCoulombWords];
 53875        Span<ulong> second = stackalloc ulong[MaxCoulombWords];
 53876        WideArithmetic.MultiplyMagnitudes(
 53877            firstNumerator,
 53878            secondDenominator,
 53879            first);
 53880        WideArithmetic.MultiplyMagnitudes(
 53881            secondNumerator,
 53882            firstDenominator,
 53883            second);
 53884        return WideArithmetic.CompareMagnitudeEqualLength(first, second);
 885    }
 886
 887    private static bool IsVectorWithinLimit(
 888        ReadOnlySpan<ulong> vectorMagnitudeSquared,
 889        ReadOnlySpan<ulong> vectorDenominator,
 890        ReadOnlySpan<ulong> limitNumerator,
 891        ReadOnlySpan<ulong> limitDenominator)
 892    {
 439893        Span<ulong> denominatorSquared =
 439894            stackalloc ulong[MaxCoulombSquareWords];
 439895        Span<ulong> limitNumeratorSquared =
 439896            stackalloc ulong[MaxCoulombSquareWords];
 439897        Span<ulong> limitDenominatorSquared =
 439898            stackalloc ulong[MaxCoulombSquareWords];
 439899        Span<ulong> left = stackalloc ulong[MaxCoulombComparisonWords];
 439900        Span<ulong> right = stackalloc ulong[MaxCoulombComparisonWords];
 439901        WideArithmetic.MultiplyMagnitudes(
 439902            vectorDenominator,
 439903            vectorDenominator,
 439904            denominatorSquared);
 439905        WideArithmetic.MultiplyMagnitudes(
 439906            limitNumerator,
 439907            limitNumerator,
 439908            limitNumeratorSquared);
 439909        WideArithmetic.MultiplyMagnitudes(
 439910            limitDenominator,
 439911            limitDenominator,
 439912            limitDenominatorSquared);
 439913        WideArithmetic.MultiplyMagnitudes(
 439914            vectorMagnitudeSquared,
 439915            limitDenominatorSquared,
 439916            left);
 439917        WideArithmetic.MultiplyMagnitudes(
 439918            limitNumeratorSquared,
 439919            denominatorSquared,
 439920            right);
 439921        return WideArithmetic.CompareMagnitudeEqualLength(left, right) <= 0;
 922    }
 923
 924    private static void AddSignedMagnitudes(
 925        ReadOnlySpan<ulong> first,
 926        int firstSign,
 927        ReadOnlySpan<ulong> second,
 928        int secondSign,
 929        Span<ulong> result,
 930        out int resultSign)
 931    {
 64205932        result.Clear();
 64205933        resultSign = 0;
 64205934        if (firstSign != 0 & !WideArithmetic.IsZeroMagnitude(first))
 50021935            WideArithmetic.AddSignedMagnitude(
 50021936                first,
 50021937                firstSign,
 50021938                result,
 50021939                ref resultSign);
 64205940        if (secondSign != 0 & !WideArithmetic.IsZeroMagnitude(second))
 54775941            WideArithmetic.AddSignedMagnitude(
 54775942                second,
 54775943                secondSign,
 54775944                result,
 54775945                ref resultSign);
 64205946    }
 947
 948    private static bool TryGetSignedRatioOverSquareRoot(
 949        ReadOnlySpan<ulong> numerator,
 950        ReadOnlySpan<ulong> denominator,
 951        ReadOnlySpan<ulong> radicand,
 952        bool negative,
 953        out Fixed64 result)
 954    {
 428955        if (WideArithmetic.IsZeroMagnitude(numerator))
 956        {
 206957            result = Fixed64.Zero;
 206958            return true;
 959        }
 960
 222961        ulong limit = negative ? 1UL << 63 : (ulong)long.MaxValue;
 222962        if (CompareRatioOverSquareRoot(
 222963                numerator,
 222964                denominator,
 222965                radicand,
 222966                limit) > 0)
 967        {
 2968            result = default;
 2969            return false;
 970        }
 971
 220972        ulong low = 0UL;
 220973        ulong high = limit;
 14083974        while (low < high)
 975        {
 13863976            ulong difference = high - low;
 13863977            ulong middle = low + (difference >> 1) + (difference & 1UL);
 13863978            if (CompareRatioOverSquareRoot(
 13863979                    numerator,
 13863980                    denominator,
 13863981                    radicand,
 13863982                    middle) >= 0)
 983            {
 3394984                low = middle;
 985            }
 986            else
 987            {
 10469988                high = middle - 1UL;
 989            }
 990        }
 991
 220992        ulong quotient = low;
 220993        Span<ulong> doubledQuotient = stackalloc ulong[2];
 220994        doubledQuotient[0] = (quotient << 1) | 1UL;
 220995        doubledQuotient[1] = quotient >> 63;
 220996        int midpointComparison = CompareRatioOverSquareRoot(
 220997            numerator,
 220998            denominator,
 220999            radicand,
 2201000            doubledQuotient,
 2201001            numeratorMultiplier: 2UL);
 2201002        bool roundUp = midpointComparison > 0
 2201003            | (midpointComparison == 0 & (quotient & 1UL) != 0UL);
 2201004        if (roundUp & quotient < limit)
 1005        {
 101006            quotient++;
 1007        }
 1008
 2201009        result = new Fixed64(
 2201010            negative ? unchecked(-(long)quotient) : (long)quotient);
 2201011        return true;
 1012    }
 1013
 1014    private static int CompareRatioOverSquareRoot(
 1015        ReadOnlySpan<ulong> numerator,
 1016        ReadOnlySpan<ulong> denominator,
 1017        ReadOnlySpan<ulong> radicand,
 1018        ulong candidate)
 1019    {
 140851020        Span<ulong> candidateMagnitude = stackalloc ulong[1];
 140851021        candidateMagnitude.Clear();
 140851022        candidateMagnitude[0] = candidate;
 140851023        return CompareRatioOverSquareRoot(
 140851024            numerator,
 140851025            denominator,
 140851026            radicand,
 140851027            candidateMagnitude,
 140851028            numeratorMultiplier: 1UL);
 1029    }
 1030
 1031    private static int CompareRatioOverSquareRoot(
 1032        ReadOnlySpan<ulong> numerator,
 1033        ReadOnlySpan<ulong> denominator,
 1034        ReadOnlySpan<ulong> radicand,
 1035        ReadOnlySpan<ulong> candidate,
 1036        ulong numeratorMultiplier)
 1037    {
 143051038        Span<ulong> multiplier = stackalloc ulong[1];
 143051039        multiplier.Clear();
 143051040        multiplier[0] = numeratorMultiplier;
 143051041        Span<ulong> scaledNumerator =
 143051042            stackalloc ulong[(MaxCoulombComparisonWords / 2) + 1];
 143051043        Span<ulong> left = stackalloc ulong[MaxCoulombComparisonWords];
 143051044        Span<ulong> denominatorTimesCandidate =
 143051045            stackalloc ulong[(MaxCoulombComparisonWords / 2) + 1];
 143051046        Span<ulong> rightBase =
 143051047            stackalloc ulong[MaxCoulombComparisonWords];
 143051048        Span<ulong> right = stackalloc ulong[MaxCoulombComparisonWords];
 143051049        WideArithmetic.MultiplyMagnitudes(
 143051050            numerator,
 143051051            multiplier,
 143051052            scaledNumerator);
 143051053        WideArithmetic.MultiplyMagnitudes(
 143051054            scaledNumerator,
 143051055            scaledNumerator,
 143051056            left);
 143051057        WideArithmetic.MultiplyMagnitudes(
 143051058            denominator,
 143051059            candidate,
 143051060            denominatorTimesCandidate);
 143051061        WideArithmetic.MultiplyMagnitudes(
 143051062            denominatorTimesCandidate,
 143051063            denominatorTimesCandidate,
 143051064            rightBase);
 143051065        WideArithmetic.MultiplyMagnitudes(rightBase, radicand, right);
 143051066        return WideArithmetic.CompareMagnitudeEqualLength(left, right);
 1067    }
 1068
 1069    private static bool HaveMatchingParticipants(
 1070        in ExactContactResponseOperand3D first,
 1071        in ExactContactResponseOperand3D second) =>
 12361072        first.Lever.XNumerator.Equals(second.Lever.XNumerator)
 12361073        & first.Lever.YNumerator.Equals(second.Lever.YNumerator)
 12361074        & first.Lever.ZNumerator.Equals(second.Lever.ZNumerator)
 12361075        & first.Lever.Denominator.Equals(second.Lever.Denominator)
 12361076        & first.InverseMass == second.InverseMass
 12361077        & first.InverseInertia == second.InverseInertia;
 1078}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/CollisionHandling/Response/Exact/ExactContactResponseKernel.CoulombDiskCache.cs

#LineLine coverage
 1//=======================================================================
 2// ExactContactResponseKernel.CoulombDiskCache.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9
 10using FixedMathSharp;
 11
 12namespace Gravitas.CollisionHandling;
 13
 14/// <content>
 15/// Owns exact cached-disk projection comparison and materialization.
 16/// </content>
 17internal static partial class ExactContactResponseKernel
 18{
 19    private static bool IsRadialProjectionEqualToFixed(
 20        ReadOnlySpan<ulong> directionNumerator,
 21        int directionSign,
 22        ReadOnlySpan<ulong> radialNumerator,
 23        ReadOnlySpan<ulong> radialDenominator,
 24        ReadOnlySpan<ulong> radicand,
 25        Fixed64 value)
 26    {
 41127        Span<ulong> projectedNumerator =
 41128            stackalloc ulong[MaxCoulombComparisonWords / 2];
 41129        Span<ulong> valueMagnitude = stackalloc ulong[3];
 41130        Span<ulong> fixedDenominator = stackalloc ulong[1];
 41131        WideArithmetic.MultiplyMagnitudes(
 41132            directionNumerator,
 41133            radialNumerator,
 41134            projectedNumerator);
 41135        SetMagnitude(value, valueMagnitude);
 41136        fixedDenominator.Clear();
 41137        fixedDenominator[0] = 1UL;
 41138        int valueSign =
 41139            value == Fixed64.Zero ? 0 : value < Fixed64.Zero ? -1 : 1;
 41140        return CompareSignedRadicalAndRationalSumToMagnitude(
 41141                projectedNumerator,
 41142                radialDenominator,
 41143                radicand,
 41144                directionSign,
 41145                valueMagnitude,
 41146                fixedDenominator,
 41147                -valueSign,
 41148                candidate: 0UL)
 41149            == 0;
 50    }
 51
 52    internal static bool TryGetSignedRadicalAndRationalSum(
 53        ReadOnlySpan<ulong> radicalNumerator,
 54        ReadOnlySpan<ulong> radicalDenominator,
 55        ReadOnlySpan<ulong> radicand,
 56        int radicalSign,
 57        ReadOnlySpan<ulong> rationalNumerator,
 58        ReadOnlySpan<ulong> rationalDenominator,
 59        int rationalSign,
 60        out Fixed64 result)
 61    {
 256662        int resultSign = CompareSignedRadicalAndRationalSumToMagnitude(
 256663            radicalNumerator,
 256664            radicalDenominator,
 256665            radicand,
 256666            radicalSign,
 256667            rationalNumerator,
 256668            rationalDenominator,
 256669            rationalSign,
 256670            candidate: 0UL);
 256671        if (resultSign == 0)
 72        {
 176073            result = Fixed64.Zero;
 176074            return true;
 75        }
 76
 80677        int normalizedRadicalSign =
 80678            resultSign < 0 ? -radicalSign : radicalSign;
 80679        int normalizedRationalSign =
 80680            resultSign < 0 ? -rationalSign : rationalSign;
 80681        ulong limit =
 80682            resultSign < 0 ? 1UL << 63 : (ulong)long.MaxValue;
 80683        Span<ulong> doubledLimit = stackalloc ulong[2];
 80684        doubledLimit[0] = (limit << 1) | 1UL;
 80685        doubledLimit[1] = limit >> 63;
 80686        int limitMidpointComparison =
 80687            CompareSignedRadicalAndRationalSumToMagnitude(
 80688                radicalNumerator,
 80689                radicalDenominator,
 80690                radicand,
 80691                normalizedRadicalSign,
 80692                rationalNumerator,
 80693                rationalDenominator,
 80694                normalizedRationalSign,
 80695                doubledLimit,
 80696                expressionMultiplier: 2UL);
 80697        if (limitMidpointComparison > 0
 80698            || (limitMidpointComparison == 0
 80699                && (limit & 1UL) != 0UL))
 100        {
 6101            result = default;
 6102            return false;
 103        }
 104
 800105        ulong low = 0UL;
 800106        ulong high = limit;
 51201107        while (low < high)
 108        {
 50401109            ulong difference = high - low;
 50401110            ulong middle =
 50401111                low + (difference >> 1) + (difference & 1UL);
 50401112            if (CompareSignedRadicalAndRationalSumToMagnitude(
 50401113                    radicalNumerator,
 50401114                    radicalDenominator,
 50401115                    radicand,
 50401116                    normalizedRadicalSign,
 50401117                    rationalNumerator,
 50401118                    rationalDenominator,
 50401119                    normalizedRationalSign,
 50401120                    middle) >= 0)
 121            {
 11761122                low = middle;
 123            }
 124            else
 125            {
 38640126                high = middle - 1UL;
 127            }
 128        }
 129
 800130        ulong quotient = low;
 800131        Span<ulong> doubledQuotient = stackalloc ulong[2];
 800132        doubledQuotient[0] = (quotient << 1) | 1UL;
 800133        doubledQuotient[1] = quotient >> 63;
 800134        int midpointComparison =
 800135            CompareSignedRadicalAndRationalSumToMagnitude(
 800136                radicalNumerator,
 800137                radicalDenominator,
 800138                radicand,
 800139                normalizedRadicalSign,
 800140                rationalNumerator,
 800141                rationalDenominator,
 800142                normalizedRationalSign,
 800143                doubledQuotient,
 800144                expressionMultiplier: 2UL);
 800145        bool roundUp = midpointComparison > 0
 800146            | (midpointComparison == 0 & (quotient & 1UL) != 0UL);
 800147        if (roundUp & quotient < limit)
 244148            quotient++;
 149
 800150        result = new Fixed64(
 800151            resultSign < 0
 800152                ? unchecked(-(long)quotient)
 800153                : (long)quotient);
 800154        return true;
 155    }
 156
 157    private static int CompareSignedRadicalAndRationalSumToMagnitude(
 158        ReadOnlySpan<ulong> radicalNumerator,
 159        ReadOnlySpan<ulong> radicalDenominator,
 160        ReadOnlySpan<ulong> radicand,
 161        int radicalSign,
 162        ReadOnlySpan<ulong> rationalNumerator,
 163        ReadOnlySpan<ulong> rationalDenominator,
 164        int rationalSign,
 165        ulong candidate)
 166    {
 53378167        Span<ulong> candidateMagnitude = stackalloc ulong[1];
 53378168        candidateMagnitude[0] = candidate;
 53378169        return CompareSignedRadicalAndRationalSumToMagnitude(
 53378170            radicalNumerator,
 53378171            radicalDenominator,
 53378172            radicand,
 53378173            radicalSign,
 53378174            rationalNumerator,
 53378175            rationalDenominator,
 53378176            rationalSign,
 53378177            candidateMagnitude,
 53378178            expressionMultiplier: 1UL);
 179    }
 180
 181    private static int CompareSignedRadicalAndRationalSumToMagnitude(
 182        ReadOnlySpan<ulong> radicalNumerator,
 183        ReadOnlySpan<ulong> radicalDenominator,
 184        ReadOnlySpan<ulong> radicand,
 185        int radicalSign,
 186        ReadOnlySpan<ulong> rationalNumerator,
 187        ReadOnlySpan<ulong> rationalDenominator,
 188        int rationalSign,
 189        ReadOnlySpan<ulong> candidate,
 190        ulong expressionMultiplier)
 191    {
 54984192        Span<ulong> multiplier = stackalloc ulong[1];
 54984193        Span<ulong> scaledRadicalNumerator =
 54984194            stackalloc ulong[MaxCoulombComparisonWords];
 54984195        Span<ulong> scaledRationalNumerator =
 54984196            stackalloc ulong[MaxCoulombComparisonWords];
 54984197        Span<ulong> candidateAtDenominator =
 54984198            stackalloc ulong[MaxCoulombComparisonWords];
 54984199        Span<ulong> adjustedRationalNumerator =
 54984200            stackalloc ulong[MaxCoulombComparisonWords];
 54984201        Span<ulong> rationalTerm =
 54984202            stackalloc ulong[MaxCoulombComparisonWords];
 54984203        Span<ulong> radicalCoefficient =
 54984204            stackalloc ulong[MaxCoulombComparisonWords];
 54984205        multiplier[0] = expressionMultiplier;
 54984206        WideArithmetic.MultiplyMagnitudes(
 54984207            radicalNumerator,
 54984208            multiplier,
 54984209            scaledRadicalNumerator);
 54984210        WideArithmetic.MultiplyMagnitudes(
 54984211            rationalNumerator,
 54984212            multiplier,
 54984213            scaledRationalNumerator);
 54984214        WideArithmetic.MultiplyMagnitudes(
 54984215            candidate,
 54984216            rationalDenominator,
 54984217            candidateAtDenominator);
 54984218        AddSignedMagnitudes(
 54984219            scaledRationalNumerator,
 54984220            rationalSign,
 54984221            candidateAtDenominator,
 54984222            -1,
 54984223            adjustedRationalNumerator,
 54984224            out int adjustedRationalSign);
 54984225        WideArithmetic.MultiplyMagnitudes(
 54984226            scaledRadicalNumerator,
 54984227            rationalDenominator,
 54984228            rationalTerm);
 54984229        WideArithmetic.MultiplyMagnitudes(
 54984230            adjustedRationalNumerator,
 54984231            radicalDenominator,
 54984232            radicalCoefficient);
 54984233        return WideArithmetic.GetSignedMagnitudeAndSquareRootSign(
 54984234            TrimMagnitude(rationalTerm),
 54984235            radicalSign,
 54984236            TrimMagnitude(radicalCoefficient),
 54984237            adjustedRationalSign,
 54984238            TrimMagnitude(radicand));
 239    }
 240
 241    private static void GetWeightedFixedSum(
 242        Fixed64 firstFactor,
 243        Fixed64 firstValue,
 244        Fixed64 secondFactor,
 245        Fixed64 secondValue,
 246        Span<ulong> result,
 247        out int resultSign)
 248    {
 1260249        Span<ulong> factorMagnitude = stackalloc ulong[3];
 1260250        Span<ulong> valueMagnitude = stackalloc ulong[3];
 1260251        Span<ulong> first = stackalloc ulong[3];
 1260252        Span<ulong> second = stackalloc ulong[3];
 1260253        SetMagnitude(firstFactor, factorMagnitude);
 1260254        SetMagnitude(firstValue, valueMagnitude);
 1260255        WideArithmetic.MultiplyMagnitudes(
 1260256            factorMagnitude,
 1260257            valueMagnitude,
 1260258            first);
 1260259        SetMagnitude(secondFactor, factorMagnitude);
 1260260        SetMagnitude(secondValue, valueMagnitude);
 1260261        WideArithmetic.MultiplyMagnitudes(
 1260262            factorMagnitude,
 1260263            valueMagnitude,
 1260264            second);
 1260265        AddSignedMagnitudes(
 1260266            first,
 1260267            GetProductSign(firstFactor, firstValue),
 1260268            second,
 1260269            GetProductSign(secondFactor, secondValue),
 1260270            result,
 1260271            out resultSign);
 1260272    }
 273
 274    private static void GetWeightedSignedWideSum(
 275        Signed832 firstFactor,
 276        Fixed64 firstValue,
 277        Signed832 secondFactor,
 278        Fixed64 secondValue,
 279        Span<ulong> result,
 280        out int resultSign)
 281    {
 1302282        Span<ulong> factorMagnitude = stackalloc ulong[13];
 1302283        Span<ulong> valueMagnitude = stackalloc ulong[3];
 1302284        Span<ulong> first = stackalloc ulong[15];
 1302285        Span<ulong> second = stackalloc ulong[15];
 1302286        SetMagnitude(firstFactor, factorMagnitude);
 1302287        SetMagnitude(firstValue, valueMagnitude);
 1302288        WideArithmetic.MultiplyMagnitudes(
 1302289            factorMagnitude,
 1302290            valueMagnitude,
 1302291            first);
 1302292        SetMagnitude(secondFactor, factorMagnitude);
 1302293        SetMagnitude(secondValue, valueMagnitude);
 1302294        WideArithmetic.MultiplyMagnitudes(
 1302295            factorMagnitude,
 1302296            valueMagnitude,
 1302297            second);
 1302298        AddSignedMagnitudes(
 1302299            first,
 1302300            firstFactor.Sign * Math.Sign(firstValue.m_rawValue),
 1302301            second,
 1302302            secondFactor.Sign * Math.Sign(secondValue.m_rawValue),
 1302303            result,
 1302304            out resultSign);
 1302305    }
 306
 307    private static int GetProductSign(Fixed64 first, Fixed64 second) =>
 2520308        Math.Sign(first.m_rawValue) * Math.Sign(second.m_rawValue);
 309
 310    private static ReadOnlySpan<ulong> TrimMagnitude(
 311        ReadOnlySpan<ulong> value)
 312    {
 164952313        int length = value.Length;
 40996574314        while (length > 0 && value[length - 1] == 0UL)
 40831622315            length--;
 164952316        return value.Slice(0, length);
 317    }
 318
 319    private static bool TryGetDiskVelocityDeltas(
 320        in ExactContactResponseOperand3D primaryFirst,
 321        in ExactContactResponseOperand3D primarySecond,
 322        in ExactContactResponseOperand3D secondaryFirst,
 323        in ExactContactResponseOperand3D secondarySecond,
 324        Vector3d primaryTangent,
 325        Vector3d secondaryTangent,
 326        ReadOnlySpan<ulong> primaryNumerator,
 327        int primarySign,
 328        ReadOnlySpan<ulong> secondaryNumerator,
 329        int secondarySign,
 330        ReadOnlySpan<ulong> commonDenominator,
 331        bool rational,
 332        ReadOnlySpan<ulong> radialNumerator,
 333        ReadOnlySpan<ulong> radialDenominator,
 334        ReadOnlySpan<ulong> radicand,
 335        Fixed64 accumulatedPrimaryTangentImpulse,
 336        Fixed64 accumulatedSecondaryTangentImpulse,
 337        out Vector3d firstLinear,
 338        out Vector3d firstAngular,
 339        out Vector3d secondLinear,
 340        out Vector3d secondAngular)
 341    {
 439342        bool resolved = TryGetDiskLinearVelocityDelta(
 439343            primaryFirst.LinearImpulseAxis,
 439344            secondaryFirst.LinearImpulseAxis,
 439345            primaryFirst.InverseMass,
 439346            primaryNumerator,
 439347            primarySign,
 439348            secondaryNumerator,
 439349            secondarySign,
 439350            commonDenominator,
 439351            rational,
 439352            radialNumerator,
 439353            radialDenominator,
 439354            radicand,
 439355            accumulatedPrimaryTangentImpulse,
 439356            accumulatedSecondaryTangentImpulse,
 439357            out firstLinear);
 439358        resolved &= TryGetDiskAngularVelocityDelta(
 439359            primaryFirst.Lever,
 439360            -primaryTangent,
 439361            -secondaryTangent,
 439362            primaryFirst.InverseInertia,
 439363            primaryNumerator,
 439364            primarySign,
 439365            secondaryNumerator,
 439366            secondarySign,
 439367            commonDenominator,
 439368            rational,
 439369            radialNumerator,
 439370            radialDenominator,
 439371            radicand,
 439372            accumulatedPrimaryTangentImpulse,
 439373            accumulatedSecondaryTangentImpulse,
 439374            out firstAngular);
 439375        resolved &= TryGetDiskLinearVelocityDelta(
 439376            primarySecond.LinearImpulseAxis,
 439377            secondarySecond.LinearImpulseAxis,
 439378            primarySecond.InverseMass,
 439379            primaryNumerator,
 439380            primarySign,
 439381            secondaryNumerator,
 439382            secondarySign,
 439383            commonDenominator,
 439384            rational,
 439385            radialNumerator,
 439386            radialDenominator,
 439387            radicand,
 439388            accumulatedPrimaryTangentImpulse,
 439389            accumulatedSecondaryTangentImpulse,
 439390            out secondLinear);
 439391        resolved &= TryGetDiskAngularVelocityDelta(
 439392            primarySecond.Lever,
 439393            primaryTangent,
 439394            secondaryTangent,
 439395            primarySecond.InverseInertia,
 439396            primaryNumerator,
 439397            primarySign,
 439398            secondaryNumerator,
 439399            secondarySign,
 439400            commonDenominator,
 439401            rational,
 439402            radialNumerator,
 439403            radialDenominator,
 439404            radicand,
 439405            accumulatedPrimaryTangentImpulse,
 439406            accumulatedSecondaryTangentImpulse,
 439407            out secondAngular);
 439408        return resolved;
 409    }
 410
 411    private static bool TryGetDiskLinearVelocityDelta(
 412        Vector3d primaryAxis,
 413        Vector3d secondaryAxis,
 414        Fixed64 inverseMass,
 415        ReadOnlySpan<ulong> primaryNumerator,
 416        int primarySign,
 417        ReadOnlySpan<ulong> secondaryNumerator,
 418        int secondarySign,
 419        ReadOnlySpan<ulong> commonDenominator,
 420        bool rational,
 421        ReadOnlySpan<ulong> radialNumerator,
 422        ReadOnlySpan<ulong> radialDenominator,
 423        ReadOnlySpan<ulong> radicand,
 424        Fixed64 accumulatedPrimaryTangentImpulse,
 425        Fixed64 accumulatedSecondaryTangentImpulse,
 426        out Vector3d result)
 427    {
 878428        bool xResolved = TryGetDiskLinearComponent(
 878429            primaryAxis.X,
 878430            secondaryAxis.X,
 878431            inverseMass,
 878432            primaryNumerator,
 878433            primarySign,
 878434            secondaryNumerator,
 878435            secondarySign,
 878436            commonDenominator,
 878437            rational,
 878438            radialNumerator,
 878439            radialDenominator,
 878440            radicand,
 878441            accumulatedPrimaryTangentImpulse,
 878442            accumulatedSecondaryTangentImpulse,
 878443            out Fixed64 x);
 878444        bool yResolved = TryGetDiskLinearComponent(
 878445            primaryAxis.Y,
 878446            secondaryAxis.Y,
 878447            inverseMass,
 878448            primaryNumerator,
 878449            primarySign,
 878450            secondaryNumerator,
 878451            secondarySign,
 878452            commonDenominator,
 878453            rational,
 878454            radialNumerator,
 878455            radialDenominator,
 878456            radicand,
 878457            accumulatedPrimaryTangentImpulse,
 878458            accumulatedSecondaryTangentImpulse,
 878459            out Fixed64 y);
 878460        bool zResolved = TryGetDiskLinearComponent(
 878461            primaryAxis.Z,
 878462            secondaryAxis.Z,
 878463            inverseMass,
 878464            primaryNumerator,
 878465            primarySign,
 878466            secondaryNumerator,
 878467            secondarySign,
 878468            commonDenominator,
 878469            rational,
 878470            radialNumerator,
 878471            radialDenominator,
 878472            radicand,
 878473            accumulatedPrimaryTangentImpulse,
 878474            accumulatedSecondaryTangentImpulse,
 878475            out Fixed64 z);
 878476        result = xResolved & yResolved & zResolved
 878477            ? new Vector3d(x, y, z)
 878478            : default;
 878479        return xResolved & yResolved & zResolved;
 480    }
 481
 482    private static bool TryGetDiskLinearComponent(
 483        Fixed64 primaryAxis,
 484        Fixed64 secondaryAxis,
 485        Fixed64 inverseMass,
 486        ReadOnlySpan<ulong> primaryNumerator,
 487        int primarySign,
 488        ReadOnlySpan<ulong> secondaryNumerator,
 489        int secondarySign,
 490        ReadOnlySpan<ulong> commonDenominator,
 491        bool rational,
 492        ReadOnlySpan<ulong> radialNumerator,
 493        ReadOnlySpan<ulong> radialDenominator,
 494        ReadOnlySpan<ulong> radicand,
 495        Fixed64 accumulatedPrimaryTangentImpulse,
 496        Fixed64 accumulatedSecondaryTangentImpulse,
 497        out Fixed64 result)
 498    {
 2634499        Span<ulong> combined = stackalloc ulong[MaxCoulombWords + 2];
 2634500        GetWeightedSignedSum(
 2634501            primaryAxis,
 2634502            primaryNumerator,
 2634503            primarySign,
 2634504            secondaryAxis,
 2634505            secondaryNumerator,
 2634506            secondarySign,
 2634507            combined,
 2634508            out int combinedSign);
 2634509        if (inverseMass == Fixed64.Zero)
 510        {
 93511            result = Fixed64.Zero;
 93512            return true;
 513        }
 514
 2541515        Span<ulong> inverseMassMagnitude =
 2541516            stackalloc ulong[3];
 2541517        Span<ulong> fixedScale = stackalloc ulong[1];
 2541518        Span<ulong> numerator = stackalloc ulong[MaxCoulombComparisonWords / 2];
 2541519        Span<ulong> denominator =
 2541520            stackalloc ulong[MaxCoulombComparisonWords / 2];
 2541521        SetMagnitude(inverseMass, inverseMassMagnitude);
 2541522        fixedScale.Clear();
 2541523        fixedScale[0] = (ulong)FixedMath.ONE_L;
 2541524        Multiply3(
 2541525            commonDenominator,
 2541526            fixedScale,
 2541527            fixedScale,
 2541528            denominator);
 2541529        if (rational)
 530        {
 1281531            if (combinedSign == 0)
 532            {
 877533                result = Fixed64.Zero;
 877534                return true;
 535            }
 536
 404537            WideArithmetic.MultiplyMagnitudes(
 404538                combined,
 404539                inverseMassMagnitude,
 404540                numerator);
 404541            return Fixed64.TryGetSignedRawRatio(
 404542                numerator,
 404543                denominator,
 404544                combinedSign < 0,
 404545                out result);
 546        }
 547
 1260548        Span<ulong> scaledNumerator =
 1260549            stackalloc ulong[MaxCoulombComparisonWords / 2];
 1260550        Span<ulong> radicalDenominator =
 1260551            stackalloc ulong[MaxCoulombComparisonWords / 2];
 1260552        Span<ulong> cachedCombined = stackalloc ulong[3];
 1260553        Span<ulong> cachedNumerator = stackalloc ulong[4];
 1260554        Span<ulong> cachedDenominator = stackalloc ulong[2];
 1260555        WideArithmetic.MultiplyMagnitudes(
 1260556            combined,
 1260557            inverseMassMagnitude,
 1260558            numerator);
 1260559        WideArithmetic.MultiplyMagnitudes(
 1260560            numerator,
 1260561            radialNumerator,
 1260562            scaledNumerator);
 1260563        WideArithmetic.MultiplyMagnitudes(
 1260564            radialDenominator,
 1260565            fixedScale,
 1260566            radicalDenominator);
 1260567        WideArithmetic.MultiplyMagnitudes(
 1260568            radicalDenominator,
 1260569            fixedScale,
 1260570            denominator);
 1260571        GetWeightedFixedSum(
 1260572            primaryAxis,
 1260573            accumulatedPrimaryTangentImpulse,
 1260574            secondaryAxis,
 1260575            accumulatedSecondaryTangentImpulse,
 1260576            cachedCombined,
 1260577            out int cachedSign);
 1260578        WideArithmetic.MultiplyMagnitudes(
 1260579            cachedCombined,
 1260580            inverseMassMagnitude,
 1260581            cachedNumerator);
 1260582        WideArithmetic.MultiplyMagnitudes(
 1260583            fixedScale,
 1260584            fixedScale,
 1260585            cachedDenominator);
 1260586        return TryGetSignedRadicalAndRationalSum(
 1260587            scaledNumerator,
 1260588            denominator,
 1260589            radicand,
 1260590            combinedSign,
 1260591            cachedNumerator,
 1260592            cachedDenominator,
 1260593            -cachedSign,
 1260594            out result);
 595    }
 596
 597    private static bool TryGetDiskAngularVelocityDelta(
 598        in ExactLever3D lever,
 599        Vector3d primaryAxis,
 600        Vector3d secondaryAxis,
 601        Fixed3x3 inverseInertia,
 602        ReadOnlySpan<ulong> primaryNumerator,
 603        int primarySign,
 604        ReadOnlySpan<ulong> secondaryNumerator,
 605        int secondarySign,
 606        ReadOnlySpan<ulong> commonDenominator,
 607        bool rational,
 608        ReadOnlySpan<ulong> radialNumerator,
 609        ReadOnlySpan<ulong> radialDenominator,
 610        ReadOnlySpan<ulong> radicand,
 611        Fixed64 accumulatedPrimaryTangentImpulse,
 612        Fixed64 accumulatedSecondaryTangentImpulse,
 613        out Vector3d result)
 614    {
 878615        ExactLever3D.GetTransformedCrossProduct(
 878616            lever,
 878617            primaryAxis,
 878618            inverseInertia,
 878619            out Signed832 primaryX,
 878620            out Signed832 primaryY,
 878621            out Signed832 primaryZ);
 878622        ExactLever3D.GetTransformedCrossProduct(
 878623            lever,
 878624            secondaryAxis,
 878625            inverseInertia,
 878626            out Signed832 secondaryX,
 878627            out Signed832 secondaryY,
 878628            out Signed832 secondaryZ);
 878629        Signed320 fixedScaleSquared = WideArithmetic.MultiplySigned192(
 878630            Signed192.One,
 878631            Signed192.One);
 878632        Signed704 transformedDenominator =
 878633            WideArithmetic.MultiplySigned576ToSigned704(
 878634                lever.Denominator,
 878635                fixedScaleSquared);
 636
 878637        bool xResolved = TryGetDiskAngularComponent(
 878638            primaryX,
 878639            secondaryX,
 878640            transformedDenominator,
 878641            primaryNumerator,
 878642            primarySign,
 878643            secondaryNumerator,
 878644            secondarySign,
 878645            commonDenominator,
 878646            rational,
 878647            radialNumerator,
 878648            radialDenominator,
 878649            radicand,
 878650            accumulatedPrimaryTangentImpulse,
 878651            accumulatedSecondaryTangentImpulse,
 878652            out Fixed64 x);
 878653        bool yResolved = TryGetDiskAngularComponent(
 878654            primaryY,
 878655            secondaryY,
 878656            transformedDenominator,
 878657            primaryNumerator,
 878658            primarySign,
 878659            secondaryNumerator,
 878660            secondarySign,
 878661            commonDenominator,
 878662            rational,
 878663            radialNumerator,
 878664            radialDenominator,
 878665            radicand,
 878666            accumulatedPrimaryTangentImpulse,
 878667            accumulatedSecondaryTangentImpulse,
 878668            out Fixed64 y);
 878669        bool zResolved = TryGetDiskAngularComponent(
 878670            primaryZ,
 878671            secondaryZ,
 878672            transformedDenominator,
 878673            primaryNumerator,
 878674            primarySign,
 878675            secondaryNumerator,
 878676            secondarySign,
 878677            commonDenominator,
 878678            rational,
 878679            radialNumerator,
 878680            radialDenominator,
 878681            radicand,
 878682            accumulatedPrimaryTangentImpulse,
 878683            accumulatedSecondaryTangentImpulse,
 878684            out Fixed64 z);
 878685        result = xResolved & yResolved & zResolved
 878686            ? new Vector3d(x, y, z)
 878687            : default;
 878688        return xResolved & yResolved & zResolved;
 689    }
 690
 691    private static bool TryGetDiskAngularComponent(
 692        Signed832 primary,
 693        Signed832 secondary,
 694        Signed704 transformedDenominator,
 695        ReadOnlySpan<ulong> primaryNumerator,
 696        int primarySign,
 697        ReadOnlySpan<ulong> secondaryNumerator,
 698        int secondarySign,
 699        ReadOnlySpan<ulong> commonDenominator,
 700        bool rational,
 701        ReadOnlySpan<ulong> radialNumerator,
 702        ReadOnlySpan<ulong> radialDenominator,
 703        ReadOnlySpan<ulong> radicand,
 704        Fixed64 accumulatedPrimaryTangentImpulse,
 705        Fixed64 accumulatedSecondaryTangentImpulse,
 706        out Fixed64 result)
 707    {
 2634708        Span<ulong> primaryMagnitude = stackalloc ulong[13];
 2634709        Span<ulong> secondaryMagnitude = stackalloc ulong[13];
 2634710        SetMagnitude(primary, primaryMagnitude);
 2634711        SetMagnitude(secondary, secondaryMagnitude);
 2634712        Span<ulong> primaryProduct =
 2634713            stackalloc ulong[MaxCoulombComparisonWords / 2];
 2634714        Span<ulong> secondaryProduct =
 2634715            stackalloc ulong[MaxCoulombComparisonWords / 2];
 2634716        WideArithmetic.MultiplyMagnitudes(
 2634717            primaryMagnitude,
 2634718            primaryNumerator,
 2634719            primaryProduct);
 2634720        WideArithmetic.MultiplyMagnitudes(
 2634721            secondaryMagnitude,
 2634722            secondaryNumerator,
 2634723            secondaryProduct);
 2634724        Span<ulong> combined =
 2634725            stackalloc ulong[MaxCoulombComparisonWords / 2];
 2634726        AddSignedMagnitudes(
 2634727            primaryProduct,
 2634728            primary.Sign * primarySign,
 2634729            secondaryProduct,
 2634730            secondary.Sign * secondarySign,
 2634731            combined,
 2634732            out int combinedSign);
 733
 2634734        Span<ulong> transformedDenominatorMagnitude =
 2634735            stackalloc ulong[11];
 2634736        Span<ulong> fixedScale = stackalloc ulong[1];
 2634737        Span<ulong> denominator =
 2634738            stackalloc ulong[MaxCoulombComparisonWords / 2];
 2634739        SetMagnitude(transformedDenominator, transformedDenominatorMagnitude);
 2634740        fixedScale.Clear();
 2634741        fixedScale[0] = (ulong)FixedMath.ONE_L;
 2634742        Multiply3(
 2634743            transformedDenominatorMagnitude,
 2634744            commonDenominator,
 2634745            fixedScale,
 2634746            denominator);
 2634747        if (rational)
 748        {
 1332749            if (combinedSign == 0)
 750            {
 994751                result = Fixed64.Zero;
 994752                return true;
 753            }
 754
 338755            return Fixed64.TryGetSignedRawRatio(
 338756                combined,
 338757                denominator,
 338758                combinedSign < 0,
 338759                out result);
 760        }
 761
 1302762        Span<ulong> scaledNumerator =
 1302763            stackalloc ulong[MaxCoulombComparisonWords / 2];
 1302764        Span<ulong> radicalDenominator =
 1302765            stackalloc ulong[MaxCoulombComparisonWords / 2];
 1302766        Span<ulong> cachedCombined = stackalloc ulong[15];
 1302767        Span<ulong> cachedDenominator = stackalloc ulong[12];
 1302768        WideArithmetic.MultiplyMagnitudes(
 1302769            combined,
 1302770            radialNumerator,
 1302771            scaledNumerator);
 1302772        WideArithmetic.MultiplyMagnitudes(
 1302773            transformedDenominatorMagnitude,
 1302774            radialDenominator,
 1302775            radicalDenominator);
 1302776        WideArithmetic.MultiplyMagnitudes(
 1302777            radicalDenominator,
 1302778            fixedScale,
 1302779            denominator);
 1302780        GetWeightedSignedWideSum(
 1302781            primary,
 1302782            accumulatedPrimaryTangentImpulse,
 1302783            secondary,
 1302784            accumulatedSecondaryTangentImpulse,
 1302785            cachedCombined,
 1302786            out int cachedSign);
 1302787        WideArithmetic.MultiplyMagnitudes(
 1302788            transformedDenominatorMagnitude,
 1302789            fixedScale,
 1302790            cachedDenominator);
 1302791        return TryGetSignedRadicalAndRationalSum(
 1302792            scaledNumerator,
 1302793            denominator,
 1302794            radicand,
 1302795            combinedSign,
 1302796            cachedCombined,
 1302797            cachedDenominator,
 1302798            -cachedSign,
 1302799            out result);
 800    }
 801
 802    private static void GetWeightedSignedSum(
 803        Fixed64 firstFactor,
 804        ReadOnlySpan<ulong> firstMagnitude,
 805        int firstSign,
 806        Fixed64 secondFactor,
 807        ReadOnlySpan<ulong> secondMagnitude,
 808        int secondSign,
 809        Span<ulong> result,
 810        out int resultSign)
 811    {
 2634812        Span<ulong> factorMagnitude = stackalloc ulong[3];
 2634813        Span<ulong> first = stackalloc ulong[MaxCoulombWords + 2];
 2634814        Span<ulong> second = stackalloc ulong[MaxCoulombWords + 2];
 2634815        SetMagnitude(firstFactor, factorMagnitude);
 2634816        WideArithmetic.MultiplyMagnitudes(
 2634817            factorMagnitude,
 2634818            firstMagnitude,
 2634819            first);
 2634820        SetMagnitude(secondFactor, factorMagnitude);
 2634821        WideArithmetic.MultiplyMagnitudes(
 2634822            factorMagnitude,
 2634823            secondMagnitude,
 2634824            second);
 2634825        AddSignedMagnitudes(
 2634826            first,
 2634827            firstFactor == Fixed64.Zero
 2634828                ? 0
 2634829                : firstFactor < Fixed64.Zero ? -firstSign : firstSign,
 2634830            second,
 2634831            secondFactor == Fixed64.Zero
 2634832                ? 0
 2634833                : secondFactor < Fixed64.Zero ? -secondSign : secondSign,
 2634834            result,
 2634835            out resultSign);
 2634836    }
 837
 838}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/CollisionHandling/Response/Exact/ExactContactResponseKernel.Normal.cs

#LineLine coverage
 1//=======================================================================
 2// ExactContactResponseKernel.Normal.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Runtime.CompilerServices;
 10
 11using FixedMathSharp;
 12using FixedMathSharp.Geometry;
 13
 14namespace Gravitas.CollisionHandling;
 15
 16/// <content>
 17/// Owns unilateral exact normal-response policy and materialization.
 18/// </content>
 19internal static partial class ExactContactResponseKernel
 20{
 21    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 22    internal static bool TryGetNormalResponse(
 23        in ExactContactResponseOperand3D first,
 24        in ExactContactResponseOperand3D second,
 25        Vector3d normal,
 26        Fixed64 restitution,
 27        Fixed64 restitutionVelocityThreshold,
 28        out ExactNormalResponse3D response) =>
 21029        TryGetNormalResponseCore(
 21030            first,
 21031            second,
 21032            normal,
 21033            restitution,
 21034            restitutionVelocityThreshold,
 21035            accumulatedImpulse: Fixed64.Zero,
 21036            positiveImpulseScale: Fixed64.One,
 21037            negativeImpulseScale: Fixed64.One,
 21038            includeAccumulator: false,
 21039            out response);
 40
 41    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 42    internal static bool TryGetAccumulatedNormalResponse(
 43        in ExactContactResponseOperand3D first,
 44        in ExactContactResponseOperand3D second,
 45        Vector3d normal,
 46        Fixed64 restitution,
 47        Fixed64 restitutionVelocityThreshold,
 48        Fixed64 accumulatedImpulse,
 49        Fixed64 positiveImpulseScale,
 50        Fixed64 negativeImpulseScale,
 51        out ExactNormalResponse3D response) =>
 147152        TryGetNormalResponseCore(
 147153            first,
 147154            second,
 147155            normal,
 147156            restitution,
 147157            restitutionVelocityThreshold,
 147158            accumulatedImpulse,
 147159            positiveImpulseScale,
 147160            negativeImpulseScale,
 147161            includeAccumulator: true,
 147162            out response);
 63
 64    [MethodImpl(MethodImplOptions.NoInlining)]
 65    private static bool TryGetNormalResponseCore(
 66        in ExactContactResponseOperand3D first,
 67        in ExactContactResponseOperand3D second,
 68        Vector3d normal,
 69        Fixed64 restitution,
 70        Fixed64 restitutionVelocityThreshold,
 71        Fixed64 accumulatedImpulse,
 72        Fixed64 positiveImpulseScale,
 73        Fixed64 negativeImpulseScale,
 74        bool includeAccumulator,
 75        out ExactNormalResponse3D response)
 76    {
 168177        response = default;
 168178        if (first.Lever.Denominator.Sign == 0
 168179            || second.Lever.Denominator.Sign == 0
 168180            || restitution < Fixed64.Zero
 168181            || restitutionVelocityThreshold < Fixed64.Zero
 168182            || accumulatedImpulse < Fixed64.Zero
 168183            || positiveImpulseScale < Fixed64.Zero
 168184            || negativeImpulseScale < Fixed64.Zero
 168185            || first.InverseMass < Fixed64.Zero
 168186            || second.InverseMass < Fixed64.Zero
 168187            || !normal.IsNormalized())
 88        {
 1389            return false;
 90        }
 91
 166892        ExactLever3D.GetRelativePointVelocityRatio(
 166893            first.LinearVelocity,
 166894            first.AngularVelocity,
 166895            first.Lever,
 166896            second.LinearVelocity,
 166897            second.AngularVelocity,
 166898            second.Lever,
 166899            normal,
 1668100            out Signed832 velocityNumerator,
 1668101            out Signed832 velocityDenominator);
 1668102        int velocitySign =
 1668103            velocityNumerator.Sign * velocityDenominator.Sign;
 1668104        bool hasNormalVelocity = Fixed64.TryGetSignedRawRatio(
 1668105            velocityNumerator,
 1668106            velocityDenominator,
 1668107            0,
 1668108            out Fixed64 normalVelocity);
 1668109        Span<ulong> effectiveNumerator =
 1668110            stackalloc ulong[MaxResponseWords];
 1668111        Span<ulong> effectiveDenominator =
 1668112            stackalloc ulong[MaxResponseWords];
 1668113        GetEffectiveMassRatio(
 1668114            first,
 1668115            second,
 1668116            normal,
 1668117            effectiveNumerator,
 1668118            effectiveDenominator);
 119
 1668120        bool denominatorTooSmall =
 1668121            WideArithmetic.IsZeroMagnitude(effectiveNumerator);
 1668122        if (denominatorTooSmall)
 123        {
 14124            if (velocitySign < 0 && !includeAccumulator)
 10125                return false;
 126
 4127            response = CreateZeroResponse(
 4128                velocitySign < 0,
 4129                hasNormalVelocity,
 4130                normalVelocity,
 4131                includeAccumulator,
 4132                accumulatedImpulse);
 4133            return true;
 134        }
 135
 1654136        if (velocitySign == 0)
 137        {
 34138            response = CreateZeroResponse(
 34139                isClosing: false,
 34140                hasNormalVelocity,
 34141                normalVelocity,
 34142                includeAccumulator,
 34143                accumulatedImpulse);
 34144            return true;
 145        }
 146
 1620147        bool applyRestitution = velocitySign < 0
 1620148            && (!hasNormalVelocity
 1620149                || normalVelocity < -restitutionVelocityThreshold);
 1620150        Fixed64 impulseScale = velocitySign < 0
 1620151            ? positiveImpulseScale
 1620152            : negativeImpulseScale;
 1620153        Span<ulong> impulseNumerator =
 1620154            stackalloc ulong[MaxResponseWords];
 1620155        Span<ulong> impulseDenominator =
 1620156            stackalloc ulong[MaxResponseWords];
 1620157        BuildImpulseRatio(
 1620158            velocityNumerator,
 1620159            velocityDenominator,
 1620160            effectiveNumerator,
 1620161            effectiveDenominator,
 1620162            applyRestitution ? restitution : Fixed64.Zero,
 1620163            impulseScale,
 1620164            impulseNumerator,
 1620165            impulseDenominator);
 1620166        int impulseSign = -velocitySign;
 167
 1620168        Span<ulong> appliedNumerator =
 1620169            stackalloc ulong[MaxResponseWords];
 1620170        Span<ulong> appliedDenominator =
 1620171            stackalloc ulong[MaxResponseWords];
 1620172        appliedNumerator.Clear();
 1620173        appliedDenominator.Clear();
 1620174        ResolveUnilateralImpulse(
 1620175            impulseNumerator,
 1620176            impulseDenominator,
 1620177            impulseSign,
 1620178            accumulatedImpulse,
 1620179            includeAccumulator,
 1620180            appliedNumerator,
 1620181            appliedDenominator,
 1620182            out int appliedSign,
 1620183            out bool useImpulseRatio,
 1620184            out bool hasAccumulatedProjection,
 1620185            out Fixed64 accumulatedProjection);
 186
 1620187        ReadOnlySpan<ulong> resolvedImpulseNumerator =
 1620188            useImpulseRatio ? impulseNumerator : appliedNumerator;
 1620189        ReadOnlySpan<ulong> resolvedImpulseDenominator =
 1620190            useImpulseRatio ? impulseDenominator : appliedDenominator;
 1620191        bool hasAppliedImpulse =
 1620192            !WideArithmetic.IsZeroMagnitude(resolvedImpulseNumerator);
 1620193        bool hasAppliedProjection = Fixed64.TryGetSignedRawRatio(
 1620194            resolvedImpulseNumerator,
 1620195            resolvedImpulseDenominator,
 1620196            appliedSign < 0,
 1620197            out Fixed64 appliedImpulse);
 1620198        bool resolved = TryGetLinearVelocityDelta(
 1620199            first.LinearImpulseAxis,
 1620200            first.InverseMass,
 1620201            resolvedImpulseNumerator,
 1620202            resolvedImpulseDenominator,
 1620203            appliedSign,
 1620204            out Vector3d firstLinear);
 1620205        resolved &= TryGetAngularVelocityDelta(
 1620206            first.Lever,
 1620207            -normal,
 1620208            first.InverseInertia,
 1620209            resolvedImpulseNumerator,
 1620210            resolvedImpulseDenominator,
 1620211            appliedSign,
 1620212            out Vector3d firstAngular);
 1620213        resolved &= TryGetLinearVelocityDelta(
 1620214            second.LinearImpulseAxis,
 1620215            second.InverseMass,
 1620216            resolvedImpulseNumerator,
 1620217            resolvedImpulseDenominator,
 1620218            appliedSign,
 1620219            out Vector3d secondLinear);
 1620220        resolved &= TryGetAngularVelocityDelta(
 1620221            second.Lever,
 1620222            normal,
 1620223            second.InverseInertia,
 1620224            resolvedImpulseNumerator,
 1620225            resolvedImpulseDenominator,
 1620226            appliedSign,
 1620227            out Vector3d secondAngular);
 1620228        if (!resolved)
 13229            return false;
 230
 1607231        response = new ExactNormalResponse3D(
 1607232            velocitySign < 0,
 1607233            hasAppliedImpulse,
 1607234            firstLinear,
 1607235            firstAngular,
 1607236            secondLinear,
 1607237            secondAngular,
 1607238            hasNormalVelocity,
 1607239            normalVelocity,
 1607240            hasAppliedProjection,
 1607241            appliedImpulse,
 1607242            includeAccumulator && hasAccumulatedProjection,
 1607243            accumulatedProjection);
 1607244        return true;
 245    }
 246
 247    private static ExactNormalResponse3D CreateZeroResponse(
 248        bool isClosing,
 249        bool hasNormalVelocity,
 250        Fixed64 normalVelocity,
 251        bool includeAccumulator,
 252        Fixed64 accumulatedImpulse) =>
 38253        new(
 38254            isClosing,
 38255            hasAppliedImpulse: false,
 38256            Vector3d.Zero,
 38257            Vector3d.Zero,
 38258            Vector3d.Zero,
 38259            Vector3d.Zero,
 38260            hasNormalVelocity,
 38261            normalVelocity,
 38262            hasAppliedImpulseProjection: true,
 38263            Fixed64.Zero,
 38264            includeAccumulator,
 38265            accumulatedImpulse);
 266
 267    private static void GetEffectiveMassRatio(
 268        in ExactContactResponseOperand3D first,
 269        in ExactContactResponseOperand3D second,
 270        Vector3d normal,
 271        Span<ulong> resultNumerator,
 272        Span<ulong> resultDenominator)
 273    {
 2707274        Signed192 normalSquared = GetRawDot(normal, normal);
 275
 2707276        Signed192 firstAllowed =
 2707277            GetRawDot(first.LinearImpulseAxis, -normal);
 2707278        Signed192 secondAllowed =
 2707279            GetRawDot(second.LinearImpulseAxis, normal);
 2707280        Signed320 linearNumerator = default;
 2707281        if (firstAllowed.Sign > 0
 2707282            && first.InverseMass > Fixed64.Zero)
 283        {
 2506284            linearNumerator = WideArithmetic.MultiplySigned192(
 2506285                firstAllowed,
 2506286                Signed192.Raw(first.InverseMass));
 287        }
 2707288        if (secondAllowed.Sign > 0
 2707289            && second.InverseMass > Fixed64.Zero)
 290        {
 2480291            linearNumerator = WideArithmetic.AddSigned320(
 2480292                linearNumerator,
 2480293                WideArithmetic.MultiplySigned192(
 2480294                    secondAllowed,
 2480295                    Signed192.Raw(second.InverseMass)));
 296        }
 297
 2707298        ExactLever3D.GetCrossProductQuadraticFormRatio(
 2707299            first.Lever,
 2707300            normal,
 2707301            first.InverseInertia,
 2707302            out Signed832 firstAngularNumerator,
 2707303            out Signed832 firstAngularDenominator);
 2707304        ExactLever3D.GetCrossProductQuadraticFormRatio(
 2707305            second.Lever,
 2707306            normal,
 2707307            second.InverseInertia,
 2707308            out Signed832 secondAngularNumerator,
 2707309            out Signed832 secondAngularDenominator);
 310
 2707311        Span<ulong> linearNumeratorMagnitude =
 2707312            stackalloc ulong[MaxResponseWords];
 2707313        Span<ulong> linearDenominatorMagnitude =
 2707314            stackalloc ulong[MaxResponseWords];
 2707315        Span<ulong> firstNumeratorMagnitude =
 2707316            stackalloc ulong[MaxResponseWords];
 2707317        Span<ulong> firstDenominatorMagnitude =
 2707318            stackalloc ulong[MaxResponseWords];
 2707319        Span<ulong> secondNumeratorMagnitude =
 2707320            stackalloc ulong[MaxResponseWords];
 2707321        Span<ulong> secondDenominatorMagnitude =
 2707322            stackalloc ulong[MaxResponseWords];
 2707323        SetMagnitude(linearNumerator, linearNumeratorMagnitude);
 2707324        SetMagnitude(normalSquared, linearDenominatorMagnitude);
 2707325        SetNonNegativeRatio(
 2707326            firstAngularNumerator,
 2707327            firstAngularDenominator,
 2707328            firstNumeratorMagnitude,
 2707329            firstDenominatorMagnitude);
 2707330        SetNonNegativeRatio(
 2707331            secondAngularNumerator,
 2707332            secondAngularDenominator,
 2707333            secondNumeratorMagnitude,
 2707334            secondDenominatorMagnitude);
 335
 2707336        Span<ulong> temporary = stackalloc ulong[MaxResponseWords];
 2707337        Multiply3(
 2707338            linearDenominatorMagnitude,
 2707339            firstDenominatorMagnitude,
 2707340            secondDenominatorMagnitude,
 2707341            resultDenominator);
 2707342        Multiply3(
 2707343            linearNumeratorMagnitude,
 2707344            firstDenominatorMagnitude,
 2707345            secondDenominatorMagnitude,
 2707346            resultNumerator);
 2707347        Multiply3(
 2707348            firstNumeratorMagnitude,
 2707349            linearDenominatorMagnitude,
 2707350            secondDenominatorMagnitude,
 2707351            temporary);
 2707352        WideArithmetic.AddMagnitudeInto(temporary, resultNumerator);
 2707353        Multiply3(
 2707354            secondNumeratorMagnitude,
 2707355            linearDenominatorMagnitude,
 2707356            firstDenominatorMagnitude,
 2707357            temporary);
 2707358        WideArithmetic.AddMagnitudeInto(temporary, resultNumerator);
 2707359    }
 360
 361    private static void BuildImpulseRatio(
 362        Signed832 velocityNumerator,
 363        Signed832 velocityDenominator,
 364        ReadOnlySpan<ulong> effectiveNumerator,
 365        ReadOnlySpan<ulong> effectiveDenominator,
 366        Fixed64 restitution,
 367        Fixed64 impulseScale,
 368        Span<ulong> numerator,
 369        Span<ulong> denominator)
 370    {
 2180371        Span<ulong> velocityNumeratorMagnitude =
 2180372            stackalloc ulong[MaxResponseWords];
 2180373        Span<ulong> velocityDenominatorMagnitude =
 2180374            stackalloc ulong[MaxResponseWords];
 2180375        Span<ulong> restitutionMagnitude =
 2180376            stackalloc ulong[MaxResponseWords];
 2180377        Span<ulong> scaleMagnitude =
 2180378            stackalloc ulong[MaxResponseWords];
 2180379        Span<ulong> fixedScale =
 2180380            stackalloc ulong[MaxResponseWords];
 2180381        SetMagnitude(velocityNumerator, velocityNumeratorMagnitude);
 2180382        SetMagnitude(velocityDenominator, velocityDenominatorMagnitude);
 2180383        SetUnsignedSum(
 2180384            (ulong)FixedMath.ONE_L,
 2180385            (ulong)restitution.m_rawValue,
 2180386            restitutionMagnitude);
 2180387        SetMagnitude(impulseScale, scaleMagnitude);
 2180388        fixedScale.Clear();
 2180389        fixedScale[0] = (ulong)FixedMath.ONE_L;
 390
 2180391        Multiply4(
 2180392            velocityNumeratorMagnitude,
 2180393            effectiveDenominator,
 2180394            restitutionMagnitude,
 2180395            scaleMagnitude,
 2180396            numerator);
 2180397        Multiply3(
 2180398            velocityDenominatorMagnitude,
 2180399            effectiveNumerator,
 2180400            fixedScale,
 2180401            denominator);
 2180402    }
 403
 404    private static void ResolveUnilateralImpulse(
 405        ReadOnlySpan<ulong> impulseNumerator,
 406        ReadOnlySpan<ulong> impulseDenominator,
 407        int impulseSign,
 408        Fixed64 accumulatedImpulse,
 409        bool includeAccumulator,
 410        Span<ulong> appliedNumerator,
 411        Span<ulong> appliedDenominator,
 412        out int appliedSign,
 413        out bool useImpulseRatio,
 414        out bool hasAccumulatedProjection,
 415        out Fixed64 accumulatedProjection)
 416    {
 1620417        appliedNumerator.Clear();
 1620418        appliedDenominator.Clear();
 1620419        useImpulseRatio = false;
 1620420        hasAccumulatedProjection = false;
 1620421        accumulatedProjection = default;
 1620422        if (!includeAccumulator)
 423        {
 189424            if (impulseSign <= 0)
 425            {
 4426                appliedDenominator[0] = 1UL;
 4427                appliedSign = 0;
 4428                return;
 429            }
 430
 185431            appliedSign = 1;
 185432            useImpulseRatio = true;
 185433            return;
 434        }
 435
 1431436        Span<ulong> accumulatorMagnitude =
 1431437            stackalloc ulong[MaxResponseWords];
 1431438        Span<ulong> accumulatedAtImpulseDenominator =
 1431439            stackalloc ulong[MaxResponseWords];
 1431440        SetMagnitude(accumulatedImpulse, accumulatorMagnitude);
 1431441        WideArithmetic.MultiplyMagnitudes(
 1431442            accumulatorMagnitude,
 1431443            impulseDenominator,
 1431444            accumulatedAtImpulseDenominator);
 1431445        if (impulseSign < 0
 1431446            && WideArithmetic.CompareMagnitudeEqualLength(
 1431447                impulseNumerator,
 1431448                accumulatedAtImpulseDenominator) >= 0)
 449        {
 359450            accumulatorMagnitude.CopyTo(appliedNumerator);
 359451            appliedDenominator[0] = 1UL;
 359452            appliedSign = WideArithmetic.IsZeroMagnitude(
 359453                accumulatorMagnitude)
 359454                ? 0
 359455                : -1;
 359456            hasAccumulatedProjection = true;
 359457            accumulatedProjection = Fixed64.Zero;
 359458            return;
 459        }
 460
 1072461        Span<ulong> completedAccumulator =
 1072462            stackalloc ulong[MaxResponseWords];
 1072463        if (impulseSign > 0)
 464        {
 876465            accumulatedAtImpulseDenominator.CopyTo(completedAccumulator);
 876466            WideArithmetic.AddMagnitudeInto(
 876467                impulseNumerator,
 876468                completedAccumulator);
 469        }
 470        else
 471        {
 196472            WideArithmetic.SubtractEqualMagnitudes(
 196473                accumulatedAtImpulseDenominator,
 196474                impulseNumerator,
 196475                completedAccumulator);
 476        }
 477
 1072478        hasAccumulatedProjection = Fixed64.TryGetSignedRawRatio(
 1072479            completedAccumulator,
 1072480            impulseDenominator,
 1072481            negative: false,
 1072482            out accumulatedProjection);
 1072483        appliedSign = impulseSign;
 1072484        useImpulseRatio = true;
 1072485    }
 486
 487    private static bool TryGetLinearVelocityDelta(
 488        Vector3d impulseAxis,
 489        Fixed64 inverseMass,
 490        ReadOnlySpan<ulong> impulseNumerator,
 491        ReadOnlySpan<ulong> impulseDenominator,
 492        int impulseSign,
 493        out Vector3d result)
 494    {
 3346495        if (inverseMass == Fixed64.Zero
 3346496            || impulseAxis == Vector3d.Zero
 3346497            || WideArithmetic.IsZeroMagnitude(impulseNumerator))
 498        {
 978499            result = Vector3d.Zero;
 978500            return true;
 501        }
 502
 2368503        bool xResolved = TryGetLinearComponent(
 2368504            impulseAxis.X,
 2368505            inverseMass,
 2368506            impulseNumerator,
 2368507            impulseDenominator,
 2368508            impulseSign,
 2368509            out Fixed64 x);
 2368510        bool yResolved = TryGetLinearComponent(
 2368511            impulseAxis.Y,
 2368512            inverseMass,
 2368513            impulseNumerator,
 2368514            impulseDenominator,
 2368515            impulseSign,
 2368516            out Fixed64 y);
 2368517        bool zResolved = TryGetLinearComponent(
 2368518            impulseAxis.Z,
 2368519            inverseMass,
 2368520            impulseNumerator,
 2368521            impulseDenominator,
 2368522            impulseSign,
 2368523            out Fixed64 z);
 2368524        result = xResolved & yResolved & zResolved
 2368525            ? new Vector3d(x, y, z)
 2368526            : default;
 2368527        return xResolved & yResolved & zResolved;
 528    }
 529
 530    private static bool TryGetLinearComponent(
 531        Fixed64 axis,
 532        Fixed64 inverseMass,
 533        ReadOnlySpan<ulong> impulseNumerator,
 534        ReadOnlySpan<ulong> impulseDenominator,
 535        int impulseSign,
 536        out Fixed64 result)
 537    {
 7104538        if (axis == Fixed64.Zero)
 539        {
 4578540            result = Fixed64.Zero;
 4578541            return true;
 542        }
 543
 2526544        Span<ulong> axisMagnitude =
 2526545            stackalloc ulong[MaxResponseWords];
 2526546        Span<ulong> inverseMassMagnitude =
 2526547            stackalloc ulong[MaxResponseWords];
 2526548        Span<ulong> fixedScale =
 2526549            stackalloc ulong[MaxResponseWords];
 2526550        Span<ulong> numerator =
 2526551            stackalloc ulong[MaxResponseWords];
 2526552        Span<ulong> denominator =
 2526553            stackalloc ulong[MaxResponseWords];
 2526554        SetMagnitude(axis, axisMagnitude);
 2526555        SetMagnitude(inverseMass, inverseMassMagnitude);
 2526556        fixedScale.Clear();
 2526557        fixedScale[0] = (ulong)FixedMath.ONE_L;
 2526558        Multiply3(
 2526559            axisMagnitude,
 2526560            inverseMassMagnitude,
 2526561            impulseNumerator,
 2526562            numerator);
 2526563        Multiply3(
 2526564            impulseDenominator,
 2526565            fixedScale,
 2526566            fixedScale,
 2526567            denominator);
 2526568        return Fixed64.TryGetSignedRawRatio(
 2526569            numerator,
 2526570            denominator,
 2526571            (axis < Fixed64.Zero) != (impulseSign < 0),
 2526572            out result);
 573    }
 574
 575    private static bool TryGetAngularVelocityDelta(
 576        in ExactLever3D lever,
 577        Vector3d impulseAxis,
 578        Fixed3x3 inverseInertia,
 579        ReadOnlySpan<ulong> impulseNumerator,
 580        ReadOnlySpan<ulong> impulseDenominator,
 581        int impulseSign,
 582        out Vector3d result)
 583    {
 3346584        if (WideArithmetic.IsZeroMagnitude(impulseNumerator))
 585        {
 738586            result = Vector3d.Zero;
 738587            return true;
 588        }
 589
 2608590        ExactLever3D.GetTransformedCrossProduct(
 2608591            lever,
 2608592            impulseAxis,
 2608593            inverseInertia,
 2608594            out Signed832 transformedX,
 2608595            out Signed832 transformedY,
 2608596            out Signed832 transformedZ);
 2608597        Signed320 fixedScaleSquared = WideArithmetic.MultiplySigned192(
 2608598            Signed192.One,
 2608599            Signed192.One);
 2608600        Signed704 transformedDenominator =
 2608601            WideArithmetic.MultiplySigned576ToSigned704(
 2608602                lever.Denominator,
 2608603                fixedScaleSquared);
 2608604        bool xResolved = TryGetAngularComponent(
 2608605            transformedX,
 2608606            transformedDenominator,
 2608607            impulseNumerator,
 2608608            impulseDenominator,
 2608609            impulseSign,
 2608610            out Fixed64 x);
 2608611        bool yResolved = TryGetAngularComponent(
 2608612            transformedY,
 2608613            transformedDenominator,
 2608614            impulseNumerator,
 2608615            impulseDenominator,
 2608616            impulseSign,
 2608617            out Fixed64 y);
 2608618        bool zResolved = TryGetAngularComponent(
 2608619            transformedZ,
 2608620            transformedDenominator,
 2608621            impulseNumerator,
 2608622            impulseDenominator,
 2608623            impulseSign,
 2608624            out Fixed64 z);
 2608625        result = xResolved & yResolved & zResolved
 2608626            ? new Vector3d(x, y, z)
 2608627            : default;
 2608628        return xResolved & yResolved & zResolved;
 629    }
 630
 631    private static bool TryGetAngularComponent(
 632        Signed832 transformed,
 633        Signed704 transformedDenominator,
 634        ReadOnlySpan<ulong> impulseNumerator,
 635        ReadOnlySpan<ulong> impulseDenominator,
 636        int impulseSign,
 637        out Fixed64 result)
 638    {
 7824639        if (transformed.Sign == 0)
 640        {
 5682641            result = Fixed64.Zero;
 5682642            return true;
 643        }
 644
 2142645        Span<ulong> transformedMagnitude =
 2142646            stackalloc ulong[MaxResponseWords];
 2142647        Span<ulong> transformedDenominatorMagnitude =
 2142648            stackalloc ulong[MaxResponseWords];
 2142649        Span<ulong> fixedScale =
 2142650            stackalloc ulong[MaxResponseWords];
 2142651        Span<ulong> numerator =
 2142652            stackalloc ulong[MaxResponseWords];
 2142653        Span<ulong> denominator =
 2142654            stackalloc ulong[MaxResponseWords];
 2142655        SetMagnitude(transformed, transformedMagnitude);
 2142656        SetMagnitude(transformedDenominator, transformedDenominatorMagnitude);
 2142657        fixedScale.Clear();
 2142658        fixedScale[0] = (ulong)FixedMath.ONE_L;
 2142659        WideArithmetic.MultiplyMagnitudes(
 2142660            transformedMagnitude,
 2142661            impulseNumerator,
 2142662            numerator);
 2142663        Multiply3(
 2142664            transformedDenominatorMagnitude,
 2142665            impulseDenominator,
 2142666            fixedScale,
 2142667            denominator);
 2142668        return Fixed64.TryGetSignedRawRatio(
 2142669            numerator,
 2142670            denominator,
 2142671            (transformed.Sign < 0) != (impulseSign < 0),
 2142672            out result);
 673    }
 674
 675    private static Signed192 GetRawDot(Vector3d left, Vector3d right) =>
 8121676        WideGeometry.GetDifferenceDotProduct3D(
 8121677            left.X,
 8121678            Fixed64.Zero,
 8121679            left.Y,
 8121680            Fixed64.Zero,
 8121681            left.Z,
 8121682            Fixed64.Zero,
 8121683            right.X,
 8121684            Fixed64.Zero,
 8121685            right.Y,
 8121686            Fixed64.Zero,
 8121687            right.Z,
 8121688            Fixed64.Zero);
 689
 690    private static void SetNonNegativeRatio(
 691        Signed832 numerator,
 692        Signed832 denominator,
 693        Span<ulong> numeratorMagnitude,
 694        Span<ulong> denominatorMagnitude)
 695    {
 5414696        numeratorMagnitude.Clear();
 5414697        denominatorMagnitude.Clear();
 5414698        if (numerator.Sign <= 0)
 699        {
 1158700            denominatorMagnitude[0] = 1UL;
 1158701            return;
 702        }
 703
 4256704        SetMagnitude(numerator, numeratorMagnitude);
 4256705        SetMagnitude(denominator, denominatorMagnitude);
 4256706    }
 707
 708    private static void SetUnsignedSum(
 709        ulong first,
 710        ulong second,
 711        Span<ulong> result)
 712    {
 2180713        result.Clear();
 2180714        result[0] = unchecked(first + second);
 2180715    }
 716
 717    private static void SetMagnitude(
 718        Fixed64 value,
 719        Span<ulong> result)
 720    {
 27143721        result.Clear();
 27143722        WideArithmetic.GetMagnitude(
 27143723            Signed192.Raw(value),
 27143724            out result[2],
 27143725            out result[1],
 27143726            out result[0]);
 27143727    }
 728
 729    private static void SetMagnitude(
 730        Signed192 value,
 731        Span<ulong> result)
 732    {
 2707733        result.Clear();
 2707734        WideArithmetic.GetMagnitude(
 2707735            value,
 2707736            out result[2],
 2707737            out result[1],
 2707738            out result[0]);
 2707739    }
 740
 741    private static void SetMagnitude(
 742        Signed320 value,
 743        Span<ulong> result)
 744    {
 2707745        result.Clear();
 2707746        WideArithmetic.GetMagnitude(
 2707747            value,
 2707748            out result[4],
 2707749            out result[3],
 2707750            out result[2],
 2707751            out result[1],
 2707752            out result[0]);
 2707753    }
 754
 755    private static void SetMagnitude(
 756        Signed704 value,
 757        Span<ulong> result)
 758    {
 4776759        result.Clear();
 4776760        WideArithmetic.GetMagnitude(value, result);
 4776761    }
 762
 763    private static void SetMagnitude(
 764        Signed832 value,
 765        Span<ulong> result)
 766    {
 22886767        result.Clear();
 22886768        WideArithmetic.GetMagnitude(value, result);
 22886769    }
 770
 771    private static void Multiply3(
 772        ReadOnlySpan<ulong> first,
 773        ReadOnlySpan<ulong> second,
 774        ReadOnlySpan<ulong> third,
 775        Span<ulong> result)
 776    {
 25377777        Span<ulong> temporary =
 25377778            stackalloc ulong[result.Length];
 25377779        WideArithmetic.MultiplyMagnitudes(first, second, temporary);
 25377780        WideArithmetic.MultiplyMagnitudes(temporary, third, result);
 25377781    }
 782
 783    private static void Multiply4(
 784        ReadOnlySpan<ulong> first,
 785        ReadOnlySpan<ulong> second,
 786        ReadOnlySpan<ulong> third,
 787        ReadOnlySpan<ulong> fourth,
 788        Span<ulong> result)
 789    {
 2180790        Span<ulong> firstProduct =
 2180791            stackalloc ulong[MaxResponseWords];
 2180792        Span<ulong> secondProduct =
 2180793            stackalloc ulong[MaxResponseWords];
 2180794        WideArithmetic.MultiplyMagnitudes(first, second, firstProduct);
 2180795        WideArithmetic.MultiplyMagnitudes(third, fourth, secondProduct);
 2180796        WideArithmetic.MultiplyMagnitudes(
 2180797            firstProduct,
 2180798            secondProduct,
 2180799            result);
 2180800    }
 801
 802}

Methods/Properties

TryGetCoulombLineResponse(Gravitas.CollisionHandling.ExactNormalConstraint3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactCoulombResponse3D&)
TryGetCoulombDiskResponse(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactCoulombResponse3D&)
TryGetCoulombDiskResponse(Gravitas.CollisionHandling.ExactNormalConstraint3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactCoulombResponse3D&)
TryGetCoulombDiskResponseCore(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactCoulombResponse3D&)
AreCoulombDiskInputsValid(FixedMathSharp.Vector3d,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TryGetCompletedNormalAccumulatorRatio(Gravitas.CollisionHandling.ExactNormalConstraint3D&,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>)
GetBilateralImpulseRatio(Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>,System.Int32&)
GetFrictionLimit(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>)
AddFixedToRatio(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Fixed64,System.Span`1<System.UInt64>,System.Int32&)
SubtractFixedFromRatio(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Fixed64,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>,System.Int32&)
CompareRatios(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>)
IsVectorWithinLimit(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>)
AddSignedMagnitudes(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.Span`1<System.UInt64>,System.Int32&)
TryGetSignedRatioOverSquareRoot(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Boolean,FixedMathSharp.Fixed64&)
CompareRatioOverSquareRoot(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.UInt64)
CompareRatioOverSquareRoot(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.UInt64)
HaveMatchingParticipants(Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&)
IsRadialProjectionEqualToFixed(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64)
TryGetSignedRadicalAndRationalSum(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Fixed64&)
CompareSignedRadicalAndRationalSumToMagnitude(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.UInt64)
CompareSignedRadicalAndRationalSumToMagnitude(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.UInt64)
GetWeightedFixedSum(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Span`1<System.UInt64>,System.Int32&)
GetWeightedSignedWideSum(FixedMathSharp.Signed832,FixedMathSharp.Fixed64,FixedMathSharp.Signed832,FixedMathSharp.Fixed64,System.Span`1<System.UInt64>,System.Int32&)
GetProductSign(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TrimMagnitude(System.ReadOnlySpan`1<System.UInt64>)
TryGetDiskVelocityDeltas(Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Boolean,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&)
TryGetDiskLinearVelocityDelta(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Boolean,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&)
TryGetDiskLinearComponent(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Boolean,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
TryGetDiskAngularVelocityDelta(Gravitas.CollisionHandling.ExactLever3D&,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed3x3,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Boolean,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&)
TryGetDiskAngularComponent(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed704,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Boolean,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
GetWeightedSignedSum(FixedMathSharp.Fixed64,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.Span`1<System.UInt64>,System.Int32&)
TryGetNormalResponse(Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactNormalResponse3D&)
TryGetAccumulatedNormalResponse(Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactNormalResponse3D&)
TryGetNormalResponseCore(Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean,Gravitas.CollisionHandling.ExactNormalResponse3D&)
CreateZeroResponse(System.Boolean,System.Boolean,FixedMathSharp.Fixed64,System.Boolean,FixedMathSharp.Fixed64)
GetEffectiveMassRatio(Gravitas.CollisionHandling.ExactContactResponseOperand3D&,Gravitas.CollisionHandling.ExactContactResponseOperand3D&,FixedMathSharp.Vector3d,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>)
BuildImpulseRatio(FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>)
ResolveUnilateralImpulse(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Fixed64,System.Boolean,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>,System.Int32&,System.Boolean&,System.Boolean&,FixedMathSharp.Fixed64&)
TryGetLinearVelocityDelta(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Vector3d&)
TryGetLinearComponent(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Fixed64&)
TryGetAngularVelocityDelta(Gravitas.CollisionHandling.ExactLever3D&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed3x3,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Vector3d&)
TryGetAngularComponent(FixedMathSharp.Signed832,FixedMathSharp.Signed704,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Fixed64&)
GetRawDot(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
SetNonNegativeRatio(FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>)
SetUnsignedSum(System.UInt64,System.UInt64,System.Span`1<System.UInt64>)
SetMagnitude(FixedMathSharp.Fixed64,System.Span`1<System.UInt64>)
SetMagnitude(FixedMathSharp.Signed192,System.Span`1<System.UInt64>)
SetMagnitude(FixedMathSharp.Signed320,System.Span`1<System.UInt64>)
SetMagnitude(FixedMathSharp.Signed704,System.Span`1<System.UInt64>)
SetMagnitude(FixedMathSharp.Signed832,System.Span`1<System.UInt64>)
Multiply3(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Span`1<System.UInt64>)
Multiply4(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Span`1<System.UInt64>)