< Summary

Information
Class: Gravitas.CollisionHandling.ContactNormalImpulse2D
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/CollisionHandling/Response/2D/ContactNormalImpulse2D.cs
Line coverage
100%
Covered lines: 380
Uncovered lines: 0
Coverable lines: 380
Total lines: 717
Line coverage: 100%
Branch coverage
100%
Covered branches: 90
Total branches: 90
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/CollisionHandling/Response/2D/ContactNormalImpulse2D.cs

#LineLine coverage
 1//=======================================================================
 2// ContactNormalImpulse2D.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 FixedMathSharp;
 9using FixedMathSharp.Geometry;
 10using System.Runtime.CompilerServices;
 11
 12namespace Gravitas.CollisionHandling;
 13
 14/// <summary>
 15/// Side-effect-free 2D contact-normal impulse result for two participants.
 16/// </summary>
 17internal readonly struct ContactNormalImpulseResult2D
 18{
 19    public ContactNormalImpulseResult2D(
 20        Fixed64 normalVelocity,
 21        Fixed64 impulseScalar,
 22        Vector2d linearVelocityDeltaA,
 23        Fixed64 angularVelocityDeltaA,
 24        Vector2d linearVelocityDeltaB,
 25        Fixed64 angularVelocityDeltaB)
 26        : this(
 27            normalVelocity,
 28            impulseScalar,
 29            impulseScalar,
 30            linearVelocityDeltaA,
 31            angularVelocityDeltaA,
 32            linearVelocityDeltaB,
 33            angularVelocityDeltaB)
 34    {
 35    }
 36
 37    public ContactNormalImpulseResult2D(
 38        Fixed64 normalVelocity,
 39        Fixed64 impulseScalar,
 40        Fixed64 appliedImpulseScalar,
 41        Vector2d linearVelocityDeltaA,
 42        Fixed64 angularVelocityDeltaA,
 43        Vector2d linearVelocityDeltaB,
 44        Fixed64 angularVelocityDeltaB,
 45        bool hasRepresentableNormalVelocity = true,
 46        bool hasRepresentableAppliedImpulse = true,
 47        bool hasRepresentableAccumulatedImpulse = true)
 48    {
 49        NormalVelocity = normalVelocity;
 50        ImpulseScalar = impulseScalar;
 51        AppliedImpulseScalar = appliedImpulseScalar;
 52        LinearVelocityDeltaA = linearVelocityDeltaA;
 53        AngularVelocityDeltaA = angularVelocityDeltaA;
 54        LinearVelocityDeltaB = linearVelocityDeltaB;
 55        AngularVelocityDeltaB = angularVelocityDeltaB;
 56        HasRepresentableNormalVelocity = hasRepresentableNormalVelocity;
 57        HasRepresentableAppliedImpulse = hasRepresentableAppliedImpulse;
 58        HasRepresentableAccumulatedImpulse =
 59            hasRepresentableAccumulatedImpulse;
 60    }
 61
 62    public Fixed64 NormalVelocity { get; }
 63
 64    public Fixed64 ImpulseScalar { get; }
 65
 66    public Fixed64 AppliedImpulseScalar { get; }
 67
 68    public bool HasRepresentableNormalVelocity { get; }
 69
 70    public bool HasRepresentableAppliedImpulse { get; }
 71
 72    public bool HasRepresentableAccumulatedImpulse { get; }
 73
 74    public Vector2d LinearVelocityDeltaA { get; }
 75
 76    public Fixed64 AngularVelocityDeltaA { get; }
 77
 78    public Vector2d LinearVelocityDeltaB { get; }
 79
 80    public Fixed64 AngularVelocityDeltaB { get; }
 81}
 82
 83/// <summary>
 84/// Side-effect-free 2D velocity deltas for a normal response whose impulse
 85/// scalar does not need to be representable.
 86/// </summary>
 87internal readonly struct ContactNormalVelocityDeltaResult2D
 88{
 89    public ContactNormalVelocityDeltaResult2D(
 90        Fixed64 normalVelocity,
 91        Vector2d linearVelocityDeltaA,
 92        Fixed64 angularVelocityDeltaA,
 93        Vector2d linearVelocityDeltaB,
 94        Fixed64 angularVelocityDeltaB)
 95        : this(
 96            normalVelocity,
 97            linearVelocityDeltaA,
 98            angularVelocityDeltaA,
 99            linearVelocityDeltaB,
 100            angularVelocityDeltaB,
 101            normalVelocity < Fixed64.Zero,
 102            hasRepresentableNormalVelocity: true)
 103    {
 104    }
 105
 106    public ContactNormalVelocityDeltaResult2D(
 107        Fixed64 normalVelocity,
 108        Vector2d linearVelocityDeltaA,
 109        Fixed64 angularVelocityDeltaA,
 110        Vector2d linearVelocityDeltaB,
 111        Fixed64 angularVelocityDeltaB,
 112        bool isClosing,
 113        bool hasRepresentableNormalVelocity)
 114    {
 115        NormalVelocity = normalVelocity;
 116        LinearVelocityDeltaA = linearVelocityDeltaA;
 117        AngularVelocityDeltaA = angularVelocityDeltaA;
 118        LinearVelocityDeltaB = linearVelocityDeltaB;
 119        AngularVelocityDeltaB = angularVelocityDeltaB;
 120        IsClosing = isClosing;
 121        HasRepresentableNormalVelocity = hasRepresentableNormalVelocity;
 122    }
 123
 124    public Fixed64 NormalVelocity { get; }
 125
 126    public bool IsClosing { get; }
 127
 128    public bool HasRepresentableNormalVelocity { get; }
 129
 130    public Vector2d LinearVelocityDeltaA { get; }
 131
 132    public Fixed64 AngularVelocityDeltaA { get; }
 133
 134    public Vector2d LinearVelocityDeltaB { get; }
 135
 136    public Fixed64 AngularVelocityDeltaB { get; }
 137}
 138
 139/// <summary>
 140/// Calculates allocation-free 2D contact-point normal response without mutating either body.
 141/// </summary>
 142internal static class ContactNormalImpulse2D
 143{
 144    internal static bool TryCalculateVelocityDeltas(
 145        SolidBody2D? bodyA,
 146        Vector2d linearVelocityA,
 147        Fixed64 angularVelocityA,
 148        Vector2d relativeContactPointA,
 149        SolidBody2D? bodyB,
 150        Vector2d linearVelocityB,
 151        Fixed64 angularVelocityB,
 152        Vector2d relativeContactPointB,
 153        Vector2d normal,
 154        Fixed64 restitution,
 155        Fixed64 restitutionVelocityThreshold,
 156        out ContactNormalVelocityDeltaResult2D result)
 157    {
 39158        result = default;
 39159        if (!TryComputeNormalVelocity(
 39160                linearVelocityA,
 39161                angularVelocityA,
 39162                relativeContactPointA,
 39163                linearVelocityB,
 39164                angularVelocityB,
 39165                relativeContactPointB,
 39166                normal,
 39167                out Fixed64 normalVelocity))
 168        {
 1169            return false;
 170        }
 38171        if (normalVelocity >= Fixed64.Zero)
 172        {
 1173            result = ZeroVelocityDelta(normalVelocity);
 1174            return true;
 175        }
 176
 37177        if (!TryComputeDenominator(
 37178                bodyA,
 37179                relativeContactPointA,
 37180                bodyB,
 37181                relativeContactPointB,
 37182                normal,
 37183                out Fixed64 denominator)
 37184            || denominator <= Fixed64.Zero)
 185        {
 7186            return false;
 187        }
 188
 30189        Fixed64 appliedRestitution = normalVelocity < -restitutionVelocityThreshold
 30190            ? restitution
 30191            : Fixed64.Zero;
 30192        Fixed64 responseFactor = -(Fixed64.One + appliedRestitution);
 30193        bool linearAResolved = ContinuousCollisionImpulsePolicy.TryResolveVelocityDelta(
 30194                bodyA?.ProjectLinearMotion(-normal) ?? Vector2d.Zero,
 30195                normalVelocity,
 30196                responseFactor,
 30197                bodyA?.EffectiveInverseMass ?? Fixed64.Zero,
 30198                denominator,
 30199                out Vector2d linearVelocityDeltaA);
 30200        bool angularAResolved = TryResolveAngularVelocityDelta(
 30201                bodyA,
 30202                relativeContactPointA,
 30203                -normal,
 30204                normalVelocity,
 30205                responseFactor,
 30206                denominator,
 30207                out Fixed64 angularVelocityDeltaA);
 30208        bool linearBResolved = ContinuousCollisionImpulsePolicy.TryResolveVelocityDelta(
 30209                bodyB?.ProjectLinearMotion(normal) ?? Vector2d.Zero,
 30210                normalVelocity,
 30211                responseFactor,
 30212                bodyB?.EffectiveInverseMass ?? Fixed64.Zero,
 30213                denominator,
 30214                out Vector2d linearVelocityDeltaB);
 30215        bool angularBResolved = TryResolveAngularVelocityDelta(
 30216                bodyB,
 30217                relativeContactPointB,
 30218                normal,
 30219                normalVelocity,
 30220                responseFactor,
 30221                denominator,
 30222                out Fixed64 angularVelocityDeltaB);
 30223        if (!(linearAResolved
 30224                & angularAResolved
 30225                & linearBResolved
 30226                & angularBResolved))
 227        {
 1228            return false;
 229        }
 230
 29231        result = new ContactNormalVelocityDeltaResult2D(
 29232            normalVelocity,
 29233            linearVelocityDeltaA,
 29234            angularVelocityDeltaA,
 29235            linearVelocityDeltaB,
 29236            angularVelocityDeltaB);
 29237        return true;
 238    }
 239
 240    internal static bool TryCalculateAccumulatedDelta(
 241        SolidBody2D? bodyA,
 242        Vector2d linearVelocityA,
 243        Fixed64 angularVelocityA,
 244        Vector2d relativeContactPointA,
 245        SolidBody2D? bodyB,
 246        Vector2d linearVelocityB,
 247        Fixed64 angularVelocityB,
 248        Vector2d relativeContactPointB,
 249        Vector2d normal,
 250        Fixed64 restitution,
 251        Fixed64 restitutionVelocityThreshold,
 252        Fixed64 accumulatedImpulse,
 253        Fixed64 positiveImpulseScale,
 254        Fixed64 negativeImpulseScale,
 255        out ContactNormalImpulseResult2D result)
 256    {
 995257        result = default;
 995258        bool inputsValid =
 995259            accumulatedImpulse >= Fixed64.Zero
 995260            & positiveImpulseScale >= Fixed64.Zero
 995261            & negativeImpulseScale >= Fixed64.Zero;
 995262        if (!inputsValid)
 3263            return false;
 992264        if (!TryComputeNormalVelocity(
 992265                linearVelocityA,
 992266                angularVelocityA,
 992267                relativeContactPointA,
 992268                linearVelocityB,
 992269                angularVelocityB,
 992270                relativeContactPointB,
 992271                normal,
 992272                out Fixed64 normalVelocity)
 992273            || !TryComputeDenominator(
 992274                bodyA,
 992275                relativeContactPointA,
 992276                bodyB,
 992277                relativeContactPointB,
 992278                normal,
 992279                out Fixed64 denominator))
 280        {
 12281            return false;
 282        }
 980283        if (denominator <= Fixed64.Zero)
 284        {
 1285            result = Zero(normalVelocity);
 1286            return true;
 287        }
 288
 979289        Fixed64 appliedRestitution = normalVelocity < -restitutionVelocityThreshold
 979290            ? restitution
 979291            : Fixed64.Zero;
 979292        Fixed64 responseFactor = -(Fixed64.One + appliedRestitution);
 979293        Fixed64 impulseScale = normalVelocity < Fixed64.Zero
 979294            ? positiveImpulseScale
 979295            : negativeImpulseScale;
 296        Fixed64 impulseScalar;
 979297        if (!Fixed64.TryMultiplyDivide(
 979298                normalVelocity,
 979299                responseFactor,
 979300                impulseScale,
 979301                denominator,
 979302                out Fixed64 scaledImpulse))
 303        {
 6304            if (normalVelocity < Fixed64.Zero)
 4305                return false;
 2306            impulseScalar = -accumulatedImpulse;
 307        }
 973308        else if (!Fixed64.TryAdd(
 973309                    accumulatedImpulse,
 973310                    scaledImpulse,
 973311                    out Fixed64 accumulated)
 973312                || !Fixed64.TrySubtract(
 973313                    FixedMath.Max(Fixed64.Zero, accumulated),
 973314                    accumulatedImpulse,
 973315                    out impulseScalar))
 316        {
 1317            return false;
 318        }
 974319        if (impulseScalar == Fixed64.Zero)
 320        {
 914321            result = Zero(normalVelocity);
 914322            return true;
 323        }
 324
 60325        bool linearAResolved = TryComputeLinearVelocityDelta(
 60326            bodyA,
 60327            -normal,
 60328            impulseScalar,
 60329            out Vector2d linearA);
 60330        bool angularAResolved = TryComputeAngularVelocityDelta(
 60331            bodyA,
 60332            relativeContactPointA,
 60333            -normal,
 60334            impulseScalar,
 60335            out Fixed64 angularA);
 60336        bool linearBResolved = TryComputeLinearVelocityDelta(
 60337            bodyB,
 60338            normal,
 60339            impulseScalar,
 60340            out Vector2d linearB);
 60341        bool angularBResolved = TryComputeAngularVelocityDelta(
 60342            bodyB,
 60343            relativeContactPointB,
 60344            normal,
 60345            impulseScalar,
 60346            out Fixed64 angularB);
 60347        if (!(linearAResolved
 60348            & angularAResolved
 60349            & linearBResolved
 60350            & angularBResolved))
 351        {
 1352            return false;
 353        }
 59354        result = new ContactNormalImpulseResult2D(
 59355            normalVelocity,
 59356            impulseScalar,
 59357            linearA,
 59358            angularA,
 59359            linearB,
 59360            angularB);
 59361        return true;
 362    }
 363
 364    internal static bool TryCalculateVelocityDeltasExact(
 365        SolidBody2D? bodyA,
 366        Vector2d linearVelocityA,
 367        Fixed64 angularVelocityA,
 368        in ExactLever3D relativeContactPointA,
 369        SolidBody2D? bodyB,
 370        Vector2d linearVelocityB,
 371        Fixed64 angularVelocityB,
 372        in ExactLever3D relativeContactPointB,
 373        Vector2d normal,
 374        Fixed64 restitution,
 375        Fixed64 restitutionVelocityThreshold,
 376        out ContactNormalVelocityDeltaResult2D result)
 377    {
 26378        result = default;
 26379        if (!ExactContactLever2D.TryGetNormalResponse(
 26380                bodyA,
 26381                linearVelocityA,
 26382                angularVelocityA,
 26383                relativeContactPointA,
 26384                bodyB,
 26385                linearVelocityB,
 26386                angularVelocityB,
 26387                relativeContactPointB,
 26388                normal,
 26389                restitution,
 26390                restitutionVelocityThreshold,
 26391                out ExactNormalResponse3D response))
 392        {
 4393            return false;
 394        }
 395
 22396        bool hasNormalVelocity =
 22397            response.TryGetNormalVelocity(out Fixed64 normalVelocity);
 22398        result = new ContactNormalVelocityDeltaResult2D(
 22399            normalVelocity,
 22400            ExactContactLever2D.ToPlanar(response.FirstLinearVelocityDelta),
 22401            ExactContactLever2D.ToPlanarAngular(response.FirstAngularVelocityDelta),
 22402            ExactContactLever2D.ToPlanar(response.SecondLinearVelocityDelta),
 22403            ExactContactLever2D.ToPlanarAngular(response.SecondAngularVelocityDelta),
 22404            response.IsClosing,
 22405            hasNormalVelocity);
 22406        return true;
 407    }
 408
 409    internal static bool TryCalculateAccumulatedDeltaExact(
 410        SolidBody2D? bodyA,
 411        Vector2d linearVelocityA,
 412        Fixed64 angularVelocityA,
 413        in ExactLever3D relativeContactPointA,
 414        SolidBody2D? bodyB,
 415        Vector2d linearVelocityB,
 416        Fixed64 angularVelocityB,
 417        in ExactLever3D relativeContactPointB,
 418        Vector2d normal,
 419        Fixed64 restitution,
 420        Fixed64 restitutionVelocityThreshold,
 421        Fixed64 accumulatedImpulse,
 422        Fixed64 positiveImpulseScale,
 423        Fixed64 negativeImpulseScale,
 424        out ContactNormalImpulseResult2D result)
 425    {
 38426        result = default;
 38427        if (!ExactContactLever2D.TryGetAccumulatedNormalResponse(
 38428                bodyA,
 38429                linearVelocityA,
 38430                angularVelocityA,
 38431                relativeContactPointA,
 38432                bodyB,
 38433                linearVelocityB,
 38434                angularVelocityB,
 38435                relativeContactPointB,
 38436                normal,
 38437                restitution,
 38438                restitutionVelocityThreshold,
 38439                accumulatedImpulse,
 38440                positiveImpulseScale,
 38441                negativeImpulseScale,
 38442                out ExactNormalResponse3D response))
 443        {
 3444            return false;
 445        }
 446
 35447        bool hasNormalVelocity =
 35448            response.TryGetNormalVelocity(out Fixed64 normalVelocity);
 35449        bool hasAppliedImpulse =
 35450            response.TryGetAppliedImpulse(out Fixed64 appliedImpulse);
 35451        bool hasAccumulatedImpulse =
 35452            response.TryGetAccumulatedImpulse(
 35453                out Fixed64 newAccumulatedImpulse);
 35454        Fixed64 impulseScalar = hasAccumulatedImpulse
 35455            ? newAccumulatedImpulse - accumulatedImpulse
 35456            : -accumulatedImpulse;
 35457        result = new ContactNormalImpulseResult2D(
 35458            normalVelocity,
 35459            impulseScalar,
 35460            appliedImpulse,
 35461            ExactContactLever2D.ToPlanar(response.FirstLinearVelocityDelta),
 35462            ExactContactLever2D.ToPlanarAngular(response.FirstAngularVelocityDelta),
 35463            ExactContactLever2D.ToPlanar(response.SecondLinearVelocityDelta),
 35464            ExactContactLever2D.ToPlanarAngular(response.SecondAngularVelocityDelta),
 35465            hasNormalVelocity,
 35466            hasAppliedImpulse,
 35467            hasAccumulatedImpulse);
 35468        return true;
 469    }
 470
 471    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 472    private static bool TryComputeNormalVelocity(
 473        Vector2d linearVelocityA,
 474        Fixed64 angularVelocityA,
 475        Vector2d relativeContactPointA,
 476        Vector2d linearVelocityB,
 477        Fixed64 angularVelocityB,
 478        Vector2d relativeContactPointB,
 479        Vector2d normal,
 480        out Fixed64 normalVelocity)
 481    {
 1031482        bool angularAResolved = ContactResponseArithmetic3D.TryCross(
 1031483            new Vector3d(
 1031484                Fixed64.Zero,
 1031485                -angularVelocityA,
 1031486                Fixed64.Zero),
 1031487            ExactContactLever2D.ToSpatial(relativeContactPointA),
 1031488            out Vector3d angularA);
 1031489        bool angularBResolved = ContactResponseArithmetic3D.TryCross(
 1031490            new Vector3d(
 1031491                Fixed64.Zero,
 1031492                -angularVelocityB,
 1031493                Fixed64.Zero),
 1031494            ExactContactLever2D.ToSpatial(relativeContactPointB),
 1031495            out Vector3d angularB);
 1031496        bool relativeResolved = Vector3d.TrySubtractSums(
 1031497            ExactContactLever2D.ToSpatial(linearVelocityB),
 1031498            angularB,
 1031499            ExactContactLever2D.ToSpatial(linearVelocityA),
 1031500            angularA,
 1031501            out Vector3d relative);
 1031502        bool projectionResolved = ContactResponseArithmetic3D.TryDot(
 1031503            relative,
 1031504            ExactContactLever2D.ToSpatial(normal),
 1031505            out normalVelocity);
 1031506        if (!(angularAResolved
 1031507            & angularBResolved
 1031508            & relativeResolved
 1031509            & projectionResolved))
 510        {
 4511            normalVelocity = default;
 4512            return false;
 513        }
 1027514        return true;
 515    }
 516
 517    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 518    internal static bool TryComputeDenominator(
 519        SolidBody2D? bodyA,
 520        Vector2d relativeContactPointA,
 521        SolidBody2D? bodyB,
 522        Vector2d relativeContactPointB,
 523        Vector2d normal,
 524        out Fixed64 denominator)
 525    {
 1081526        bool angularAResolved = TryComputeAngularDenominator(
 1081527            bodyA,
 1081528            relativeContactPointA,
 1081529            normal,
 1081530            out Fixed64 angularA);
 1081531        bool angularBResolved = TryComputeAngularDenominator(
 1081532            bodyB,
 1081533            relativeContactPointB,
 1081534            normal,
 1081535            out Fixed64 angularB);
 1081536        bool linearAResolved = TryGetConstrainedInverseMass(
 1081537            bodyA,
 1081538            normal,
 1081539            out Fixed64 linearA);
 1081540        bool linearBResolved = TryGetConstrainedInverseMass(
 1081541            bodyB,
 1081542            normal,
 1081543            out Fixed64 linearB);
 1081544        bool sumResolved = Fixed64.TryAdd(
 1081545                linearA,
 1081546                linearB,
 1081547                out Fixed64 linear)
 1081548            & Fixed64.TryAdd(
 1081549                linear,
 1081550                angularA,
 1081551                out Fixed64 first)
 1081552            & Fixed64.TryAdd(
 1081553                first,
 1081554                angularB,
 1081555                out denominator);
 1081556        if (!(linearAResolved
 1081557            & linearBResolved
 1081558            & angularAResolved
 1081559            & angularBResolved
 1081560            & sumResolved))
 561        {
 13562            denominator = default;
 13563            return false;
 564        }
 1068565        return true;
 566    }
 567
 568    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 569    internal static bool TryComputeAngularDenominator(
 570        SolidBody2D? body,
 571        Vector2d relativeContactPoint,
 572        Vector2d axis,
 573        out Fixed64 denominator)
 574    {
 2500575        if (body?.CanRotate != true)
 576        {
 1119577            denominator = Fixed64.Zero;
 1119578            return true;
 579        }
 580
 1381581        denominator = default;
 1381582        bool crossResolved = ContactResponseArithmetic3D.TryCross(
 1381583                ExactContactLever2D.ToSpatial(relativeContactPoint),
 1381584                ExactContactLever2D.ToSpatial(axis),
 1381585                out Vector3d cross);
 1381586        bool denominatorResolved = crossResolved
 1381587            && Fixed64.TryMultiplyDivide(
 1381588                cross.Y,
 1381589                cross.Y,
 1381590                body.EffectiveInverseMomentOfInertia,
 1381591                Fixed64.One,
 1381592                out denominator);
 1381593        if (!denominatorResolved
 1381594            || (denominator == Fixed64.Zero
 1381595                && cross.Y != Fixed64.Zero
 1381596                && body.EffectiveInverseMomentOfInertia
 1381597                    != Fixed64.Zero))
 598        {
 10599            denominator = default;
 10600            return false;
 601        }
 602
 1371603        return true;
 604    }
 605
 606    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 607    internal static bool TryGetConstrainedInverseMass(
 608        SolidBody2D? body,
 609        Vector2d axis,
 610        out Fixed64 inverseMass)
 611    {
 2182612        if (body == null)
 613        {
 54614            inverseMass = Fixed64.Zero;
 54615            return true;
 616        }
 617
 2128618        inverseMass = body.GetConstrainedInverseMass(axis);
 2128619        return inverseMass != Fixed64.Zero
 2128620            || body.EffectiveInverseMass == Fixed64.Zero
 2128621            || body.ProjectLinearMotion(axis) == Vector2d.Zero;
 622    }
 623
 624    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 625    internal static bool TryComputeLinearVelocityDelta(
 626        SolidBody2D? body,
 627        Vector2d signedNormal,
 628        Fixed64 impulseScalar,
 629        out Vector2d velocityDelta) =>
 223630        ContinuousCollisionImpulsePolicy.TryResolveVelocityDelta(
 223631            body?.ProjectLinearMotion(signedNormal) ?? Vector2d.Zero,
 223632            impulseScalar,
 223633            body?.EffectiveInverseMass ?? Fixed64.Zero,
 223634            Fixed64.One,
 223635            out velocityDelta);
 636
 637    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 638    internal static bool TryComputeAngularVelocityDelta(
 639        SolidBody2D? body,
 640        Vector2d relativeContactPoint,
 641        Vector2d signedNormal,
 642        Fixed64 impulseScalar,
 643        out Fixed64 velocityDelta)
 644    {
 226645        velocityDelta = Fixed64.Zero;
 226646        if (body?.CanRotate != true)
 80647            return true;
 648
 146649        Vector3d spatialPoint =
 146650            ExactContactLever2D.ToSpatial(relativeContactPoint);
 146651        Vector3d spatialNormal =
 146652            ExactContactLever2D.ToSpatial(signedNormal);
 146653        return ContactResponseArithmetic3D.TryCross(
 146654                spatialPoint,
 146655                spatialNormal,
 146656                out Vector3d cross)
 146657            && Fixed64.TryMultiplyDivide(
 146658                -cross.Y,
 146659                impulseScalar,
 146660                body.EffectiveInverseMomentOfInertia,
 146661                Fixed64.One,
 146662                out velocityDelta);
 663    }
 664
 665    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 666    private static bool TryResolveAngularVelocityDelta(
 667        SolidBody2D? body,
 668        Vector2d relativeContactPoint,
 669        Vector2d signedNormal,
 670        Fixed64 normalVelocity,
 671        Fixed64 responseFactor,
 672        Fixed64 denominator,
 673        out Fixed64 velocityDelta)
 674    {
 60675        velocityDelta = Fixed64.Zero;
 60676        if (body?.CanRotate != true)
 20677            return true;
 678
 40679        Fixed64 torqueScale = Vector2d.CrossProduct(relativeContactPoint, signedNormal);
 40680        if (torqueScale == Fixed64.Zero)
 28681            return true;
 682
 12683        bool angularScaleResolved = Fixed64.TryMultiplyDivide(
 12684            normalVelocity,
 12685            responseFactor,
 12686            body.EffectiveInverseMomentOfInertia,
 12687            denominator,
 12688            out Fixed64 angularScale);
 12689        bool velocityDeltaResolved = Fixed64.TryMultiplyDivide(
 12690            torqueScale,
 12691            angularScale,
 12692            Fixed64.One,
 12693            out velocityDelta);
 12694        return angularScaleResolved
 12695            & (angularScale != Fixed64.Zero | torqueScale.Abs() <= Fixed64.One)
 12696            & velocityDeltaResolved;
 697    }
 698
 699    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 700    private static ContactNormalImpulseResult2D Zero(Fixed64 normalVelocity) =>
 915701        new(
 915702            normalVelocity,
 915703            Fixed64.Zero,
 915704            Vector2d.Zero,
 915705            Fixed64.Zero,
 915706            Vector2d.Zero,
 915707            Fixed64.Zero);
 708
 709    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 710    private static ContactNormalVelocityDeltaResult2D ZeroVelocityDelta(Fixed64 normalVelocity) =>
 1711        new(
 1712            normalVelocity,
 1713            Vector2d.Zero,
 1714            Fixed64.Zero,
 1715            Vector2d.Zero,
 1716            Fixed64.Zero);
 717}

Methods/Properties

TryCalculateVelocityDeltas(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ContactNormalVelocityDeltaResult2D&)
TryCalculateAccumulatedDelta(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ContactNormalImpulseResult2D&)
TryCalculateVelocityDeltasExact(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactLever3D&,Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactLever3D&,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ContactNormalVelocityDeltaResult2D&)
TryCalculateAccumulatedDeltaExact(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactLever3D&,Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ExactLever3D&,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.CollisionHandling.ContactNormalImpulseResult2D&)
TryComputeNormalVelocity(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64&)
TryComputeDenominator(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64&)
TryComputeAngularDenominator(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64&)
TryGetConstrainedInverseMass(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64&)
TryComputeLinearVelocityDelta(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d&)
TryComputeAngularVelocityDelta(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
TryResolveAngularVelocityDelta(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
Zero(FixedMathSharp.Fixed64)
ZeroVelocityDelta(FixedMathSharp.Fixed64)