< Summary

Information
Class: FixedMathSharp.Geometry.WideFiniteAxisProjection
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/WideFiniteAxisProjection.cs
Line coverage
100%
Covered lines: 514
Uncovered lines: 0
Coverable lines: 514
Total lines: 894
Line coverage: 100%
Branch coverage
100%
Covered branches: 54
Total branches: 54
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/WideFiniteAxisProjection.cs

#LineLine coverage
 1//=======================================================================
 2// WideFiniteAxisProjection.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8namespace FixedMathSharp.Geometry;
 9
 10/// <summary>
 11/// Provides deterministic, high-precision (wide/Signed192) axis-projection utilities for evaluating
 12/// separating-axis overlap and penetration depth between finite-length capsule and cylinder shapes.
 13/// Projects shape extents and centers onto a given axis using extended-precision arithmetic to avoid
 14/// overflow/rounding issues inherent in fixed-point math, enabling robust SAT-based collision detection
 15/// and accurate minimum translation vector (MTV) computation for narrow-phase physics queries.
 16/// </summary>
 17internal static class WideFiniteAxisProjection
 18{
 119    private static readonly Signed192 Scale = Signed192.Signed(Fixed64.One.m_rawValue);
 120    private static readonly Signed192 DoubleScale = Signed192.Signed(Fixed64.Two.m_rawValue);
 121    private static readonly Signed192 ScaleSquared = GetScaleSquared();
 22
 23    #region Nested Types
 24
 25    private readonly struct ProjectionDepth
 26    {
 27        internal readonly Signed320 RationalNumerator;
 28        internal readonly Signed192 RationalDenominator;
 29        internal readonly Radical First;
 30        internal readonly Radical Second;
 31
 32        internal ProjectionDepth(
 33            Signed320 rationalNumerator,
 34            Signed192 rationalDenominator,
 35            Radical first,
 36            Radical second)
 37        {
 37738            RationalNumerator = rationalNumerator;
 37739            RationalDenominator = rationalDenominator;
 37740            First = first;
 37741            Second = second;
 37742        }
 43    }
 44
 45    private readonly struct Radical
 46    {
 47        internal readonly Signed576 Numerator;
 48        internal readonly Signed192 Denominator;
 49
 50        internal Radical(Signed576 numerator, Signed192 denominator)
 51        {
 73752            Numerator = numerator;
 73753            Denominator = denominator;
 73754        }
 55    }
 56
 57    #endregion
 58
 59    internal static bool DoCylinderCapsuleOverlapOnAxis(
 60        Vector3d projectionAxis,
 61        Vector3d cylinderCenter,
 62        Vector3d cylinderAxis,
 63        Fixed64 cylinderLength,
 64        Fixed64 cylinderRadius,
 65        Vector3d capsuleCenter,
 66        Vector3d capsuleAxis,
 67        Fixed64 capsuleLength,
 68        Fixed64 capsuleRadius)
 69    {
 370        CreateCylinderCapsuleDepth(
 371            projectionAxis,
 372            cylinderCenter,
 373            cylinderAxis,
 374            cylinderLength,
 375            cylinderRadius,
 376            capsuleCenter,
 377            capsuleAxis,
 378            capsuleLength,
 379            capsuleRadius,
 380            out ProjectionDepth depth);
 381        return CompareToTwiceRaw(depth, default) >= 0;
 82    }
 83
 84    internal static bool TryGetCylinderCapsuleAxisPenetration(
 85        Vector3d projectionAxis,
 86        Vector3d cylinderCenter,
 87        Vector3d cylinderAxis,
 88        Fixed64 cylinderLength,
 89        Fixed64 cylinderRadius,
 90        Vector3d capsuleCenter,
 91        Vector3d capsuleAxis,
 92        Fixed64 capsuleLength,
 93        Fixed64 capsuleRadius,
 94        out Vector3d orientedAxis,
 95        out Fixed64 penetrationDepth)
 96    {
 797        bool result = TryGetCylinderCapsuleAxisPenetration(
 798            projectionAxis,
 799            cylinderCenter,
 7100            cylinderAxis,
 7101            cylinderLength,
 7102            cylinderRadius,
 7103            capsuleCenter,
 7104            capsuleAxis,
 7105            capsuleLength,
 7106            capsuleRadius,
 7107            out orientedAxis,
 7108            out penetrationDepth,
 7109            out bool depthIsClamped);
 7110        return result & !depthIsClamped;
 111    }
 112
 113    internal static bool TryGetCylinderCapsuleAxisPenetration(
 114        Vector3d projectionAxis,
 115        Vector3d cylinderCenter,
 116        Vector3d cylinderAxis,
 117        Fixed64 cylinderLength,
 118        Fixed64 cylinderRadius,
 119        Vector3d capsuleCenter,
 120        Vector3d capsuleAxis,
 121        Fixed64 capsuleLength,
 122        Fixed64 capsuleRadius,
 123        out Vector3d orientedAxis,
 124        out Fixed64 penetrationDepth,
 125        out bool depthIsClamped)
 126    {
 13127        CreateCylinderCapsuleDepth(
 13128            projectionAxis,
 13129            cylinderCenter,
 13130            cylinderAxis,
 13131            cylinderLength,
 13132            cylinderRadius,
 13133            capsuleCenter,
 13134            capsuleAxis,
 13135            capsuleLength,
 13136            capsuleRadius,
 13137            out ProjectionDepth depth);
 13138        return TryMaterializeDepth(
 13139            depth,
 13140            projectionAxis,
 13141            GetDot(capsuleCenter, cylinderCenter, projectionAxis),
 13142            out orientedAxis,
 13143            out penetrationDepth,
 13144            out depthIsClamped);
 145    }
 146
 147    internal static bool DoCylindersOverlapOnAxis(
 148        Vector3d projectionAxis,
 149        Vector3d firstCenter,
 150        Vector3d firstAxis,
 151        Fixed64 firstLength,
 152        Fixed64 firstRadius,
 153        Vector3d secondCenter,
 154        Vector3d secondAxis,
 155        Fixed64 secondLength,
 156        Fixed64 secondRadius)
 157    {
 217158        CreateCylinderDepth(
 217159            projectionAxis,
 217160            firstCenter,
 217161            firstAxis,
 217162            firstLength,
 217163            firstRadius,
 217164            secondCenter,
 217165            secondAxis,
 217166            secondLength,
 217167            secondRadius,
 217168            out ProjectionDepth depth);
 217169        return CompareToTwiceRaw(depth, default) >= 0;
 170    }
 171
 172    internal static bool TryGetCylindersAxisPenetration(
 173        Vector3d projectionAxis,
 174        Vector3d firstCenter,
 175        Vector3d firstAxis,
 176        Fixed64 firstLength,
 177        Fixed64 firstRadius,
 178        Vector3d secondCenter,
 179        Vector3d secondAxis,
 180        Fixed64 secondLength,
 181        Fixed64 secondRadius,
 182        out Vector3d orientedAxis,
 183        out Fixed64 penetrationDepth)
 184    {
 116185        bool result = TryGetCylindersAxisPenetration(
 116186            projectionAxis,
 116187            firstCenter,
 116188            firstAxis,
 116189            firstLength,
 116190            firstRadius,
 116191            secondCenter,
 116192            secondAxis,
 116193            secondLength,
 116194            secondRadius,
 116195            out orientedAxis,
 116196            out penetrationDepth,
 116197            out bool depthIsClamped);
 116198        return result && !depthIsClamped;
 199    }
 200
 201    internal static bool TryGetCylindersAxisPenetration(
 202        Vector3d projectionAxis,
 203        Vector3d firstCenter,
 204        Vector3d firstAxis,
 205        Fixed64 firstLength,
 206        Fixed64 firstRadius,
 207        Vector3d secondCenter,
 208        Vector3d secondAxis,
 209        Fixed64 secondLength,
 210        Fixed64 secondRadius,
 211        out Vector3d orientedAxis,
 212        out Fixed64 penetrationDepth,
 213        out bool depthIsClamped)
 214    {
 117215        CreateCylinderDepth(
 117216            projectionAxis,
 117217            firstCenter,
 117218            firstAxis,
 117219            firstLength,
 117220            firstRadius,
 117221            secondCenter,
 117222            secondAxis,
 117223            secondLength,
 117224            secondRadius,
 117225            out ProjectionDepth depth);
 117226        return TryMaterializeDepth(
 117227            depth,
 117228            projectionAxis,
 117229            GetDot(secondCenter, firstCenter, projectionAxis),
 117230            out orientedAxis,
 117231            out penetrationDepth,
 117232            out depthIsClamped);
 233    }
 234
 235    private static void CreateCylinderCapsuleDepth(
 236        Vector3d projectionAxis,
 237        Vector3d cylinderCenter,
 238        Vector3d cylinderAxis,
 239        Fixed64 cylinderLength,
 240        Fixed64 cylinderRadius,
 241        Vector3d capsuleCenter,
 242        Vector3d capsuleAxis,
 243        Fixed64 capsuleLength,
 244        Fixed64 capsuleRadius,
 245        out ProjectionDepth depth)
 246    {
 16247        CreateRationalDepth(
 16248            projectionAxis,
 16249            cylinderCenter,
 16250            cylinderAxis,
 16251            cylinderLength,
 16252            capsuleCenter,
 16253            capsuleAxis,
 16254            capsuleLength,
 16255            out Signed320 rationalNumerator,
 16256            out Signed192 rationalDenominator);
 16257        depth = new ProjectionDepth(
 16258            rationalNumerator,
 16259            rationalDenominator,
 16260            CreateCylinderRadical(projectionAxis, cylinderAxis, cylinderRadius),
 16261            CreateCapsuleRadical(projectionAxis, capsuleRadius));
 16262    }
 263
 264    private static void CreateCylinderDepth(
 265        Vector3d projectionAxis,
 266        Vector3d firstCenter,
 267        Vector3d firstAxis,
 268        Fixed64 firstLength,
 269        Fixed64 firstRadius,
 270        Vector3d secondCenter,
 271        Vector3d secondAxis,
 272        Fixed64 secondLength,
 273        Fixed64 secondRadius,
 274        out ProjectionDepth depth)
 275    {
 334276        CreateRationalDepth(
 334277            projectionAxis,
 334278            firstCenter,
 334279            firstAxis,
 334280            firstLength,
 334281            secondCenter,
 334282            secondAxis,
 334283            secondLength,
 334284            out Signed320 rationalNumerator,
 334285            out Signed192 rationalDenominator);
 334286        depth = new ProjectionDepth(
 334287            rationalNumerator,
 334288            rationalDenominator,
 334289            CreateCylinderRadical(projectionAxis, firstAxis, firstRadius),
 334290            CreateCylinderRadical(projectionAxis, secondAxis, secondRadius));
 334291    }
 292
 293    private static void CreateRationalDepth(
 294        Vector3d projectionAxis,
 295        Vector3d firstCenter,
 296        Vector3d firstAxis,
 297        Fixed64 firstLength,
 298        Vector3d secondCenter,
 299        Vector3d secondAxis,
 300        Fixed64 secondLength,
 301        out Signed320 numerator,
 302        out Signed192 denominator)
 303    {
 350304        Signed192 firstAlignment = WideArithmetic.Absolute(GetDot(firstAxis, projectionAxis));
 350305        Signed192 secondAlignment = WideArithmetic.Absolute(GetDot(secondAxis, projectionAxis));
 350306        Signed192 centerSeparation = WideArithmetic.Absolute(
 350307            GetDot(secondCenter, firstCenter, projectionAxis));
 350308        numerator = WideArithmetic.SubtractSigned320(
 350309            WideArithmetic.AddSigned320(
 350310                WideArithmetic.MultiplySigned192(
 350311                    firstAlignment,
 350312                    Signed192.Signed(firstLength.m_rawValue)),
 350313                WideArithmetic.MultiplySigned192(
 350314                    secondAlignment,
 350315                    Signed192.Signed(secondLength.m_rawValue))),
 350316            WideArithmetic.MultiplySigned192(centerSeparation, DoubleScale));
 350317        Signed320 wideDenominator = WideArithmetic.MultiplySigned192(
 350318            DoubleScale,
 350319            Scale);
 350320        denominator = new Signed192(
 350321            wideDenominator.Word2,
 350322            wideDenominator.Word1,
 350323            wideDenominator.Word0);
 350324    }
 325
 326    private static Radical CreateCylinderRadical(
 327        Vector3d projectionAxis,
 328        Vector3d cylinderAxis,
 329        Fixed64 radius)
 330    {
 714331        Signed192 axisSquared = GetDot(cylinderAxis, cylinderAxis);
 714332        Signed192 projectionSquared = GetDot(projectionAxis, projectionAxis);
 714333        Signed192 alignment = GetDot(cylinderAxis, projectionAxis);
 714334        Signed320 planeSquared = WideArithmetic.MultiplySubtract(
 714335            axisSquared,
 714336            projectionSquared,
 714337            alignment,
 714338            alignment);
 714339        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 714340            Signed192.Signed(radius.m_rawValue),
 714341            Signed192.Signed(radius.m_rawValue));
 714342        Signed576 numerator = WideArithmetic.MultiplySigned320(
 714343            radiusSquared,
 714344            planeSquared);
 714345        Signed576 wideDenominator = WideArithmetic.MultiplySigned576(
 714346            Signed576.ExtendValue(
 714347                WideArithmetic.MultiplySigned192(axisSquared, ScaleSquared)),
 714348            Signed192.Signed(1L));
 349        // A normalized direction squared is Q64-scaled; multiplying by the
 350        // Q64 scale denominator needs at most 129 signed bits.
 714351        Signed192 denominator = new(
 714352            wideDenominator.Word2,
 714353            wideDenominator.Word1,
 714354            wideDenominator.Word0);
 714355        return new Radical(numerator, denominator);
 356    }
 357
 358    private static Radical CreateCapsuleRadical(
 359        Vector3d projectionAxis,
 360        Fixed64 radius)
 361    {
 20362        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 20363            Signed192.Signed(radius.m_rawValue),
 20364            Signed192.Signed(radius.m_rawValue));
 20365        Signed192 projectionSquared = GetDot(projectionAxis, projectionAxis);
 20366        Signed576 numerator = WideArithmetic.MultiplySigned576(
 20367            Signed576.ExtendValue(radiusSquared),
 20368            projectionSquared);
 20369        return new Radical(numerator, ScaleSquared);
 370    }
 371
 372    private static bool TryMaterializeDepth(
 373        ProjectionDepth depth,
 374        Vector3d projectionAxis,
 375        Signed192 centerProjection,
 376        out Vector3d orientedAxis,
 377        out Fixed64 result,
 378        out bool depthIsClamped)
 379    {
 137380        return TryMaterializeDepth(
 137381            depth,
 137382            centerProjection.Sign < 0
 137383                ? -projectionAxis
 137384                : projectionAxis,
 137385            out orientedAxis,
 137386            out result,
 137387            out depthIsClamped);
 388    }
 389
 390    private static bool TryMaterializeDepth(
 391        ProjectionDepth depth,
 392        Vector3d selectedAxis,
 393        out Vector3d orientedAxis,
 394        out Fixed64 result,
 395        out bool depthIsClamped)
 396    {
 145397        if (CompareToTwiceRaw(depth, default) < 0)
 398        {
 25399            orientedAxis = default;
 25400            result = default;
 25401            depthIsClamped = default;
 25402            return false;
 403        }
 404
 120405        orientedAxis = selectedAxis;
 120406        if (CompareToTwiceRaw(
 120407                depth,
 120408                new Signed192(0UL, 0UL, ulong.MaxValue - 1UL)) > 0)
 409        {
 7410            result = Fixed64.MaxValue;
 7411            depthIsClamped = true;
 7412            return true;
 413        }
 414
 113415        bool approximationsAreRepresentable =
 113416            TryGetRadicalApproximation(depth.First, out Fixed64 firstApproximation)
 113417            & TryGetRadicalApproximation(depth.Second, out Fixed64 secondApproximation);
 113418        if (!approximationsAreRepresentable)
 419        {
 420            // Individual supports may exceed Fixed64 even when their sum
 421            // cancels against the rational separation into range.
 3422            result = GetRoundedDepthByExactSearch(depth);
 3423            depthIsClamped = false;
 3424            return true;
 425        }
 426
 110427        Signed192 approximatedRadicals = WideArithmetic.AddSigned192(
 110428            Signed192.Signed(firstApproximation.m_rawValue),
 110429            Signed192.Signed(secondApproximation.m_rawValue));
 110430        Signed320 approximationNumerator = WideArithmetic.AddSigned320(
 110431            depth.RationalNumerator,
 110432            WideArithmetic.MultiplySigned192(
 110433                depth.RationalDenominator,
 110434                approximatedRadicals));
 435        // Cancel the rational and radical terms before narrowing. The
 436        // nonnegative floor gives correction a bounded endpoint even when an
 437        // individual term is outside the Fixed64 domain.
 110438        result = Fixed64.GetNonNegativeRawRatioFloor(
 110439            Signed704.ExtendValue(
 110440                Signed576.ExtendValue(approximationNumerator)),
 110441            Signed704.ExtendValue(
 110442                Signed576.ExtendValue(
 110443                    Signed320.ExtendValue(
 110444                        depth.RationalDenominator))));
 445
 110446        CorrectRoundedDepth(depth, ref result);
 110447        depthIsClamped = false;
 110448        return true;
 449    }
 450
 451    private static bool TryGetRadicalApproximation(
 452        Radical radical,
 453        out Fixed64 result)
 454    {
 226455        if (radical.Numerator.IsZero)
 456        {
 71457            result = Fixed64.Zero;
 71458            return true;
 459        }
 460
 155461        Signed576 root = WideArithmetic.GetFloorSquareRootOfProduct(
 155462            Signed832.ExtendValue(radical.Numerator),
 155463            radical.Denominator);
 155464        return Fixed64.TryGetSignedRawRatio(
 155465            root,
 155466            Signed576.ExtendValue(
 155467                Signed320.ExtendValue(radical.Denominator)),
 155468            out result);
 469    }
 470
 471    private static Fixed64 GetRoundedDepthByExactSearch(ProjectionDepth depth)
 472    {
 3473        ulong low = 0UL;
 3474        ulong high = (ulong)long.MaxValue;
 3475        ulong floor = 0UL;
 192476        while (low <= high)
 477        {
 189478            ulong midpoint = low + ((high - low) >> 1);
 189479            if (CompareToTwiceRaw(
 189480                    depth,
 189481                    new Signed192(0UL, 0UL, midpoint << 1)) >= 0)
 482            {
 9483                floor = midpoint;
 9484                low = midpoint + 1UL;
 485            }
 486            else
 487            {
 180488                high = midpoint - 1UL;
 489            }
 490        }
 491
 3492        Fixed64 result = Fixed64.FromRaw((long)floor);
 3493        CorrectRoundedDepth(depth, ref result);
 3494        return result;
 495    }
 496
 497    private static void CorrectRoundedDepth(
 498        ProjectionDepth depth,
 499        ref Fixed64 result)
 500    {
 238501        for (int iteration = 0; (iteration < 3) & (result > Fixed64.Zero); iteration++)
 502        {
 116503            Signed192 lowerMidpoint = new(
 116504                0UL,
 116505                unchecked((ulong)result.m_rawValue) >> 63,
 116506                unchecked((ulong)(result.m_rawValue + result.m_rawValue - 1L)));
 116507            int comparison = CompareToTwiceRaw(depth, lowerMidpoint);
 116508            if (comparison >= (result.m_rawValue & 1L))
 509            {
 510                break;
 511            }
 512
 6513            result = Fixed64.FromRaw(result.m_rawValue - 1L);
 514        }
 515
 256516        for (int iteration = 0; (iteration < 3) & (result < Fixed64.MaxValue); iteration++)
 517        {
 125518            Signed192 upperMidpoint = new(
 125519                0UL,
 125520                0UL,
 125521                unchecked((ulong)result.m_rawValue << 1) | 1UL);
 125522            int comparison = CompareToTwiceRaw(depth, upperMidpoint);
 125523            if (comparison + (result.m_rawValue & 1L) <= 0)
 524            {
 525                break;
 526            }
 527
 15528            result = Fixed64.FromRaw(result.m_rawValue + 1L);
 529        }
 113530    }
 531
 532    private static int CompareToTwiceRaw(
 533        ProjectionDepth depth,
 534        Signed192 twiceRaw)
 535    {
 934536        Signed320 thresholdNumerator = WideArithmetic.SubtractSigned320(
 934537            WideArithmetic.MultiplySigned192(
 934538                twiceRaw,
 934539                depth.RationalDenominator),
 934540            WideArithmetic.AddSigned320(
 934541                depth.RationalNumerator,
 934542                depth.RationalNumerator));
 934543        if (thresholdNumerator.Sign <= 0)
 544        {
 219545            if (thresholdNumerator.Sign < 0)
 195546                return 1;
 24547            return depth.First.Numerator.IsZero && depth.Second.Numerator.IsZero
 24548                ? 0
 24549                : 1;
 550        }
 551
 715552        Signed192 thresholdDenominator = WideArithmetic.AddSigned192(
 715553            depth.RationalDenominator,
 715554            depth.RationalDenominator);
 715555        return WideArithmetic.CompareNonNegativeRadicalSumToRatio(
 715556            depth.First.Numerator,
 715557            depth.First.Denominator,
 715558            depth.Second.Numerator,
 715559            depth.Second.Denominator,
 715560            thresholdNumerator,
 715561            thresholdDenominator);
 562    }
 563
 564    private static Signed192 GetDot(Vector3d left, Vector3d right) =>
 2913565        WideGeometry.GetDifferenceDotProduct3D(
 2913566            left.X,
 2913567            Fixed64.Zero,
 2913568            left.Y,
 2913569            Fixed64.Zero,
 2913570            left.Z,
 2913571            Fixed64.Zero,
 2913572            right.X,
 2913573            Fixed64.Zero,
 2913574            right.Y,
 2913575            Fixed64.Zero,
 2913576            right.Z,
 2913577            Fixed64.Zero);
 578
 579    private static Signed192 GetDot(
 580        Vector3d end,
 581        Vector3d start,
 582        Vector3d direction) =>
 504583        WideGeometry.GetDifferenceDotProduct3D(
 504584            end.X,
 504585            start.X,
 504586            end.Y,
 504587            start.Y,
 504588            end.Z,
 504589            start.Z,
 504590            direction.X,
 504591            Fixed64.Zero,
 504592            direction.Y,
 504593            Fixed64.Zero,
 504594            direction.Z,
 504595            Fixed64.Zero);
 596
 597    private static Signed192 GetScaleSquared()
 598    {
 1599        Signed320 value = WideArithmetic.MultiplySigned192(Scale, Scale);
 1600        return new Signed192(value.Word2, value.Word1, value.Word0);
 601    }
 602
 603    internal static bool TryGetCapsuleCapsuleSlabAxisPenetration(
 604            Vector3d projectionAxis,
 605            Vector3d capsuleCenter,
 606            Vector3d capsuleAxis,
 607            Fixed64 capsuleLength,
 608            Fixed64 capsuleRadius,
 609            Vector3d slabCenter,
 610            Vector2d slabCapsuleAxis,
 611            Fixed64 slabCapsuleLength,
 612            Fixed64 slabCapsuleRadius,
 613            Fixed64 slabHalfThickness,
 614            out Vector3d orientedAxis,
 615            out Fixed64 depth,
 616            out bool depthIsClamped)
 617    {
 4618        CreateSymmetricCapsuleSlabDepth(
 4619            projectionAxis,
 4620            capsuleCenter,
 4621            capsuleAxis,
 4622            capsuleLength,
 4623            capsuleRadius,
 4624            shapeUsesSphericalRadius: true,
 4625            slabCenter,
 4626            slabCapsuleAxis,
 4627            slabCapsuleLength,
 4628            slabCapsuleRadius,
 4629            slabHalfThickness,
 4630            out ProjectionDepth projectionDepth);
 4631        return TryMaterializeDepth(
 4632            projectionDepth,
 4633            projectionAxis,
 4634            GetDot(slabCenter, capsuleCenter, projectionAxis),
 4635            out orientedAxis,
 4636            out depth,
 4637            out depthIsClamped);
 638    }
 639
 640    internal static bool TryGetCylinderCapsuleSlabAxisPenetration(
 641        Vector3d projectionAxis,
 642        Vector3d cylinderCenter,
 643        Vector3d cylinderAxis,
 644        Fixed64 cylinderLength,
 645        Fixed64 cylinderRadius,
 646        Vector3d slabCenter,
 647        Vector2d slabCapsuleAxis,
 648        Fixed64 slabCapsuleLength,
 649        Fixed64 slabCapsuleRadius,
 650        Fixed64 slabHalfThickness,
 651        out Vector3d orientedAxis,
 652        out Fixed64 depth,
 653        out bool depthIsClamped)
 654    {
 3655        CreateSymmetricCapsuleSlabDepth(
 3656            projectionAxis,
 3657            cylinderCenter,
 3658            cylinderAxis,
 3659            cylinderLength,
 3660            cylinderRadius,
 3661            shapeUsesSphericalRadius: false,
 3662            slabCenter,
 3663            slabCapsuleAxis,
 3664            slabCapsuleLength,
 3665            slabCapsuleRadius,
 3666            slabHalfThickness,
 3667            out ProjectionDepth projectionDepth);
 3668        return TryMaterializeDepth(
 3669            projectionDepth,
 3670            projectionAxis,
 3671            GetDot(slabCenter, cylinderCenter, projectionAxis),
 3672            out orientedAxis,
 3673            out depth,
 3674            out depthIsClamped);
 675    }
 676
 677    internal static bool TryGetConeCapsuleSlabAxisPenetration(
 678        Vector3d projectionAxis,
 679        Vector3d coneCenter,
 680        Vector3d coneAxis,
 681        Fixed64 coneHeight,
 682        Fixed64 coneRadius,
 683        Vector3d slabCenter,
 684        Vector2d slabCapsuleAxis,
 685        Fixed64 slabCapsuleLength,
 686        Fixed64 slabCapsuleRadius,
 687        Fixed64 slabHalfThickness,
 688        out Vector3d orientedAxis,
 689        out Fixed64 depth,
 690        out bool depthIsClamped)
 691    {
 10692        Signed192 centerProjection =
 10693            GetDot(slabCenter, coneCenter, projectionAxis);
 10694        Signed192 coneAlignment = GetDot(coneAxis, projectionAxis);
 10695        Signed320 coneAxial = WideArithmetic.MultiplySigned192(
 10696            coneAlignment,
 10697            Signed192.Signed(coneHeight.m_rawValue));
 10698        Radical coneDisk =
 10699            CreateCylinderRadical(projectionAxis, coneAxis, coneRadius);
 10700        Radical slabRadial =
 10701            CreateCapsuleSlabRadical(projectionAxis, slabCapsuleRadius);
 10702        Signed320 slabRational = CreateCapsuleSlabRational(
 10703            projectionAxis,
 10704            slabCapsuleAxis,
 10705            slabCapsuleLength,
 10706            slabHalfThickness);
 10707        Signed320 centerRational = WideArithmetic.MultiplySigned192(
 10708            centerProjection,
 10709            DoubleScale);
 10710        Signed192 denominator = GetRationalDenominator();
 711
 10712        bool maximumUsesBase = coneAxial.Sign <= 0
 10713            || IsRadicalAtLeastRatio(coneDisk, coneAxial);
 10714        Signed320 negativeConeAxial =
 10715            WideArithmetic.SubtractSigned320(default, coneAxial);
 10716        bool minimumUsesBase = negativeConeAxial.Sign <= 0
 10717            || IsRadicalAtLeastRatio(coneDisk, negativeConeAxial);
 10718        Signed320 maximumRational = maximumUsesBase
 10719            ? negativeConeAxial
 10720            : coneAxial;
 10721        Signed320 minimumRational = minimumUsesBase
 10722            ? negativeConeAxial
 10723            : coneAxial;
 724
 10725        var positive = new ProjectionDepth(
 10726            WideArithmetic.AddSigned320(
 10727                WideArithmetic.SubtractSigned320(
 10728                    maximumRational,
 10729                    centerRational),
 10730                slabRational),
 10731            denominator,
 10732            maximumUsesBase ? coneDisk : CreateZeroRadical(),
 10733            slabRadial);
 10734        var negative = new ProjectionDepth(
 10735            WideArithmetic.SubtractSigned320(
 10736                WideArithmetic.AddSigned320(
 10737                    centerRational,
 10738                    slabRational),
 10739                minimumRational),
 10740            denominator,
 10741            minimumUsesBase ? coneDisk : CreateZeroRadical(),
 10742            slabRadial);
 10743        if (CompareToTwiceRaw(positive, default) < 0
 10744            || CompareToTwiceRaw(negative, default) < 0)
 745        {
 2746            orientedAxis = default;
 2747            depth = default;
 2748            depthIsClamped = default;
 2749            return false;
 750        }
 751
 8752        bool positiveSelected =
 8753            CompareProjectionDepthsWithoutSharedSecond(
 8754                positive,
 8755                negative) <= 0;
 8756        ProjectionDepth selected =
 8757            positiveSelected ? positive : negative;
 8758        return TryMaterializeDepth(
 8759            selected,
 8760            positiveSelected ? projectionAxis : -projectionAxis,
 8761            out orientedAxis,
 8762            out depth,
 8763            out depthIsClamped);
 764    }
 765
 766    private static void CreateSymmetricCapsuleSlabDepth(
 767        Vector3d projectionAxis,
 768        Vector3d shapeCenter,
 769        Vector3d shapeAxis,
 770        Fixed64 shapeLength,
 771        Fixed64 shapeRadius,
 772        bool shapeUsesSphericalRadius,
 773        Vector3d slabCenter,
 774        Vector2d slabCapsuleAxis,
 775        Fixed64 slabCapsuleLength,
 776        Fixed64 slabCapsuleRadius,
 777        Fixed64 slabHalfThickness,
 778        out ProjectionDepth depth)
 779    {
 7780        Signed320 shapeAxial = WideArithmetic.MultiplySigned192(
 7781            WideArithmetic.Absolute(GetDot(shapeAxis, projectionAxis)),
 7782            Signed192.Signed(shapeLength.m_rawValue));
 7783        Signed320 slabRational = CreateCapsuleSlabRational(
 7784            projectionAxis,
 7785            slabCapsuleAxis,
 7786            slabCapsuleLength,
 7787            slabHalfThickness);
 7788        Signed320 centerRational = WideArithmetic.MultiplySigned192(
 7789            WideArithmetic.Absolute(GetDot(slabCenter, shapeCenter, projectionAxis)),
 7790            DoubleScale);
 7791        depth = new ProjectionDepth(
 7792            WideArithmetic.SubtractSigned320(
 7793                WideArithmetic.AddSigned320(shapeAxial, slabRational),
 7794                centerRational),
 7795            GetRationalDenominator(),
 7796            shapeUsesSphericalRadius
 7797                ? CreateCapsuleRadical(projectionAxis, shapeRadius)
 7798                : CreateCylinderRadical(
 7799                    projectionAxis,
 7800                    shapeAxis,
 7801                    shapeRadius),
 7802            CreateCapsuleSlabRadical(
 7803                projectionAxis,
 7804                slabCapsuleRadius));
 7805    }
 806
 807    private static Signed320 CreateCapsuleSlabRational(
 808        Vector3d projectionAxis,
 809        Vector2d slabCapsuleAxis,
 810        Fixed64 slabCapsuleLength,
 811        Fixed64 slabHalfThickness)
 812    {
 17813        var worldSlabAxis = new Vector3d(
 17814            slabCapsuleAxis.X,
 17815            Fixed64.Zero,
 17816            slabCapsuleAxis.Y);
 17817        Signed320 planarAxial = WideArithmetic.MultiplySigned192(
 17818            WideArithmetic.Absolute(GetDot(worldSlabAxis, projectionAxis)),
 17819            Signed192.Signed(
 17820                slabCapsuleLength.m_rawValue));
 17821        Signed320 vertical = WideArithmetic.MultiplySigned192(
 17822            WideArithmetic.Absolute(GetDot(Vector3d.Up, projectionAxis)),
 17823            Signed192.Signed(
 17824                slabHalfThickness.m_rawValue));
 17825        return WideArithmetic.AddSigned320(
 17826            planarAxial,
 17827            WideArithmetic.AddSigned320(vertical, vertical));
 828    }
 829
 830    private static Radical CreateCapsuleSlabRadical(
 831        Vector3d projectionAxis,
 832        Fixed64 radius) =>
 17833        CreateCylinderRadical(
 17834            projectionAxis,
 17835            Vector3d.Up,
 17836            radius);
 837
 838    private static Radical CreateZeroRadical() =>
 3839        new(default, ScaleSquared);
 840
 841    private static Signed192 GetRationalDenominator()
 842    {
 17843        Signed320 wide = WideArithmetic.MultiplySigned192(
 17844            DoubleScale,
 17845            Scale);
 17846        return new Signed192(
 17847            wide.Word2,
 17848            wide.Word1,
 17849            wide.Word0);
 850    }
 851
 852    private static bool IsRadicalAtLeastRatio(
 853        Radical radical,
 854        Signed320 ratioNumerator) =>
 5855        WideArithmetic.CompareNonNegativeRadicalSumToRatio(
 5856            radical.Numerator,
 5857            radical.Denominator,
 5858            default,
 5859            ScaleSquared,
 5860            ratioNumerator,
 5861            ScaleSquared) >= 0;
 862
 863    private static int CompareProjectionDepthsWithoutSharedSecond(
 864        ProjectionDepth left,
 865        ProjectionDepth right)
 866    {
 8867        Signed576 unit = Signed576.ExtendValue(
 8868            Signed320.ExtendValue(
 8869                Signed192.Signed(1L)));
 8870        return WideArithmetic.CompareRadialProjectionDepths(
 8871            Signed704.ExtendValue(
 8872                Signed576.ExtendValue(
 8873                    left.RationalNumerator)),
 8874            Signed320.ExtendValue(
 8875                left.RationalDenominator),
 8876            Signed832.ExtendValue(
 8877                left.First.Numerator),
 8878            Signed576.ExtendValue(
 8879                Signed320.ExtendValue(
 8880                    left.First.Denominator)),
 8881            unit,
 8882            Signed704.ExtendValue(
 8883                Signed576.ExtendValue(
 8884                    right.RationalNumerator)),
 8885            Signed320.ExtendValue(
 8886                right.RationalDenominator),
 8887            Signed832.ExtendValue(
 8888                right.First.Numerator),
 8889            Signed576.ExtendValue(
 8890                Signed320.ExtendValue(
 8891                    right.First.Denominator)),
 8892            unit);
 893    }
 894}

