< Summary

Information
Class: FixedMathSharp.Geometry.WideCenteredCapsule2dRelations
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideCenteredCapsule2dRelations.cs
Line coverage
100%
Covered lines: 486
Uncovered lines: 0
Coverable lines: 486
Total lines: 859
Line coverage: 100%
Branch coverage
100%
Covered branches: 136
Total branches: 136
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/Convex/WideCenteredCapsule2dRelations.cs

#LineLine coverage
 1//=======================================================================
 2// WideCenteredCapsule2dRelations.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using RotationFrame2d = FixedMathSharp.Geometry.WideConvex2dRelations.RotationFrame2d;
 10
 11namespace FixedMathSharp.Geometry;
 12
 13/// <summary>
 14/// Owns rigid-frame full-domain relations for conceptual 2D capsules.
 15/// </summary>
 16internal static class WideCenteredCapsule2dRelations
 17{
 18    /// <summary>Returns the exact world direction from an anchored point toward its closest finite core point.</summary
 19    internal static WideDirection3d GetPointToCoreDirection(Vector2d origin, Fixed64 rotation,
 20        Fixed64 coreLength, in FixedPointAnchor2d point)
 21    {
 622        RationalPoint3d start = RationalPoint3d.FromAnchor(WideFiniteAxisIntersection.GetCenteredCapsuleSupportAnchor(
 623            origin, rotation, Vector2d.Forward, coreLength, Fixed64.Zero, -Vector2d.Forward));
 624        RationalPoint3d end = RationalPoint3d.FromAnchor(WideFiniteAxisIntersection.GetCenteredCapsuleSupportAnchor(
 625            origin, rotation, Vector2d.Forward, coreLength, Fixed64.Zero, Vector2d.Forward));
 626        Signed192 denominator = WideArithmetic.TruncateSigned320By64(start.Denominator);
 627        WideDirection3d edge = WideTriangleRelations.GetScaledPointDifference(end, start, denominator),
 628            offset = WideTriangleRelations.GetScaledPointDifference(RationalPoint3d.FromAnchor(point), start, denominato
 629        Signed320 n = Signed320.NarrowValue(Signed576.NarrowValue(WideDirection3d.Dot(edge, offset))),
 630            d = Signed320.NarrowValue(Signed576.NarrowValue(WideDirection3d.Dot(edge, edge)));
 831        if (n.Sign <= 0) return -offset;
 432        if (WideArithmetic.SubtractSigned320(n, d).Sign >= 0)
 133            return new(WideArithmetic.SubtractSigned576(edge.X, offset.X), default(Signed576),
 134                WideArithmetic.SubtractSigned576(edge.Z, offset.Z));
 35        // All planar anchors share 2 Q²: differences need fewer than 131 bits,
 36        // dot products fewer than 264, and these cleared products fewer than 396.
 337        return new(Signed576.NarrowValue(WideArithmetic.SubtractSigned832(
 338                WideArithmetic.MultiplySigned576ToSigned832(edge.X, n), WideArithmetic.MultiplySigned576ToSigned832(offs
 339            default(Signed576), Signed576.NarrowValue(WideArithmetic.SubtractSigned832(
 340                WideArithmetic.MultiplySigned576ToSigned832(edge.Z, n), WideArithmetic.MultiplySigned576ToSigned832(offs
 41    }
 42
 43    // Full-domain bounds (S = 2^32): relative point numerators are below 2^97,
 44    // exact axis components below 2^99, and signed overlaps below 2^199.
 45    // Squared-overlap/axis products stay below 2^597, fitting Signed832.
 46    // No world endpoint, unit axis, or radial square root is narrowed to Fixed64
 47    // until classification and minimum-depth ordering are complete.
 148    private static readonly Fixed64 SideAlignmentTolerance =
 149        Fixed64.Epsilon * (Fixed64)16;
 50
 51    private readonly struct ContactAxis
 52    {
 53        internal readonly Signed192 X;
 54        internal readonly Signed192 Y;
 55        internal readonly Signed320 SquaredLength;
 56        internal readonly Signed320 Overlap;
 57        internal readonly bool FromEdge;
 58
 640259        internal bool HasValue => !SquaredLength.IsZero;
 60
 61        internal ContactAxis(
 62            Signed192 x,
 63            Signed192 y,
 64            Signed320 squaredLength,
 65            Signed320 overlap,
 66            bool fromEdge)
 67        {
 798368            X = x;
 798369            Y = y;
 798370            SquaredLength = squaredLength;
 798371            Overlap = overlap;
 798372            FromEdge = fromEdge;
 798373        }
 74    }
 75
 76    /// <summary>
 77    /// Finds a contained or boundary point's minimum-separation normal toward a
 78    /// rotated nondegenerate closed convex polygon. Outside points return false
 79    /// and zero.
 80    /// </summary>
 81    /// <remarks>
 82    /// The caller supplies a validated convex boundary. Uses the same exact
 83    /// signed depth/axis ranking and feature ties as point contacts. Only the
 84    /// normalized direction is rounded to Q32.32; no depth
 85    /// or contact anchor is materialized.
 86    /// </remarks>
 87    internal static bool TryGetPointMinimumTranslationNormal(
 88        Vector2d point,
 89        Vector2d convexOrigin,
 90        Fixed64 convexRotation,
 91        ReadOnlySpan<Vector2d> convexOriginOffsets,
 92        out Vector2d normal)
 93    {
 994        normal = default;
 995        if (!TryGetContactAxis(
 996                point, Vector2d.Right, Fixed64.Zero, Fixed64.Zero,
 997                convexOrigin, convexRotation, convexOriginOffsets,
 998                strict: false, out ContactAxis best, pointFaceAxesOnly: true))
 199            return false;
 100
 8101        normal = WideNormalization.GetNormalized(best.X, best.Y);
 8102        return true;
 103    }
 104
 105    internal static bool TryGetMinimumTranslation(
 106        Vector2d center,
 107        Vector2d capsuleAxis,
 108        Fixed64 axisLength,
 109        Fixed64 radius,
 110        Vector2d convexOrigin,
 111        ReadOnlySpan<Vector2d> convexOriginOffsets,
 112        out Vector2d normal,
 113        out Fixed64 depth) =>
 24114        TryGetMinimumTranslation(
 24115            center,
 24116            capsuleAxis,
 24117            axisLength,
 24118            radius,
 24119            convexOrigin,
 24120            Fixed64.Zero,
 24121            convexOriginOffsets,
 24122            out normal,
 24123            out depth);
 124
 125    internal static bool TryGetMinimumTranslation(
 126        Vector2d center,
 127        Vector2d capsuleAxis,
 128        Fixed64 axisLength,
 129        Fixed64 radius,
 130        Vector2d convexOrigin,
 131        Fixed64 convexRotation,
 132        ReadOnlySpan<Vector2d> convexOriginOffsets,
 133        out Vector2d normal,
 134        out Fixed64 depth) =>
 1314135        TryGetMinimumTranslation(
 1314136            center,
 1314137            capsuleAxis,
 1314138            axisLength,
 1314139            radius,
 1314140            convexOrigin,
 1314141            convexRotation,
 1314142            convexOriginOffsets,
 1314143            out normal,
 1314144            out depth,
 1314145            out _,
 1314146            out _);
 147
 148    /// <summary>Tests exact closed contact or strict penetration without materializing contact anchors or depth.</summa
 149    internal static bool DoesCapsuleOverlapConvex(
 150        Vector2d center,
 151        Vector2d capsuleAxis,
 152        Fixed64 axisLength,
 153        Fixed64 radius,
 154        Vector2d convexOrigin,
 155        Fixed64 convexRotation,
 156        ReadOnlySpan<Vector2d> convexOriginOffsets,
 157        bool strict = true) =>
 1320158        TryGetContactAxis(
 1320159            center, capsuleAxis, axisLength, radius,
 1320160            convexOrigin, convexRotation, convexOriginOffsets,
 1320161            strict, out _);
 162
 163    internal static bool TryGetContacts(
 164        Vector2d capsuleCenter,
 165        Fixed64 capsuleRotation,
 166        Vector2d localCapsuleAxis,
 167        Fixed64 axisLength,
 168        Fixed64 radius,
 169        Vector2d convexOrigin,
 170        Fixed64 convexRotation,
 171        ReadOnlySpan<Vector2d> convexVertexOffsets,
 172        Span<FixedPointAnchor2d> capsuleContacts,
 173        Span<FixedPointAnchor2d> convexContacts,
 174        out int contactCount,
 175        out Vector2d normal,
 176        out Fixed64 depth,
 177        out bool depthIsClamped)
 178    {
 507179        _ = Vector2d.TryRotate(
 507180            localCapsuleAxis,
 507181            capsuleRotation,
 507182            out Vector2d capsuleAxis);
 507183        if (!TryGetMinimumTranslation(
 507184                capsuleCenter,
 507185                capsuleAxis,
 507186                axisLength,
 507187                radius,
 507188                convexOrigin,
 507189                convexRotation,
 507190                convexVertexOffsets,
 507191                out normal,
 507192                out depth,
 507193                out depthIsClamped,
 507194                out ContactAxis contactAxis))
 195        {
 255196            contactCount = default;
 255197            return false;
 198        }
 199
 252200        _ = Vector2d.TryRotate(
 252201            normal,
 252202            -capsuleRotation,
 252203            out Vector2d localNormal);
 252204        localNormal = localNormal.Normalized;
 252205        GetSupportFeature(
 252206            capsuleCenter,
 252207            convexOrigin,
 252208            new RotationFrame2d(convexRotation),
 252209            convexVertexOffsets,
 252210            contactAxis,
 252211            out Vector2d featureStart,
 252212            out Vector2d featureEnd);
 252213        Vector2d featureDirection = WideNormalization.GetDirection(featureStart, featureEnd);
 252214        if (axisLength > Fixed64.Epsilon
 252215            && featureDirection != Vector2d.Zero
 252216            && Vector2d.Dot(capsuleAxis, normal).Abs()
 252217                <= SideAlignmentTolerance)
 218        {
 7219            FixedPointAnchor2d firstCapsuleAnchor =
 7220                GetCenteredCapsuleSideAnchor(
 7221                    capsuleCenter,
 7222                    capsuleRotation,
 7223                    localCapsuleAxis,
 7224                    -axisLength,
 7225                    localNormal,
 7226                    radius);
 7227            FixedPointAnchor2d secondCapsuleAnchor =
 7228                GetCenteredCapsuleSideAnchor(
 7229                    capsuleCenter,
 7230                    capsuleRotation,
 7231                    localCapsuleAxis,
 7232                    axisLength,
 7233                    localNormal,
 7234                    radius);
 7235            if (WideConvex2dRelations.TryProjectAnchorOntoFeature(
 7236                    firstCapsuleAnchor,
 7237                    convexOrigin,
 7238                    convexRotation,
 7239                    featureStart,
 7240                    featureEnd,
 7241                    requireInteriorProjection: true,
 7242                    out Vector2d firstConvexOffset)
 7243                && WideConvex2dRelations.TryProjectAnchorOntoFeature(
 7244                    secondCapsuleAnchor,
 7245                    convexOrigin,
 7246                    convexRotation,
 7247                    featureStart,
 7248                    featureEnd,
 7249                    requireInteriorProjection: true,
 7250                    out Vector2d secondConvexOffset))
 251            {
 4252                capsuleContacts[0] = firstCapsuleAnchor;
 4253                capsuleContacts[1] = secondCapsuleAnchor;
 4254                convexContacts[0] = new FixedPointAnchor2d(
 4255                    convexOrigin,
 4256                    convexRotation,
 4257                    firstConvexOffset);
 4258                convexContacts[1] = new FixedPointAnchor2d(
 4259                    convexOrigin,
 4260                    convexRotation,
 4261                    secondConvexOffset);
 4262                contactCount = 2;
 4263                return true;
 264            }
 265        }
 266
 248267        FixedPointAnchor2d capsuleContact =
 248268            WideFiniteAxisIntersection.GetCenteredCapsuleSupportAnchor(
 248269                capsuleCenter,
 248270                capsuleRotation,
 248271                localCapsuleAxis,
 248272                axisLength,
 248273                radius,
 248274                localNormal);
 248275        _ = WideConvex2dRelations.TryProjectAnchorOntoFeature(
 248276            capsuleContact,
 248277            convexOrigin,
 248278            convexRotation,
 248279            featureStart,
 248280            featureEnd,
 248281            requireInteriorProjection: false,
 248282            out Vector2d convexOffset);
 283
 284        // A side support is an entire segment, not its arbitrary midpoint.
 285        // Resolve its axial witness from the opposing feature using the exact
 286        // selected axis; a rounded normal can turn a side tie into an end cap.
 248287        if (axisLength > Fixed64.Zero
 248288            && WideArithmetic.AddSigned320(
 248289                WideArithmetic.MultiplySigned192(contactAxis.X, Signed192.Raw(capsuleAxis.X)),
 248290                WideArithmetic.MultiplySigned192(contactAxis.Y, Signed192.Raw(capsuleAxis.Y))).IsZero)
 291        {
 69292            capsuleContact = GetProjectedSideAnchor(
 69293                capsuleCenter, capsuleRotation, localCapsuleAxis, axisLength,
 69294                localNormal, radius, convexOrigin, convexRotation, convexOffset);
 295        }
 296
 248297        capsuleContacts[0] = capsuleContact;
 248298        convexContacts[0] = new FixedPointAnchor2d(
 248299            convexOrigin,
 248300            convexRotation,
 248301            convexOffset);
 248302        contactCount = 1;
 248303        return true;
 304    }
 305
 306    /// <summary>Admits an original finite vertex normal against all exact incident sectors before normalization.</summa
 307    internal static bool TryGetBoundaryVertexContact(Vector2d center, Fixed64 rotation, Fixed64 axisLength,
 308        Fixed64 radius, in FixedPointAnchor2d vertex, ReadOnlySpan<FixedPointAnchor2d> incidentPoints,
 309        out FixedContactAnchors2d contact)
 310    {
 9311        _ = Vector2d.TryRotate(Vector2d.Forward, rotation, out Vector2d axis);
 9312        Span<Vector2d> point = stackalloc Vector2d[1] { vertex.LocalPoint };
 9313        if (!TryGetContactAxis(center, axis, axisLength, radius, vertex.Origin, vertex.Rotation, point,
 13314            strict: false, out ContactAxis best)) { contact = default; return false; }
 7315        if (!WideConvex2dRelations.SupportsBoundaryFan(best.X, best.Y, vertex, incidentPoints))
 316        {
 317            // A point on the core has tied opposite side directions. Do not
 318            // let the ordinary authored-direction tie hide an admissible side.
 4319            if (!best.Overlap.IsZero || !WideConvex2dRelations.SupportsBoundaryFan(
 4320                WideArithmetic.Negate(best.X), WideArithmetic.Negate(best.Y), vertex, incidentPoints))
 6321            { contact = default; return false; }
 1322            best = new ContactAxis(WideArithmetic.Negate(best.X), WideArithmetic.Negate(best.Y),
 1323                best.SquaredLength, best.Overlap, best.FromEdge);
 324        }
 4325        Vector2d normal = WideNormalization.GetNormalized(best.X, best.Y);
 4326        _ = Vector2d.TryRotate(normal, -rotation, out Vector2d localNormal);
 4327        localNormal = localNormal.Normalized;
 4328        FixedPointAnchor2d anchor = WideFiniteAxisIntersection.GetCenteredCapsuleSupportAnchor(
 4329            center, rotation, Vector2d.Forward, axisLength, radius, localNormal);
 4330        if (axisLength > Fixed64.Zero && WideArithmetic.AddProducts(best.X, Signed192.Raw(axis.X),
 4331            best.Y, Signed192.Raw(axis.Y)).IsZero)
 2332            anchor = GetProjectedSideAnchor(center, rotation, Vector2d.Forward, axisLength, localNormal,
 2333                radius, vertex.Origin, vertex.Rotation, vertex.LocalPoint);
 4334        contact = new FixedContactAnchors2d(anchor, vertex, normal, GetDepth(best, radius, out bool clamped), clamped);
 4335        return true;
 336    }
 337
 338    private static FixedPointAnchor2d GetProjectedSideAnchor(
 339        Vector2d center,
 340        Fixed64 rotation,
 341        Vector2d localAxis,
 342        Fixed64 axisLength,
 343        Vector2d localNormal,
 344        Fixed64 radius,
 345        Vector2d pointOrigin,
 346        Fixed64 pointRotation,
 347        Vector2d pointOffset)
 348    {
 71349        RotationFrame2d frame = new(rotation);
 71350        WideConvex2dRelations.GetRotatedOffset(frame, localAxis,
 71351            out Signed192 axisX, out Signed192 axisY);
 71352        WideConvex2dRelations.GetRotatedOffset(frame, localNormal,
 71353            out Signed192 radialX, out Signed192 radialY);
 71354        GetRelativePointNumerators(pointOrigin, new RotationFrame2d(pointRotation),
 71355            pointOffset, center, out Signed192 pointX, out Signed192 pointY);
 356
 357        // Axis and point numerators have denominator S^2. Subtract the radial
 358        // support at denominator S^3 before projecting onto the conceptual side.
 359        // Twice the local axial distance in raw units is 2*dot(delta,axis)/|axis|^2.
 71360        Signed192 deltaX = Signed192.NarrowValue(WideArithmetic.SubtractSigned320(
 71361            WideArithmetic.MultiplySigned192(pointX, Signed192.One),
 71362            WideArithmetic.MultiplySigned192(radialX, Signed192.Raw(radius))));
 71363        Signed192 deltaY = Signed192.NarrowValue(WideArithmetic.SubtractSigned320(
 71364            WideArithmetic.MultiplySigned192(pointY, Signed192.One),
 71365            WideArithmetic.MultiplySigned192(radialY, Signed192.Raw(radius))));
 71366        Signed320 projection = WideArithmetic.AddSigned320(
 71367            WideArithmetic.MultiplySigned192(deltaX, axisX),
 71368            WideArithmetic.MultiplySigned192(deltaY, axisY));
 71369        Signed320 numerator = WideArithmetic.AddSigned320(projection, projection);
 71370        Signed320 denominator = WideArithmetic.AddSigned320(
 71371            WideArithmetic.MultiplySigned192(axisX, axisX),
 71372            WideArithmetic.MultiplySigned192(axisY, axisY));
 71373        Signed576 limit = WideArithmetic.MultiplySigned320(denominator, Signed192.Raw(axisLength));
 71374        Signed576 signedNumerator = Signed576.ExtendValue(numerator);
 375        Fixed64 signedLength;
 71376        if (WideArithmetic.SubtractSigned576(signedNumerator, limit).Sign >= 0)
 1377            signedLength = axisLength;
 70378        else if (WideArithmetic.AddSigned576(signedNumerator, limit).Sign <= 0)
 1379            signedLength = -axisLength;
 380        else
 69381            _ = Fixed64.TryGetSignedRawRatio(signedNumerator,
 69382                Signed576.ExtendValue(denominator), out signedLength);
 383
 71384        return GetCenteredCapsuleSideAnchor(
 71385            center, rotation, localAxis, signedLength, localNormal, radius);
 386    }
 387
 388    private static FixedPointAnchor2d GetCenteredCapsuleSideAnchor(
 389        Vector2d center,
 390        Fixed64 rotation,
 391        Vector2d localAxis,
 392        Fixed64 signedAxisLength,
 393        Vector2d localRadialDirection,
 394        Fixed64 radius)
 395    {
 85396        Vector2d axialOffset =
 85397            localAxis * (signedAxisLength / Fixed64.Two);
 85398        Vector2d radialOffset = localRadialDirection * radius;
 85399        FixedPointAnchorTerm2d exactLocalTerm =
 85400            FixedPointAnchorTerm2d.CreateCenteredAxisSupport(
 85401                localAxis,
 85402                signedAxisLength,
 85403                localRadialDirection,
 85404                radius,
 85405                axialOffset,
 85406                radialOffset);
 85407        return new FixedPointAnchor2d(
 85408            center,
 85409            rotation,
 85410            axialOffset,
 85411            radialOffset,
 85412            exactLocalTerm);
 413    }
 414
 415    private static bool TryGetMinimumTranslation(
 416        Vector2d center,
 417        Vector2d capsuleAxis,
 418        Fixed64 axisLength,
 419        Fixed64 radius,
 420        Vector2d convexOrigin,
 421        Fixed64 convexRotation,
 422        ReadOnlySpan<Vector2d> convexOriginOffsets,
 423        out Vector2d normal,
 424        out Fixed64 depth,
 425        out bool depthIsClamped,
 426        out ContactAxis best)
 427    {
 1821428        normal = default;
 1821429        depth = default;
 1821430        depthIsClamped = false;
 1821431        if (!TryGetContactAxis(
 1821432                center, capsuleAxis, axisLength, radius,
 1821433                convexOrigin, convexRotation, convexOriginOffsets,
 1821434                strict: false, out best))
 435        {
 1300436            return false;
 437        }
 438
 521439        normal = WideNormalization.GetNormalized(best.X, best.Y);
 521440        depth = GetDepth(best, radius, out depthIsClamped);
 521441        return true;
 442    }
 443
 444    private static bool TryGetContactAxis(
 445        Vector2d center,
 446        Vector2d capsuleAxis,
 447        Fixed64 axisLength,
 448        Fixed64 radius,
 449        Vector2d convexOrigin,
 450        Fixed64 convexRotation,
 451        ReadOnlySpan<Vector2d> convexOriginOffsets,
 452        bool strict,
 453        out ContactAxis best,
 454        bool pointFaceAxesOnly = false)
 455    {
 3159456        RotationFrame2d frame = new(convexRotation);
 3159457        best = default;
 15384458        for (int i = 0; i < convexOriginOffsets.Length; i++)
 459        {
 6692460            WideConvex2dRelations.GetRotatedOffset(
 6692461                frame, convexOriginOffsets[i],
 6692462                out Signed192 startX, out Signed192 startY);
 6692463            WideConvex2dRelations.GetRotatedOffset(
 6692464                frame, convexOriginOffsets[(i + 1) % convexOriginOffsets.Length],
 6692465                out Signed192 endX, out Signed192 endY);
 6692466            Signed192 axisX = WideArithmetic.SubtractSigned192(startY, endY);
 6692467            Signed192 axisY = WideArithmetic.SubtractSigned192(endX, startX);
 6692468            if (axisX.IsZero && axisY.IsZero)
 469                continue;
 470
 6379471            if (!TryKeepAxis(
 6379472                    center, capsuleAxis, axisLength, radius,
 6379473                    convexOrigin, frame, convexOriginOffsets,
 6379474                    axisX, axisY, true, strict, ref best))
 475            {
 2159476                return false;
 477            }
 478        }
 479
 480        // The admitted nondegenerate point-normal path separates through a
 481        // face. General contacts retain vertex axes for degenerate boundaries.
 1000482        if (pointFaceAxesOnly)
 8483            return best.HasValue;
 484
 485        // The segment contributes its own pair of sides to the polygon's
 486        // Minkowski expansion. A closest endpoint/vertex axis need not cover it.
 992487        if (axisLength > Fixed64.Zero
 992488            && !TryKeepAxis(
 992489                center, capsuleAxis, axisLength, radius,
 992490                convexOrigin, frame, convexOriginOffsets,
 992491                WideArithmetic.Negate(Signed192.Raw(capsuleAxis.Y)),
 992492                Signed192.Raw(capsuleAxis.X), false, strict, ref best))
 493        {
 87494            return false;
 495        }
 496
 905497        GetClosestVertexAxis(
 905498            center, capsuleAxis, axisLength,
 905499            convexOrigin, frame, convexOriginOffsets,
 905500            out Signed192 closestX, out Signed192 closestY);
 905501        if ((!closestX.IsZero || !closestY.IsZero)
 905502            && !TryKeepAxis(
 905503                center, capsuleAxis, axisLength, radius,
 905504                convexOrigin, frame, convexOriginOffsets,
 905505                closestX, closestY, false, strict, ref best))
 506        {
 123507            return false;
 508        }
 509
 510        // A coincident point and zero-length core have no geometric axis;
 511        // any cardinal axis gives their exact radial depth, including zero.
 782512        return best.HasValue || TryKeepAxis(
 782513            center, capsuleAxis, axisLength, radius, convexOrigin, frame, convexOriginOffsets,
 782514            Signed192.One, default, false, strict, ref best);
 515    }
 516
 517    private static void GetClosestVertexAxis(
 518        Vector2d center,
 519        Vector2d capsuleAxis,
 520        Fixed64 axisLength,
 521        Vector2d convexOrigin,
 522        RotationFrame2d convexRotation,
 523        ReadOnlySpan<Vector2d> convexOriginOffsets,
 524        out Signed192 bestX,
 525        out Signed192 bestY)
 526    {
 905527        bool found = false;
 905528        bestX = default;
 905529        bestY = default;
 905530        Signed576 bestSquaredDistance = default;
 905531        Signed192 directionSquared = Signed192.NarrowValue(
 905532            WideArithmetic.AddSigned320(
 905533                WideArithmetic.MultiplySigned192(
 905534                    Signed192.Raw(capsuleAxis.X), Signed192.Raw(capsuleAxis.X)),
 905535                WideArithmetic.MultiplySigned192(
 905536                    Signed192.Raw(capsuleAxis.Y), Signed192.Raw(capsuleAxis.Y))));
 8758537        for (int i = 0; i < convexOriginOffsets.Length; i++)
 538        {
 3474539            GetDirectionFromCenteredAxis(
 3474540                convexOrigin, convexRotation, convexOriginOffsets[i],
 3474541                center, capsuleAxis, axisLength, directionSquared,
 3474542                out Signed192 candidateX, out Signed192 candidateY,
 3474543                out Signed576 candidateSquaredDistance);
 3474544            if (candidateX.IsZero && candidateY.IsZero)
 545                continue;
 3230546            if (found && WideArithmetic.CompareNonNegative(
 3230547                    candidateSquaredDistance, bestSquaredDistance) >= 0)
 548            {
 549                continue;
 550            }
 551
 1755552            found = true;
 1755553            bestX = candidateX;
 1755554            bestY = candidateY;
 1755555            bestSquaredDistance = candidateSquaredDistance;
 556        }
 905557    }
 558
 559    private static void GetDirectionFromCenteredAxis(
 560        Vector2d pointOrigin,
 561        RotationFrame2d pointRotation,
 562        Vector2d pointOriginOffset,
 563        Vector2d axisCenter,
 564        Vector2d axisDirection,
 565        Fixed64 axisLength,
 566        Signed192 directionSquared,
 567        out Signed192 directionX,
 568        out Signed192 directionY,
 569        out Signed576 squaredDistance)
 570    {
 3474571        GetRelativePointNumerators(
 3474572            pointOrigin, pointRotation, pointOriginOffset, axisCenter,
 3474573            out Signed192 relativeX, out Signed192 relativeY);
 3474574        Signed192 axisX = Signed192.Raw(axisDirection.X);
 3474575        Signed192 axisY = Signed192.Raw(axisDirection.Y);
 3474576        Signed320 projection = WideArithmetic.AddSigned320(
 3474577            WideArithmetic.MultiplySigned192(relativeX, axisX),
 3474578            WideArithmetic.MultiplySigned192(relativeY, axisY));
 3474579        Signed320 doubleProjection = WideArithmetic.AddSigned320(projection, projection);
 3474580        Signed320 axialThreshold = WideArithmetic.MultiplySigned192(
 3474581            Signed192.Raw(axisLength), directionSquared);
 582
 583        // A supplied normalized direction still has representable components.
 584        // Use its actual squared length when clamping the closest parameter.
 3474585        if (WideArithmetic.SubtractSigned320(doubleProjection, axialThreshold).Sign > 0
 3474586            || WideArithmetic.AddSigned320(doubleProjection, axialThreshold).Sign < 0)
 587        {
 2228588            Signed192 signedLength = projection.Sign > 0
 2228589                ? Signed192.Raw(axisLength)
 2228590                : WideArithmetic.Negate(Signed192.Raw(axisLength));
 2228591            directionX = WideArithmetic.SubtractSigned192(
 2228592                WideArithmetic.AddSigned192(relativeX, relativeX),
 2228593                Signed192.NarrowValue(WideArithmetic.MultiplySigned192(axisX, signedLength)));
 2228594            directionY = WideArithmetic.SubtractSigned192(
 2228595                WideArithmetic.AddSigned192(relativeY, relativeY),
 2228596                Signed192.NarrowValue(WideArithmetic.MultiplySigned192(axisY, signedLength)));
 2228597            Signed320 endpointSquared = WideArithmetic.AddSigned320(
 2228598                WideArithmetic.MultiplySigned192(directionX, directionX),
 2228599                WideArithmetic.MultiplySigned192(directionY, directionY));
 2228600            squaredDistance = WideArithmetic.MultiplySigned320(endpointSquared, directionSquared);
 2228601            return;
 602        }
 603
 1246604        Signed320 cross = WideArithmetic.SubtractSigned320(
 1246605            WideArithmetic.MultiplySigned192(axisX, relativeY),
 1246606            WideArithmetic.MultiplySigned192(axisY, relativeX));
 1246607        directionX = cross.IsZero ? default : WideArithmetic.Negate(axisY);
 1246608        directionY = cross.IsZero ? default : axisX;
 1246609        if (cross.Sign < 0)
 610        {
 488611            directionX = WideArithmetic.Negate(directionX);
 488612            directionY = WideArithmetic.Negate(directionY);
 613        }
 614
 615        // Endpoint and interior distances share denominator 4 * |direction|^2.
 616        // The interior axis is exactly perpendicular, without a rounded projection.
 1246617        Signed320 twiceCross = WideArithmetic.AddSigned320(cross, cross);
 1246618        squaredDistance = WideArithmetic.MultiplySigned320(twiceCross, twiceCross);
 1246619    }
 620
 621    private static void GetSupportFeature(
 622        Vector2d center,
 623        Vector2d convexOrigin,
 624        RotationFrame2d convexRotation,
 625        ReadOnlySpan<Vector2d> convexOriginOffsets,
 626        ContactAxis axis,
 627        out Vector2d featureStart,
 628        out Vector2d featureEnd)
 629    {
 252630        if (axis.FromEdge)
 631        {
 44632            WideConvex2dRelations.GetMinimumSupportFeature(convexOrigin, convexRotation, convexOriginOffsets,
 44633                axis.X, axis.Y, out featureStart, out featureEnd);
 44634            return;
 635        }
 636
 208637        int minimumIndex = 0;
 208638        Signed320 minimum = GetRelativeProjection(
 208639            center,
 208640            convexOrigin,
 208641            convexRotation,
 208642            convexOriginOffsets[0],
 208643            axis.X, axis.Y);
 1520644        for (int i = 1; i < convexOriginOffsets.Length; i++)
 645        {
 552646            Signed320 projection = GetRelativeProjection(
 552647                center,
 552648                convexOrigin,
 552649                convexRotation,
 552650                convexOriginOffsets[i],
 552651                axis.X, axis.Y);
 552652            if (WideArithmetic.SubtractSigned320(projection, minimum).Sign < 0)
 653            {
 232654                minimum = projection;
 232655                minimumIndex = i;
 656            }
 657        }
 658
 208659        featureStart = convexOriginOffsets[minimumIndex];
 208660        featureEnd = featureStart;
 208661    }
 662
 663    private static bool TryKeepAxis(
 664        Vector2d center,
 665        Vector2d capsuleAxis,
 666        Fixed64 axisLength,
 667        Fixed64 radius,
 668        Vector2d convexOrigin,
 669        RotationFrame2d convexRotation,
 670        ReadOnlySpan<Vector2d> convexOriginOffsets,
 671        Signed192 axisX,
 672        Signed192 axisY,
 673        bool axisFromEdge,
 674        bool strict,
 675        ref ContactAxis best)
 676    {
 7982677        GetRelativeProjectionRange(
 7982678            center, convexOrigin, convexRotation, convexOriginOffsets,
 7982679            axisX, axisY, out Signed320 minimum, out Signed320 maximum);
 7982680        Signed192 axialAlignment = Signed192.NarrowValue(WideArithmetic.AddSigned320(
 7982681            WideArithmetic.MultiplySigned192(Signed192.Raw(capsuleAxis.X), axisX),
 7982682            WideArithmetic.MultiplySigned192(Signed192.Raw(capsuleAxis.Y), axisY)));
 7982683        if (axialAlignment.Sign < 0)
 3321684            axialAlignment = WideArithmetic.Negate(axialAlignment);
 7982685        Signed320 axialExtent = WideArithmetic.MultiplySigned192(
 7982686            axialAlignment, Signed192.Raw(axisLength));
 7982687        Signed320 positive = WideArithmetic.SubtractSigned320(
 7982688            axialExtent, WideArithmetic.AddSigned320(minimum, minimum));
 7982689        Signed320 negative = WideArithmetic.AddSigned320(
 7982690            axialExtent, WideArithmetic.AddSigned320(maximum, maximum));
 7982691        bool usePositive = WideArithmetic.SubtractSigned320(positive, negative).Sign <= 0;
 7982692        Signed320 overlap = usePositive ? positive : negative;
 7982693        Signed320 axisSquared = WideArithmetic.AddSigned320(
 7982694            WideArithmetic.MultiplySigned192(axisX, axisX),
 7982695            WideArithmetic.MultiplySigned192(axisY, axisY));
 7982696        ContactAxis candidate = new(
 7982697            usePositive ? axisX : WideArithmetic.Negate(axisX),
 7982698            usePositive ? axisY : WideArithmetic.Negate(axisY),
 7982699            axisSquared, overlap, axisFromEdge);
 700
 701        // With S = 2^32, the exact depth in raw units is
 702        // radius.Raw + overlap / (2*S*sqrt(axisSquared)). Test its sign
 703        // before rounding either the axis, radial support, or public depth.
 7982704        int depthSign = CompareDepthToTwiceRaw(candidate, radius, default);
 7982705        if (strict ? depthSign <= 0 : depthSign < 0)
 2370706            return false;
 707        // A boolean strict relation needs no minimum-depth ranking, normal,
 708        // square root, or rounded contact witness.
 5612709        if (!best.HasValue || (!strict && CompareDepths(candidate, best) < 0))
 2267710            best = candidate;
 5612711        return true;
 712    }
 713
 714    private static int CompareDepths(ContactAxis left, ContactAxis right)
 715    {
 716        // The radius is identical on every axis and cancels. Compare signed
 717        // normalized axial overlaps; squaring reverses order for negative ones.
 2362718        int leftSign = left.Overlap.Sign;
 2362719        int rightSign = right.Overlap.Sign;
 2362720        if (leftSign != rightSign)
 456721            return leftSign.CompareTo(rightSign);
 1906722        Signed576 leftSquared = WideArithmetic.MultiplySigned320(left.Overlap, left.Overlap);
 1906723        Signed576 rightSquared = WideArithmetic.MultiplySigned320(right.Overlap, right.Overlap);
 1906724        int comparison = WideArithmetic.SubtractSigned832(
 1906725            WideArithmetic.MultiplySigned576ToSigned832(leftSquared, right.SquaredLength),
 1906726            WideArithmetic.MultiplySigned576ToSigned832(rightSquared, left.SquaredLength)).Sign;
 1906727        return leftSign < 0 ? -comparison : comparison;
 728    }
 729
 730    private static int CompareDepthToTwiceRaw(
 731        ContactAxis axis,
 732        Fixed64 radius,
 733        Signed192 twiceRaw)
 734    {
 8515735        Signed192 threshold = Signed192.NarrowValue(WideArithmetic.MultiplySigned192(
 8515736            WideArithmetic.SubtractSigned192(
 8515737                twiceRaw,
 8515738                WideArithmetic.AddSigned192(Signed192.Raw(radius), Signed192.Raw(radius))),
 8515739            Signed192.One));
 8515740        int overlapSign = axis.Overlap.Sign;
 8515741        int thresholdSign = threshold.Sign;
 8515742        if (overlapSign != thresholdSign)
 2694743            return overlapSign.CompareTo(thresholdSign);
 5821744        Signed576 left = WideArithmetic.MultiplySigned320(axis.Overlap, axis.Overlap);
 5821745        Signed576 right = WideArithmetic.MultiplySigned320(
 5821746            WideArithmetic.MultiplySigned192(threshold, threshold), axis.SquaredLength);
 5821747        int comparison = WideArithmetic.SubtractSigned576(left, right).Sign;
 5821748        return overlapSign < 0 ? -comparison : comparison;
 749    }
 750
 751    private static Fixed64 GetDepth(ContactAxis axis, Fixed64 radius, out bool isClamped)
 752    {
 525753        Signed192 twiceMaximum = WideArithmetic.AddSigned192(
 525754            Signed192.Signed(long.MaxValue), Signed192.Signed(long.MaxValue));
 525755        isClamped = CompareDepthToTwiceRaw(axis, radius, twiceMaximum) > 0;
 525756        if (isClamped)
 13757            return Fixed64.MaxValue;
 758
 512759        Signed320 root = WideArithmetic.GetFloorSquareRootScaledByFixed64(
 512760            Signed576.ExtendValue(axis.SquaredLength));
 512761        long first = GetDepthBound(axis.Overlap, radius, root);
 512762        long second = GetDepthBound(axis.Overlap, radius,
 512763            WideArithmetic.AddSigned320(root, Signed320.ExtendValue(Signed192.Signed(1))));
 512764        long low = Math.Min(first, second);
 512765        long high = Math.Max(first, second);
 766        // The exact root lies between these adjacent integer roots. Their
 767        // rounded depths bound the answer, even for sub-raw axes or cancellation
 768        // against the radius. Only a straddled midpoint needs exact refinement.
 520769        while (low < high)
 770        {
 8771            long candidate = (long)(((ulong)low + (ulong)high + 1UL) >> 1);
 8772            Signed192 midpoint = WideArithmetic.SubtractSigned192(
 8773                WideArithmetic.AddSigned192(
 8774                    Signed192.Signed(candidate), Signed192.Signed(candidate)),
 8775                Signed192.Signed(1));
 8776            int comparison = CompareDepthToTwiceRaw(axis, radius, midpoint);
 8777            if (comparison > 0 || (comparison == 0 && (candidate & 1L) == 0L))
 3778                low = candidate;
 779            else
 5780                high = candidate - 1L;
 781        }
 512782        return Fixed64.FromRaw(low);
 783    }
 784
 785    private static long GetDepthBound(Signed320 overlap, Fixed64 radius, Signed320 scaledRoot)
 786    {
 1024787        Signed320 denominator = WideArithmetic.AddSigned320(scaledRoot, scaledRoot);
 1024788        Signed576 numerator = WideArithmetic.AddSigned576(
 1024789            Signed576.ExtendValue(overlap),
 1024790            WideArithmetic.MultiplySigned320(denominator, Signed192.Raw(radius)));
 1024791        if (numerator.Sign <= 0)
 113792            return 0L;
 911793        Signed576 maximum = WideArithmetic.MultiplySigned320(
 911794            denominator, Signed192.Signed(long.MaxValue));
 911795        if (WideArithmetic.SubtractSigned576(numerator, maximum).Sign >= 0)
 6796            return long.MaxValue;
 797
 798        // Clip the root bound before conversion, so nearest-even narrowing is
 799        // representable even when an approximation lies outside the raw domain.
 905800        _ = Fixed64.TryGetSignedRawRatio(
 905801            numerator, Signed576.ExtendValue(denominator), out Fixed64 bound);
 905802        return bound.m_rawValue;
 803    }
 804
 805    private static void GetRelativeProjectionRange(
 806        Vector2d center,
 807        Vector2d convexOrigin,
 808        RotationFrame2d convexRotation,
 809        ReadOnlySpan<Vector2d> convexOriginOffsets,
 810        Signed192 axisX,
 811        Signed192 axisY,
 812        out Signed320 minimum,
 813        out Signed320 maximum)
 814    {
 7982815        minimum = GetRelativeProjection(
 7982816            center, convexOrigin, convexRotation, convexOriginOffsets[0], axisX, axisY);
 7982817        maximum = minimum;
 62906818        for (int i = 1; i < convexOriginOffsets.Length; i++)
 819        {
 23471820            Signed320 projection = GetRelativeProjection(
 23471821                center, convexOrigin, convexRotation, convexOriginOffsets[i], axisX, axisY);
 23471822            if (WideArithmetic.SubtractSigned320(projection, minimum).Sign < 0)
 4159823                minimum = projection;
 19312824            else if (WideArithmetic.SubtractSigned320(projection, maximum).Sign > 0)
 5253825                maximum = projection;
 826        }
 7982827    }
 828
 829    private static Signed320 GetRelativeProjection(
 830        Vector2d center,
 831        Vector2d pointOrigin,
 832        RotationFrame2d pointRotation,
 833        Vector2d pointOriginOffset,
 834        Signed192 axisX,
 835        Signed192 axisY)
 836    {
 32213837        GetRelativePointNumerators(
 32213838            pointOrigin, pointRotation, pointOriginOffset, center,
 32213839            out Signed192 differenceX, out Signed192 differenceY);
 32213840        return WideArithmetic.AddSigned320(
 32213841            WideArithmetic.MultiplySigned192(differenceX, axisX),
 32213842            WideArithmetic.MultiplySigned192(differenceY, axisY));
 843    }
 844    private static void GetRelativePointNumerators(
 845        Vector2d origin,
 846        RotationFrame2d rotation,
 847        Vector2d offset,
 848        Vector2d center,
 849        out Signed192 x,
 850        out Signed192 y)
 851    {
 35758852        WideConvex2dRelations.GetRotatedOffset(rotation, offset, out x, out y);
 35758853        x = WideArithmetic.AddSigned192(x, WideArithmetic.SubtractSigned192(
 35758854            WideArithmetic.Scale(origin.X), WideArithmetic.Scale(center.X)));
 35758855        y = WideArithmetic.AddSigned192(y, WideArithmetic.SubtractSigned192(
 35758856            WideArithmetic.Scale(origin.Y), WideArithmetic.Scale(center.Y)));
 35758857    }
 858
 859}

Methods/Properties

GetPointToCoreDirection(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedPointAnchor2d&)
.cctor()
get_HasValue()
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Signed320,System.Boolean)
TryGetPointMinimumTranslationNormal(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d&)
TryGetMinimumTranslation(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&)
TryGetMinimumTranslation(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&)
DoesCapsuleOverlapConvex(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Boolean)
TryGetContacts(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Span`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,System.Span`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,System.Int32&,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&,System.Boolean&)
TryGetBoundaryVertexContact(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedPointAnchor2d&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,FixedMathSharp.Geometry.FixedContactAnchors2d&)
GetProjectedSideAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d)
GetCenteredCapsuleSideAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
TryGetMinimumTranslation(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&,System.Boolean&,FixedMathSharp.Geometry.WideCenteredCapsule2dRelations/ContactAxis&)
TryGetContactAxis(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Boolean,FixedMathSharp.Geometry.WideCenteredCapsule2dRelations/ContactAxis&,System.Boolean)
GetClosestVertexAxis(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetDirectionFromCenteredAxis(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed576&)
GetSupportFeature(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.WideCenteredCapsule2dRelations/ContactAxis,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryKeepAxis(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Boolean,System.Boolean,FixedMathSharp.Geometry.WideCenteredCapsule2dRelations/ContactAxis&)
CompareDepths(FixedMathSharp.Geometry.WideCenteredCapsule2dRelations/ContactAxis,FixedMathSharp.Geometry.WideCenteredCapsule2dRelations/ContactAxis)
CompareDepthToTwiceRaw(FixedMathSharp.Geometry.WideCenteredCapsule2dRelations/ContactAxis,FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
GetDepth(FixedMathSharp.Geometry.WideCenteredCapsule2dRelations/ContactAxis,FixedMathSharp.Fixed64,System.Boolean&)
GetDepthBound(FixedMathSharp.Signed320,FixedMathSharp.Fixed64,FixedMathSharp.Signed320)
GetRelativeProjectionRange(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
GetRelativeProjection(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
GetRelativePointNumerators(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)