Methods/Properties

.cctor()
.ctor(FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideFiniteAxisProjection/Radical,FixedMathSharp.Geometry.WideFiniteAxisProjection/Radical)
.ctor(FixedMathSharp.Signed576,FixedMathSharp.Signed192)
DoCylinderCapsuleOverlapOnAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TryGetCylinderCapsuleAxisPenetration(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&)
TryGetCylinderCapsuleAxisPenetration(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&,System.Boolean&)
DoCylindersOverlapOnAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TryGetCylindersAxisPenetration(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&)
TryGetCylindersAxisPenetration(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&,System.Boolean&)
CreateCylinderCapsuleDepth(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth&)
CreateCylinderDepth(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth&)
CreateRationalDepth(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Signed320&,FixedMathSharp.Signed192&)
CreateCylinderRadical(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64)
CreateCapsuleRadical(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64)
TryMaterializeDepth(FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth,FixedMathSharp.Vector3d,FixedMathSharp.Signed192,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&,System.Boolean&)
TryMaterializeDepth(FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&,System.Boolean&)
TryGetRadicalApproximation(FixedMathSharp.Geometry.WideFiniteAxisProjection/Radical,FixedMathSharp.Fixed64&)
GetRoundedDepthByExactSearch(FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth)
CorrectRoundedDepth(FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth,FixedMathSharp.Fixed64&)
CompareToTwiceRaw(FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth,FixedMathSharp.Signed192)
GetDot(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetDot(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetScaleSquared()
TryGetCapsuleCapsuleSlabAxisPenetration(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&,System.Boolean&)
TryGetCylinderCapsuleSlabAxisPenetration(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&,System.Boolean&)
TryGetConeCapsuleSlabAxisPenetration(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Fixed64&,System.Boolean&)
CreateSymmetricCapsuleSlabDepth(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth&)
CreateCapsuleSlabRational(FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CreateCapsuleSlabRadical(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64)
CreateZeroRadical()
GetRationalDenominator()
IsRadicalAtLeastRatio(FixedMathSharp.Geometry.WideFiniteAxisProjection/Radical,FixedMathSharp.Signed320)
CompareProjectionDepthsWithoutSharedSecond(FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth,FixedMathSharp.Geometry.WideFiniteAxisProjection/ProjectionDepth)