< Summary

Line coverage
100%
Covered lines: 994
Uncovered lines: 0
Coverable lines: 994
Total lines: 1526
Line coverage: 100%
Branch coverage
100%
Covered branches: 150
Total branches: 150
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: get_IsZero()100%22100%
File 1: .ctor(...)100%11100%
File 1: op_UnaryNegation(...)100%11100%
File 1: .cctor()100%11100%
File 1: .ctor(...)100%11100%
File 1: .ctor(...)100%11100%
File 1: get_IsPoint()100%11100%
File 1: .ctor(...)100%11100%
File 1: .ctor(...)100%11100%
File 1: GetBoundsClippedToDomain(...)100%1010100%
File 1: GetTransformedEdgeDirection(...)100%11100%
File 1: GetRelativePointNumerators(...)100%11100%
File 1: IsStrictlyConvex(...)100%1212100%
File 1: GetSupportOffset(...)100%11100%
File 1: GetSupportOffset(...)100%44100%
File 1: OrientTargetToSourceNormal(...)100%44100%
File 1: GetClosestPointOffset(...)100%11100%
File 1: GetClosestPointOffset(...)100%66100%
File 1: GetSweptPointTargetContactOffset(...)100%11100%
File 1: GetSweptPointTargetContactOffset(...)100%11100%
File 1: GetSweptAnchorTargetContactOffset(...)100%11100%
File 1: GetSweptConvexTargetContactOffset(...)100%11100%
File 1: ContainsPoint(...)100%11100%
File 1: ContainsPoint(...)100%1010100%
File 1: TryProjectAnchorOntoFeature(...)100%11100%
File 1: TryGetContactOffsets(...)100%1414100%
File 1: TryGetAreaAndCentroid(...)100%44100%
File 1: TryGetSignedDoubleAreaAndCentroid(...)100%44100%
File 1: TryKeepAxes(...)100%88100%
File 1: TryKeepAxis(...)100%2828100%
File 2: GetSupportFeature(...)100%1616100%
File 2: GetProjectionRange(...)100%66100%
File 2: GetProjection(...)100%11100%
File 2: GetSquaredDistance(...)100%11100%
File 2: AddProjectedEndpoint(...)100%88100%
File 2: TryProjectPointOntoFeature(...)100%11100%
File 2: TryProjectPointOntoFeature(...)100%1010100%
File 2: GetProjectedOffsetCoordinate(...)100%11100%
File 2: GetDepth(...)100%22100%
File 2: CorrectDepth(...)100%22100%
File 2: CompareDepthToTwiceRaw(...)100%11100%
File 2: GetTransformedEdge(...)100%11100%
File 2: GetWorldPoint(...)100%11100%
File 2: GetWorldPoint(...)100%11100%
File 2: GetRotatedOffset(...)100%11100%
File 2: GetRotatedOffset(...)100%11100%
File 2: GetDirection(...)100%11100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.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;
 9
 10namespace FixedMathSharp.Geometry;
 11
 12/// <summary>
 13/// Contains methods for computing geometric relations between convex shapes in 2D space using wide fixed-point arithmet
 14/// </summary>
 15internal static partial class WideConvex2dRelations
 16{
 17    #region Nested Types
 18
 19    private readonly struct WideAxis2d
 20    {
 21        internal readonly Signed192 X;
 22        internal readonly Signed192 Y;
 23
 14124        internal bool IsZero => X.IsZero && Y.IsZero;
 25
 26        internal WideAxis2d(Signed192 x, Signed192 y)
 27        {
 16528            X = x;
 16529            Y = y;
 16530        }
 31
 32        public static WideAxis2d operator -(WideAxis2d value) =>
 733            new(WideArithmetic.Negate(value.X), WideArithmetic.Negate(value.Y));
 34    }
 35
 36    private readonly struct RotationFrame2d
 37    {
 138        internal static readonly RotationFrame2d Identity = new(
 139            Signed192.One,
 140            default);
 41
 42        internal readonly Signed192 Cosine;
 43        internal readonly Signed192 Sine;
 44
 45        internal RotationFrame2d(Fixed64 rotation)
 1730046            : this(
 1730047                Signed192.Raw(FixedMath.Cos(rotation)),
 1730048                Signed192.Raw(FixedMath.Sin(rotation)))
 49        {
 1730050        }
 51
 52        private RotationFrame2d(
 53            Signed192 cosine,
 54            Signed192 sine)
 55        {
 1730156            Cosine = cosine;
 1730157            Sine = sine;
 1730158        }
 59    }
 60
 61    private readonly struct Feature
 62    {
 63        internal readonly Vector2d Start;
 64        internal readonly Vector2d End;
 65
 5066        internal bool IsPoint => Start == End;
 67
 68        internal Feature(Vector2d start, Vector2d end)
 69        {
 5170            Start = start;
 5171            End = end;
 5172        }
 73    }
 74
 75    private readonly struct PenetrationAxis
 76    {
 77        internal readonly WideAxis2d Axis;
 78        internal readonly Signed320 Overlap;
 79        internal readonly Signed576 OverlapSquared;
 80        internal readonly Signed320 AxisSquared;
 81        internal readonly bool Negate;
 82        internal readonly bool HasValue;
 83
 84        internal PenetrationAxis(
 85            WideAxis2d axis,
 86            Signed320 overlap,
 87            Signed576 overlapSquared,
 88            Signed320 axisSquared,
 89            bool negate)
 90        {
 2691            Axis = axis;
 2692            Overlap = overlap;
 2693            OverlapSquared = overlapSquared;
 2694            AxisSquared = axisSquared;
 2695            Negate = negate;
 2696            HasValue = true;
 2697        }
 98    }
 99
 100    #endregion
 101
 102    internal static FixedBoundArea GetBoundsClippedToDomain(
 103        Vector2d origin,
 104        Fixed64 rotation,
 105        ReadOnlySpan<Vector2d> vertexOffsets)
 106    {
 2107        RotationFrame2d rotationFrame = new(rotation);
 2108        GetWorldPoint(
 2109            origin,
 2110            rotationFrame,
 2111            vertexOffsets[0],
 2112            Vector2d.Zero,
 2113            out Signed192 minimumX,
 2114            out Signed192 minimumY);
 2115        Signed192 maximumX = minimumX;
 2116        Signed192 maximumY = minimumY;
 16117        for (int i = 1; i < vertexOffsets.Length; i++)
 118        {
 6119            GetWorldPoint(
 6120                origin,
 6121                rotationFrame,
 6122                vertexOffsets[i],
 6123                Vector2d.Zero,
 6124                out Signed192 x,
 6125                out Signed192 y);
 6126            if (WideArithmetic.SubtractSigned192(x, minimumX).Sign < 0)
 2127                minimumX = x;
 6128            if (WideArithmetic.SubtractSigned192(x, maximumX).Sign > 0)
 1129                maximumX = x;
 6130            if (WideArithmetic.SubtractSigned192(y, minimumY).Sign < 0)
 1131                minimumY = y;
 6132            if (WideArithmetic.SubtractSigned192(y, maximumY).Sign > 0)
 2133                maximumY = y;
 134        }
 135
 2136        Signed192 denominator = Signed192.One;
 2137        return FixedBoundArea.FromMinMax(
 2138            new Vector2d(
 2139                WideGeometry.GetRationalBoundClippedToDomain(
 2140                    Signed320.ExtendValue(minimumX),
 2141                    denominator,
 2142                    minimum: true),
 2143                WideGeometry.GetRationalBoundClippedToDomain(
 2144                    Signed320.ExtendValue(minimumY),
 2145                    denominator,
 2146                    minimum: true)),
 2147            new Vector2d(
 2148                WideGeometry.GetRationalBoundClippedToDomain(
 2149                    Signed320.ExtendValue(maximumX),
 2150                    denominator,
 2151                    minimum: false),
 2152                WideGeometry.GetRationalBoundClippedToDomain(
 2153                    Signed320.ExtendValue(maximumY),
 2154                    denominator,
 2155                    minimum: false)));
 156    }
 157
 158    internal static Vector2d GetTransformedEdgeDirection(
 159        Fixed64 rotation,
 160        Vector2d start,
 161        Vector2d end)
 162    {
 265163        GetTransformedEdge(
 265164            new RotationFrame2d(rotation),
 265165            start,
 265166            end,
 265167            out Signed192 x,
 265168            out Signed192 y);
 265169        return WideNormalization.GetNormalized(x, y);
 170    }
 171
 172    internal static void GetRelativePointNumerators(
 173        Vector2d pointOrigin,
 174        Fixed64 pointRotation,
 175        Vector2d pointLocalOffset,
 176        Vector2d referenceOrigin,
 177        out Signed192 x,
 178        out Signed192 y)
 179    {
 16851180        GetWorldPoint(
 16851181            pointOrigin,
 16851182            new RotationFrame2d(pointRotation),
 16851183            pointLocalOffset,
 16851184            Vector2d.Zero,
 16851185            out Signed192 pointX,
 16851186            out Signed192 pointY);
 16851187        GetWorldPoint(
 16851188            referenceOrigin,
 16851189            RotationFrame2d.Identity,
 16851190            Vector2d.Zero,
 16851191            Vector2d.Zero,
 16851192            out Signed192 referenceX,
 16851193            out Signed192 referenceY);
 16851194        x = WideArithmetic.SubtractSigned192(pointX, referenceX);
 16851195        y = WideArithmetic.SubtractSigned192(pointY, referenceY);
 16851196    }
 197
 198    internal static bool IsStrictlyConvex(
 199        ReadOnlySpan<Vector2d> vertexOffsets)
 200    {
 5201        int winding = 0;
 32202        for (int index = 0; index < vertexOffsets.Length; index++)
 203        {
 13204            Vector2d first = vertexOffsets[index];
 13205            Vector2d second = vertexOffsets[
 13206                index + 1 == vertexOffsets.Length ? 0 : index + 1];
 13207            Vector2d third = vertexOffsets[
 13208                index + 2 >= vertexOffsets.Length
 13209                    ? index + 2 - vertexOffsets.Length
 13210                    : index + 2];
 13211            Signed192 firstEdgeX = WideArithmetic.Difference(second.X, first.X);
 13212            Signed192 firstEdgeY = WideArithmetic.Difference(second.Y, first.Y);
 13213            Signed192 secondEdgeX = WideArithmetic.Difference(third.X, second.X);
 13214            Signed192 secondEdgeY = WideArithmetic.Difference(third.Y, second.Y);
 13215            Signed320 cross = WideArithmetic.SubtractSigned320(
 13216                WideArithmetic.MultiplySigned192(firstEdgeX, secondEdgeY),
 13217                WideArithmetic.MultiplySigned192(firstEdgeY, secondEdgeX));
 13218            int sign = cross.Sign;
 13219            if (sign == 0)
 1220                return false;
 12221            if (winding == 0)
 4222                winding = sign;
 8223            else if (sign != winding)
 1224                return false;
 225        }
 226
 3227        return true;
 228    }
 229
 230    internal static Vector2d GetSupportOffset(
 231        ReadOnlySpan<Vector2d> vertexOffsets,
 232        Vector2d direction) =>
 2233        GetSupportOffset(
 2234            Fixed64.Zero,
 2235            vertexOffsets,
 2236            direction);
 237
 238    internal static Vector2d GetSupportOffset(
 239        Fixed64 rotation,
 240        ReadOnlySpan<Vector2d> vertexOffsets,
 241        Vector2d direction)
 242    {
 3243        RotationFrame2d rotationFrame = new(rotation);
 3244        GetDirection(direction, out WideAxis2d axis);
 3245        int bestIndex = 0;
 3246        Signed320 bestProjection = GetProjection(
 3247            Vector2d.Zero,
 3248            rotationFrame,
 3249            vertexOffsets[0],
 3250            axis);
 24251        for (int i = 1; i < vertexOffsets.Length; i++)
 252        {
 9253            Signed320 projection = GetProjection(
 9254                Vector2d.Zero,
 9255                rotationFrame,
 9256                vertexOffsets[i],
 9257                axis);
 9258            if (WideArithmetic.SubtractSigned320(
 9259                    projection,
 9260                    bestProjection).Sign <= 0)
 261            {
 262                continue;
 263            }
 264
 1265            bestIndex = i;
 1266            bestProjection = projection;
 267        }
 268
 3269        return vertexOffsets[bestIndex];
 270    }
 271
 272    internal static Vector2d OrientTargetToSourceNormal(
 273        Vector2d normal,
 274        Vector2d sourceOrigin,
 275        Vector2d sourceTranslationOffset,
 276        Vector2d targetOrigin)
 277    {
 61278        Signed192 x = WideArithmetic.AddSigned192(
 61279            WideArithmetic.Difference(sourceOrigin.X, targetOrigin.X),
 61280            Signed192.Raw(sourceTranslationOffset.X));
 61281        Signed192 y = WideArithmetic.AddSigned192(
 61282            WideArithmetic.Difference(sourceOrigin.Y, targetOrigin.Y),
 61283            Signed192.Raw(sourceTranslationOffset.Y));
 61284        Signed320 centerProjection = WideArithmetic.AddSigned320(
 61285            WideArithmetic.MultiplySigned192(x, Signed192.Raw(normal.X)),
 61286            WideArithmetic.MultiplySigned192(y, Signed192.Raw(normal.Y)));
 61287        if (centerProjection.Sign > 0)
 26288            return normal;
 35289        if (centerProjection.Sign < 0)
 15290            return -normal;
 291
 292        // Sweep normals already face against motion. Preserve that orientation
 293        // when coincident centers provide no geometric preference.
 20294        return normal;
 295    }
 296
 297    internal static Vector2d GetClosestPointOffset(
 298        Vector2d pointOrigin,
 299        Vector2d pointOriginOffset,
 300        Vector2d convexOrigin,
 301        ReadOnlySpan<Vector2d> convexVertexOffsets) =>
 23302        GetClosestPointOffset(
 23303            pointOrigin,
 23304            pointOriginOffset,
 23305            convexOrigin,
 23306            Fixed64.Zero,
 23307            convexVertexOffsets);
 308
 309    internal static Vector2d GetClosestPointOffset(
 310        Vector2d pointOrigin,
 311        Vector2d pointOriginOffset,
 312        Vector2d convexOrigin,
 313        Fixed64 convexRotation,
 314        ReadOnlySpan<Vector2d> convexVertexOffsets)
 315    {
 24316        RotationFrame2d convexFrame = new(convexRotation);
 24317        Vector2d start = convexVertexOffsets[0];
 24318        Vector2d end = convexVertexOffsets[1];
 24319        _ = TryProjectPointOntoFeature(
 24320            pointOrigin,
 24321            pointOriginOffset,
 24322            convexOrigin,
 24323            convexFrame,
 24324            start,
 24325            end,
 24326            requireInteriorProjection: false,
 24327            out Vector2d convexPointOffset);
 24328        Signed320 bestSquaredDistance = GetSquaredDistance(
 24329            pointOrigin,
 24330            pointOriginOffset,
 24331            convexOrigin,
 24332            convexFrame,
 24333            convexPointOffset);
 192334        for (int i = 1; i < convexVertexOffsets.Length; i++)
 335        {
 72336            start = convexVertexOffsets[i];
 72337            end = convexVertexOffsets[
 72338                i + 1 == convexVertexOffsets.Length ? 0 : i + 1];
 72339            _ = TryProjectPointOntoFeature(
 72340                pointOrigin,
 72341                pointOriginOffset,
 72342                convexOrigin,
 72343                convexFrame,
 72344                start,
 72345                end,
 72346                requireInteriorProjection: false,
 72347                out Vector2d candidateOffset);
 348
 72349            Signed320 squaredDistance = GetSquaredDistance(
 72350                pointOrigin,
 72351                pointOriginOffset,
 72352                convexOrigin,
 72353                convexFrame,
 72354                candidateOffset);
 72355            if (WideArithmetic.SubtractSigned320(
 72356                    squaredDistance,
 72357                    bestSquaredDistance).Sign >= 0)
 358            {
 359                continue;
 360            }
 361
 9362            bestSquaredDistance = squaredDistance;
 9363            convexPointOffset = candidateOffset;
 364        }
 365
 24366        return convexPointOffset;
 367    }
 368
 369    internal static Vector2d GetSweptPointTargetContactOffset(
 370        Vector2d sourceOrigin,
 371        Vector2d sourceTranslationOffset,
 372        Vector2d sourceLocalOffset,
 373        Vector2d targetOrigin,
 374        ReadOnlySpan<Vector2d> targetVertexOffsets,
 375        Vector2d targetSupportDirection) =>
 1376        GetSweptPointTargetContactOffset(
 1377            sourceOrigin,
 1378            sourceTranslationOffset,
 1379            sourceLocalOffset,
 1380            targetOrigin,
 1381            Fixed64.Zero,
 1382            targetVertexOffsets,
 1383            targetSupportDirection);
 384
 385    internal static Vector2d GetSweptPointTargetContactOffset(
 386        Vector2d sourceOrigin,
 387        Vector2d sourceTranslationOffset,
 388        Vector2d sourceLocalOffset,
 389        Vector2d targetOrigin,
 390        Fixed64 targetRotation,
 391        ReadOnlySpan<Vector2d> targetVertexOffsets,
 392        Vector2d targetSupportDirection)
 393    {
 2394        RotationFrame2d targetFrame = new(targetRotation);
 2395        GetDirection(targetSupportDirection, out WideAxis2d axis);
 2396        GetSupportFeature(
 2397            targetOrigin,
 2398            targetFrame,
 2399            targetVertexOffsets,
 2400            axis,
 2401            maximum: true,
 2402            out Feature targetFeature);
 2403        _ = TryProjectPointOntoFeature(
 2404            sourceOrigin,
 2405            RotationFrame2d.Identity,
 2406            sourceLocalOffset,
 2407            Vector2d.Zero,
 2408            sourceTranslationOffset,
 2409            targetOrigin,
 2410            targetFrame,
 2411            targetFeature.Start,
 2412            targetFeature.End,
 2413            requireInteriorProjection: false,
 2414            out Vector2d targetContactOffset);
 2415        return targetContactOffset;
 416    }
 417
 418    internal static Vector2d GetSweptAnchorTargetContactOffset(
 419        in FixedPointAnchor2d source,
 420        Vector2d sourceTranslationOffset,
 421        Vector2d targetOrigin,
 422        Fixed64 targetRotation,
 423        ReadOnlySpan<Vector2d> targetVertexOffsets,
 424        Vector2d targetSupportDirection)
 425    {
 9426        RotationFrame2d targetFrame = new(targetRotation);
 9427        GetDirection(targetSupportDirection, out WideAxis2d axis);
 9428        GetSupportFeature(
 9429            targetOrigin,
 9430            targetFrame,
 9431            targetVertexOffsets,
 9432            axis,
 9433            maximum: true,
 9434            out Feature targetFeature);
 9435        _ = TryProjectPointOntoFeature(
 9436            source.Origin,
 9437            new RotationFrame2d(source.Rotation),
 9438            source.LocalPoint,
 9439            source.LocalDisplacement,
 9440            sourceTranslationOffset,
 9441            targetOrigin,
 9442            targetFrame,
 9443            targetFeature.Start,
 9444            targetFeature.End,
 9445            requireInteriorProjection: false,
 9446            out Vector2d targetContactOffset);
 9447        return targetContactOffset;
 448    }
 449
 450    internal static Vector2d GetSweptConvexTargetContactOffset(
 451        Vector2d sourceOrigin,
 452        Fixed64 sourceRotation,
 453        ReadOnlySpan<Vector2d> sourceVertexOffsets,
 454        Vector2d sourceTranslationOffset,
 455        Vector2d targetOrigin,
 456        Fixed64 targetRotation,
 457        ReadOnlySpan<Vector2d> targetVertexOffsets,
 458        Vector2d targetSupportDirection)
 459    {
 3460        RotationFrame2d sourceFrame = new(sourceRotation);
 3461        RotationFrame2d targetFrame = new(targetRotation);
 3462        GetDirection(targetSupportDirection, out WideAxis2d targetAxis);
 3463        GetSupportFeature(
 3464            targetOrigin,
 3465            targetFrame,
 3466            targetVertexOffsets,
 3467            targetAxis,
 3468            maximum: true,
 3469            out Feature targetFeature);
 3470        GetSupportFeature(
 3471            sourceOrigin,
 3472            sourceFrame,
 3473            sourceVertexOffsets,
 3474            -targetAxis,
 3475            maximum: true,
 3476            out Feature sourceFeature);
 3477        _ = TryProjectPointOntoFeature(
 3478            sourceOrigin,
 3479            sourceFrame,
 3480            sourceFeature.Start,
 3481            Vector2d.Zero,
 3482            sourceTranslationOffset,
 3483            targetOrigin,
 3484            targetFrame,
 3485            targetFeature.Start,
 3486            targetFeature.End,
 3487            requireInteriorProjection: false,
 3488            out Vector2d targetContactOffset);
 3489        return targetContactOffset;
 490    }
 491
 492    internal static bool ContainsPoint(
 493        Vector2d pointOrigin,
 494        Vector2d pointOriginOffset,
 495        Vector2d convexOrigin,
 496        ReadOnlySpan<Vector2d> convexVertexOffsets)
 19497        => ContainsPoint(
 19498            pointOrigin,
 19499            pointOriginOffset,
 19500            convexOrigin,
 19501            Fixed64.Zero,
 19502            convexVertexOffsets);
 503
 504    internal static bool ContainsPoint(
 505        Vector2d pointOrigin,
 506        Vector2d pointOriginOffset,
 507        Vector2d convexOrigin,
 508        Fixed64 convexRotation,
 509        ReadOnlySpan<Vector2d> convexVertexOffsets)
 510    {
 23511        RotationFrame2d convexFrame = new(convexRotation);
 23512        bool hasPositive = false;
 23513        bool hasNegative = false;
 212514        for (int i = 0; i < convexVertexOffsets.Length; i++)
 515        {
 87516            Vector2d start = convexVertexOffsets[i];
 87517            Vector2d end = convexVertexOffsets[
 87518                i + 1 == convexVertexOffsets.Length ? 0 : i + 1];
 87519            GetTransformedEdge(
 87520                convexFrame,
 87521                start,
 87522                end,
 87523                out Signed192 edgeX,
 87524                out Signed192 edgeY);
 87525            GetWorldPoint(
 87526                pointOrigin,
 87527                RotationFrame2d.Identity,
 87528                pointOriginOffset,
 87529                Vector2d.Zero,
 87530                out Signed192 pointWorldX,
 87531                out Signed192 pointWorldY);
 87532            GetWorldPoint(
 87533                convexOrigin,
 87534                convexFrame,
 87535                start,
 87536                Vector2d.Zero,
 87537                out Signed192 startWorldX,
 87538                out Signed192 startWorldY);
 87539            Signed192 pointX =
 87540                WideArithmetic.SubtractSigned192(
 87541                    pointWorldX,
 87542                    startWorldX);
 87543            Signed192 pointY =
 87544                WideArithmetic.SubtractSigned192(
 87545                    pointWorldY,
 87546                    startWorldY);
 87547            int orientation = WideArithmetic.MultiplySubtract(
 87548                edgeX,
 87549                pointY,
 87550                edgeY,
 87551                pointX).Sign;
 87552            if (orientation > 0)
 77553                hasPositive = true;
 10554            else if (orientation < 0)
 8555                hasNegative = true;
 87556            if (hasPositive && hasNegative)
 4557                return false;
 558        }
 559
 19560        return true;
 561    }
 562
 563    internal static bool TryProjectAnchorOntoFeature(
 564        in FixedPointAnchor2d source,
 565        Vector2d targetOrigin,
 566        Fixed64 targetRotation,
 567        Vector2d featureStart,
 568        Vector2d featureEnd,
 569        bool requireInteriorProjection,
 570        out Vector2d targetOffset) =>
 31571        TryProjectPointOntoFeature(
 31572            source.Origin,
 31573            new RotationFrame2d(source.Rotation),
 31574            source.LocalPoint,
 31575            source.LocalDisplacement,
 31576            Vector2d.Zero,
 31577            targetOrigin,
 31578            new RotationFrame2d(targetRotation),
 31579            featureStart,
 31580            featureEnd,
 31581            requireInteriorProjection,
 31582            out targetOffset);
 583
 584    internal static bool TryGetContactOffsets(
 585        Vector2d firstOrigin,
 586        Fixed64 firstRotation,
 587        ReadOnlySpan<Vector2d> firstVertexOffsets,
 588        Vector2d secondOrigin,
 589        Fixed64 secondRotation,
 590        ReadOnlySpan<Vector2d> secondVertexOffsets,
 591        Span<Vector2d> firstContactOffsets,
 592        Span<Vector2d> secondContactOffsets,
 593        out int contactCount,
 594        out Vector2d normal,
 595        out Fixed64 depth,
 596        out bool depthIsClamped)
 597    {
 22598        RotationFrame2d firstFrame = new(firstRotation);
 22599        RotationFrame2d secondFrame = new(secondRotation);
 22600        var best = default(PenetrationAxis);
 22601        if (!TryKeepAxes(
 22602                firstOrigin,
 22603                firstFrame,
 22604                firstVertexOffsets,
 22605                secondOrigin,
 22606                secondFrame,
 22607                secondVertexOffsets,
 22608                sourceIsFirst: true,
 22609                ref best)
 22610            || !TryKeepAxes(
 22611                secondOrigin,
 22612                secondFrame,
 22613                secondVertexOffsets,
 22614                firstOrigin,
 22615                firstFrame,
 22616                firstVertexOffsets,
 22617                sourceIsFirst: false,
 22618                ref best))
 619        {
 5620            contactCount = default;
 5621            normal = default;
 5622            depth = default;
 5623            depthIsClamped = default;
 5624            return false;
 625        }
 626
 17627        WideAxis2d orientedAxis = best.Negate ? -best.Axis : best.Axis;
 17628        normal = WideNormalization.GetNormalized(
 17629            orientedAxis.X,
 17630            orientedAxis.Y);
 17631        GetDepth(
 17632            best.Overlap,
 17633            best.AxisSquared,
 17634            out depth,
 17635            out depthIsClamped);
 17636        GetSupportFeature(
 17637            firstOrigin,
 17638            firstFrame,
 17639            firstVertexOffsets,
 17640            orientedAxis,
 17641            maximum: true,
 17642            out Feature firstFeature);
 17643        GetSupportFeature(
 17644            secondOrigin,
 17645            secondFrame,
 17646            secondVertexOffsets,
 17647            orientedAxis,
 17648            maximum: false,
 17649            out Feature secondFeature);
 17650        contactCount = 0;
 651
 17652        if (firstFeature.IsPoint && secondFeature.IsPoint)
 653        {
 1654            firstContactOffsets[0] = firstFeature.Start;
 1655            secondContactOffsets[0] = secondFeature.Start;
 1656            contactCount = 1;
 1657            return true;
 658        }
 659
 16660        if (firstFeature.IsPoint)
 661        {
 1662            _ = TryProjectPointOntoFeature(
 1663                firstOrigin,
 1664                firstFeature.Start,
 1665                secondOrigin,
 1666                secondFrame,
 1667                secondFeature.Start,
 1668                secondFeature.End,
 1669                requireInteriorProjection: false,
 1670                out Vector2d secondOffset);
 671
 1672            firstContactOffsets[0] = firstFeature.Start;
 1673            secondContactOffsets[0] = secondOffset;
 1674            contactCount = 1;
 1675            return true;
 676        }
 677
 15678        if (secondFeature.IsPoint)
 679        {
 6680            _ = TryProjectPointOntoFeature(
 6681                secondOrigin,
 6682                secondFeature.Start,
 6683                firstOrigin,
 6684                firstFrame,
 6685                firstFeature.Start,
 6686                firstFeature.End,
 6687                requireInteriorProjection: false,
 6688                out Vector2d firstOffset);
 689
 6690            firstContactOffsets[0] = firstOffset;
 6691            secondContactOffsets[0] = secondFeature.Start;
 6692            contactCount = 1;
 6693            return true;
 694        }
 695
 9696        AddProjectedEndpoint(
 9697            secondOrigin,
 9698            secondFrame,
 9699            secondFeature.Start,
 9700            firstOrigin,
 9701            firstFrame,
 9702            firstFeature,
 9703            sourceIsFirst: false,
 9704            firstContactOffsets,
 9705            secondContactOffsets,
 9706            ref contactCount);
 9707        AddProjectedEndpoint(
 9708            secondOrigin,
 9709            secondFrame,
 9710            secondFeature.End,
 9711            firstOrigin,
 9712            firstFrame,
 9713            firstFeature,
 9714            sourceIsFirst: false,
 9715            firstContactOffsets,
 9716            secondContactOffsets,
 9717            ref contactCount);
 9718        AddProjectedEndpoint(
 9719            firstOrigin,
 9720            firstFrame,
 9721            firstFeature.Start,
 9722            secondOrigin,
 9723            secondFrame,
 9724            secondFeature,
 9725            sourceIsFirst: true,
 9726            firstContactOffsets,
 9727            secondContactOffsets,
 9728            ref contactCount);
 9729        AddProjectedEndpoint(
 9730            firstOrigin,
 9731            firstFrame,
 9732            firstFeature.End,
 9733            secondOrigin,
 9734            secondFrame,
 9735            secondFeature,
 9736            sourceIsFirst: true,
 9737            firstContactOffsets,
 9738            secondContactOffsets,
 9739            ref contactCount);
 740        // Overlapping closed convex support segments have overlapping
 741        // tangential intervals, so at least one endpoint projection is
 742        // necessarily retained by the four exact checks above.
 9743        return true;
 744    }
 745
 746    internal static bool TryGetAreaAndCentroid(
 747        ReadOnlySpan<Vector2d> vertices,
 748        out Fixed64 area,
 749        out Vector2d centroid)
 750    {
 133751        bool result = TryGetSignedDoubleAreaAndCentroid(
 133752            vertices,
 133753            out Signed320 signedDoubleArea,
 133754            out centroid);
 133755        Signed320 absoluteDoubleArea = signedDoubleArea.Sign < 0
 133756            ? WideArithmetic.SubtractSigned320(
 133757                default,
 133758                signedDoubleArea)
 133759            : signedDoubleArea;
 133760        Signed192 doubledFixedScale =
 133761            WideArithmetic.AddSigned192(
 133762                Signed192.One,
 133763                Signed192.One);
 133764        if (!Fixed64.TryGetSignedRawRatio(
 133765                Signed576.ExtendValue(absoluteDoubleArea),
 133766                Signed576.ExtendValue(
 133767                    Signed320.ExtendValue(doubledFixedScale)),
 133768                out area))
 769        {
 1770            area = Fixed64.MaxValue;
 771        }
 133772        return result;
 773    }
 774
 775    internal static bool TryGetSignedDoubleAreaAndCentroid(
 776        ReadOnlySpan<Vector2d> vertices,
 777        out Signed320 signedDoubleArea,
 778        out Vector2d centroid)
 779    {
 133780        Vector2d anchor = vertices[0];
 133781        signedDoubleArea = default;
 133782        Signed576 weightedX = default;
 133783        Signed576 weightedY = default;
 538784        for (int i = 1; i < vertices.Length - 1; i++)
 785        {
 136786            Signed192 ax = WideArithmetic.SubtractSigned192(
 136787                Signed192.Raw(vertices[i].X),
 136788                Signed192.Raw(anchor.X));
 136789            Signed192 ay = WideArithmetic.SubtractSigned192(
 136790                Signed192.Raw(vertices[i].Y),
 136791                Signed192.Raw(anchor.Y));
 136792            Signed192 bx = WideArithmetic.SubtractSigned192(
 136793                Signed192.Raw(vertices[i + 1].X),
 136794                Signed192.Raw(anchor.X));
 136795            Signed192 by = WideArithmetic.SubtractSigned192(
 136796                Signed192.Raw(vertices[i + 1].Y),
 136797                Signed192.Raw(anchor.Y));
 136798            Signed320 cross = WideArithmetic.SubtractSigned320(
 136799                WideArithmetic.MultiplySigned192(ax, by),
 136800                WideArithmetic.MultiplySigned192(ay, bx));
 136801            signedDoubleArea =
 136802                WideArithmetic.AddSigned320(signedDoubleArea, cross);
 136803            weightedX = WideArithmetic.AddSigned576(
 136804                weightedX,
 136805                WideArithmetic.MultiplySigned320(
 136806                    Signed320.ExtendValue(
 136807                        WideArithmetic.AddSigned192(ax, bx)),
 136808                    cross));
 136809            weightedY = WideArithmetic.AddSigned576(
 136810                weightedY,
 136811                WideArithmetic.MultiplySigned320(
 136812                    Signed320.ExtendValue(
 136813                        WideArithmetic.AddSigned192(ay, by)),
 136814                    cross));
 815        }
 816
 133817        int areaSign = signedDoubleArea.Sign;
 133818        if (areaSign == 0)
 819        {
 1820            centroid = default;
 1821            return false;
 822        }
 823
 824        // The signed area can require more than one word. Multiplication by
 825        // three is therefore performed directly at the five-word width.
 132826        Signed320 centroidDenominator = WideArithmetic.AddSigned320(
 132827            WideArithmetic.AddSigned320(
 132828                signedDoubleArea,
 132829                signedDoubleArea),
 132830            signedDoubleArea);
 132831        Signed576 denominator =
 132832            Signed576.ExtendValue(centroidDenominator);
 132833        Signed576 centroidXNumerator = WideArithmetic.AddSigned576(
 132834            WideArithmetic.MultiplySigned320(
 132835                Signed320.ExtendValue(Signed192.Raw(anchor.X)),
 132836                centroidDenominator),
 132837            weightedX);
 132838        Signed576 centroidYNumerator = WideArithmetic.AddSigned576(
 132839            WideArithmetic.MultiplySigned320(
 132840                Signed320.ExtendValue(Signed192.Raw(anchor.Y)),
 132841                centroidDenominator),
 132842            weightedY);
 843        // A centroid remains inside the convex hull of representable inputs.
 132844        _ = Fixed64.TryGetSignedRawRatio(
 132845            centroidXNumerator,
 132846            denominator,
 132847            out Fixed64 x);
 132848        _ = Fixed64.TryGetSignedRawRatio(
 132849            centroidYNumerator,
 132850            denominator,
 132851            out Fixed64 y);
 132852        centroid = new Vector2d(x, y);
 132853        return true;
 854    }
 855
 856    private static bool TryKeepAxes(
 857        Vector2d axisSourceOrigin,
 858        RotationFrame2d axisSourceRotation,
 859        ReadOnlySpan<Vector2d> axisSourceOffsets,
 860        Vector2d otherOrigin,
 861        RotationFrame2d otherRotation,
 862        ReadOnlySpan<Vector2d> otherOffsets,
 863        bool sourceIsFirst,
 864        ref PenetrationAxis best)
 865    {
 350866        for (int i = 0; i < axisSourceOffsets.Length; i++)
 867        {
 141868            Vector2d start = axisSourceOffsets[i];
 141869            Vector2d end = axisSourceOffsets[
 141870                i + 1 == axisSourceOffsets.Length ? 0 : i + 1];
 141871            GetTransformedEdge(
 141872                axisSourceRotation,
 141873                start,
 141874                end,
 141875                out Signed192 edgeX,
 141876                out Signed192 edgeY);
 141877            WideAxis2d axis = new(edgeY, WideArithmetic.Negate(edgeX));
 141878            if (axis.IsZero)
 879                continue;
 140880            if (!TryKeepAxis(
 140881                    axis,
 140882                    axisSourceOrigin,
 140883                    axisSourceRotation,
 140884                    axisSourceOffsets,
 140885                    otherOrigin,
 140886                    otherRotation,
 140887                    otherOffsets,
 140888                    sourceIsFirst,
 140889                    ref best))
 890            {
 5891                return false;
 892            }
 893        }
 894
 34895        return true;
 896    }
 897
 898    private static bool TryKeepAxis(
 899        WideAxis2d axis,
 900        Vector2d axisSourceOrigin,
 901        RotationFrame2d axisSourceRotation,
 902        ReadOnlySpan<Vector2d> axisSourceOffsets,
 903        Vector2d otherOrigin,
 904        RotationFrame2d otherRotation,
 905        ReadOnlySpan<Vector2d> otherOffsets,
 906        bool sourceIsFirst,
 907        ref PenetrationAxis best)
 908    {
 140909        Vector2d firstOrigin = sourceIsFirst
 140910            ? axisSourceOrigin
 140911            : otherOrigin;
 140912        ReadOnlySpan<Vector2d> firstOffsets = sourceIsFirst
 140913            ? axisSourceOffsets
 140914            : otherOffsets;
 140915        RotationFrame2d firstRotation = sourceIsFirst
 140916            ? axisSourceRotation
 140917            : otherRotation;
 140918        Vector2d secondOrigin = sourceIsFirst
 140919            ? otherOrigin
 140920            : axisSourceOrigin;
 140921        ReadOnlySpan<Vector2d> secondOffsets = sourceIsFirst
 140922            ? otherOffsets
 140923            : axisSourceOffsets;
 140924        RotationFrame2d secondRotation = sourceIsFirst
 140925            ? otherRotation
 140926            : axisSourceRotation;
 140927        GetProjectionRange(
 140928            firstOrigin,
 140929            firstRotation,
 140930            firstOffsets,
 140931            axis,
 140932            out Signed320 firstMinimum,
 140933            out Signed320 firstMaximum);
 140934        GetProjectionRange(
 140935            secondOrigin,
 140936            secondRotation,
 140937            secondOffsets,
 140938            axis,
 140939            out Signed320 secondMinimum,
 140940            out Signed320 secondMaximum);
 140941        Signed320 positive = WideArithmetic.SubtractSigned320(
 140942            firstMaximum,
 140943            secondMinimum);
 140944        Signed320 negative = WideArithmetic.SubtractSigned320(
 140945            secondMaximum,
 140946            firstMinimum);
 140947        if (positive.Sign < 0 || negative.Sign < 0)
 5948            return false;
 949
 135950        Signed320 signedCenterDifference =
 135951            WideArithmetic.SubtractSigned320(positive, negative);
 135952        int signedOverlapComparison = signedCenterDifference.Sign;
 135953        bool negate = signedOverlapComparison >= 0;
 135954        Signed320 overlap = negate ? negative : positive;
 135955        Signed320 axisSquared = WideArithmetic.AddSigned320(
 135956            WideArithmetic.MultiplySigned192(axis.X, axis.X),
 135957            WideArithmetic.MultiplySigned192(axis.Y, axis.Y));
 135958        Signed576 overlapSquared = WideArithmetic.MultiplySigned320(
 135959            overlap,
 135960            overlap);
 135961        if (best.HasValue)
 962        {
 115963            Signed832 candidateScaled =
 115964                WideArithmetic.MultiplyNonNegativeToSigned832(
 115965                    Signed832.ExtendValue(overlapSquared),
 115966                    best.AxisSquared);
 115967            Signed832 bestScaled =
 115968                WideArithmetic.MultiplyNonNegativeToSigned832(
 115969                    Signed832.ExtendValue(best.OverlapSquared),
 115970                    axisSquared);
 115971            int depthComparison = WideArithmetic.SubtractSigned832(
 115972                candidateScaled,
 115973                bestScaled).Sign;
 115974            if (depthComparison >= 0)
 95975                return true;
 976
 977            // Trigonometric frames are representable approximations. Two
 978            // mathematically equal axes can therefore differ below the
 979            // observable Fixed64 depth resolution. Preserve the first authored
 980            // axis when both exact candidates narrow to the same public depth;
 981            // a representable depth still wins over a clamped tie.
 20982            GetDepth(
 20983                overlap,
 20984                axisSquared,
 20985                out Fixed64 candidateDepth,
 20986                out bool candidateDepthIsClamped);
 20987            GetDepth(
 20988                best.Overlap,
 20989                best.AxisSquared,
 20990                out Fixed64 bestDepth,
 20991                out bool bestDepthIsClamped);
 20992            if (candidateDepth == bestDepth
 20993                && !(bestDepthIsClamped
 20994                    && !candidateDepthIsClamped))
 995            {
 14996                return true;
 997            }
 998        }
 999
 261000        best = new PenetrationAxis(
 261001            axis,
 261002            overlap,
 261003            overlapSquared,
 261004            axisSquared,
 261005            negate);
 261006        return true;
 1007    }
 1008}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.ProjectionMath.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.ProjectionMath.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;
 9
 10namespace FixedMathSharp.Geometry;
 11
 12/// <content>
 13/// Provides high-precision projection math used for support feature
 14/// resolution and axis projection comparisons in convex 2D queries.
 15/// </content>
 16internal static partial class WideConvex2dRelations
 17{
 18    private static void GetSupportFeature(
 19        Vector2d origin,
 20        RotationFrame2d rotation,
 21        ReadOnlySpan<Vector2d> offsets,
 22        WideAxis2d axis,
 23        bool maximum,
 24        out Feature feature)
 25    {
 5126        int bestIndex = 0;
 5127        Signed320 bestProjection = GetProjection(
 5128            origin,
 5129            rotation,
 5130            offsets[0],
 5131            axis);
 40232        for (int i = 1; i < offsets.Length; i++)
 33        {
 15034            Signed320 projection = GetProjection(
 15035                origin,
 15036                rotation,
 15037                offsets[i],
 15038                axis);
 15039            int comparison = WideArithmetic.SubtractSigned320(
 15040                projection,
 15041                bestProjection).Sign;
 15042            if ((maximum && comparison > 0)
 15043                || (!maximum && comparison < 0))
 44            {
 2845                bestProjection = projection;
 2846                bestIndex = i;
 47            }
 48        }
 49
 5150        int previousIndex =
 5151            (bestIndex + offsets.Length - 1) % offsets.Length;
 5152        if (WideArithmetic.SubtractSigned320(
 5153                GetProjection(
 5154                    origin,
 5155                    rotation,
 5156                    offsets[previousIndex],
 5157                    axis),
 5158                bestProjection).IsZero)
 59        {
 1360            feature = new Feature(
 1361                offsets[previousIndex],
 1362                offsets[bestIndex]);
 1363            return;
 64        }
 65
 3866        int nextIndex = bestIndex + 1 == offsets.Length ? 0 : bestIndex + 1;
 3867        feature = WideArithmetic.SubtractSigned320(
 3868                GetProjection(
 3869                    origin,
 3870                    rotation,
 3871                    offsets[nextIndex],
 3872                    axis),
 3873                bestProjection).IsZero
 3874            ? new Feature(offsets[bestIndex], offsets[nextIndex])
 3875            : new Feature(offsets[bestIndex], offsets[bestIndex]);
 3876    }
 77
 78    private static void GetProjectionRange(
 79        Vector2d origin,
 80        RotationFrame2d rotation,
 81        ReadOnlySpan<Vector2d> offsets,
 82        WideAxis2d axis,
 83        out Signed320 minimum,
 84        out Signed320 maximum)
 85    {
 28086        minimum = GetProjection(
 28087            origin,
 28088            rotation,
 28089            offsets[0],
 28090            axis);
 28091        maximum = minimum;
 220492        for (int i = 1; i < offsets.Length; i++)
 93        {
 82294            Signed320 projection = GetProjection(
 82295                origin,
 82296                rotation,
 82297                offsets[i],
 82298                axis);
 82299            if (WideArithmetic.SubtractSigned320(
 822100                    projection,
 822101                    minimum).Sign < 0)
 102            {
 165103                minimum = projection;
 104            }
 822105            if (WideArithmetic.SubtractSigned320(
 822106                    projection,
 822107                    maximum).Sign > 0)
 108            {
 163109                maximum = projection;
 110            }
 111        }
 280112    }
 113
 114    private static Signed320 GetProjection(
 115        Vector2d origin,
 116        RotationFrame2d rotation,
 117        Vector2d offset,
 118        WideAxis2d axis)
 119    {
 1404120        GetWorldPoint(
 1404121            origin,
 1404122            rotation,
 1404123            offset,
 1404124            Vector2d.Zero,
 1404125            out Signed192 x,
 1404126            out Signed192 y);
 1404127        return WideArithmetic.AddSigned320(
 1404128            WideArithmetic.MultiplySigned192(x, axis.X),
 1404129            WideArithmetic.MultiplySigned192(y, axis.Y));
 130    }
 131
 132    private static Signed320 GetSquaredDistance(
 133        Vector2d firstOrigin,
 134        Vector2d firstOffset,
 135        Vector2d secondOrigin,
 136        RotationFrame2d secondRotation,
 137        Vector2d secondOffset)
 138    {
 96139        GetWorldPoint(
 96140            firstOrigin,
 96141            RotationFrame2d.Identity,
 96142            firstOffset,
 96143            Vector2d.Zero,
 96144            out Signed192 firstX,
 96145            out Signed192 firstY);
 96146        GetWorldPoint(
 96147            secondOrigin,
 96148            secondRotation,
 96149            secondOffset,
 96150            Vector2d.Zero,
 96151            out Signed192 secondX,
 96152            out Signed192 secondY);
 96153        Signed192 x = WideArithmetic.SubtractSigned192(firstX, secondX);
 96154        Signed192 y = WideArithmetic.SubtractSigned192(firstY, secondY);
 96155        return WideArithmetic.AddSigned320(
 96156            WideArithmetic.MultiplySigned192(x, x),
 96157            WideArithmetic.MultiplySigned192(y, y));
 158    }
 159
 160    private static void AddProjectedEndpoint(
 161        Vector2d sourceOrigin,
 162        RotationFrame2d sourceRotation,
 163        Vector2d sourceOffset,
 164        Vector2d targetOrigin,
 165        RotationFrame2d targetRotation,
 166        Feature targetFeature,
 167        bool sourceIsFirst,
 168        Span<Vector2d> firstContactOffsets,
 169        Span<Vector2d> secondContactOffsets,
 170        ref int contactCount)
 171    {
 36172        if (contactCount == 2
 36173            || !TryProjectPointOntoFeature(
 36174                sourceOrigin,
 36175                sourceRotation,
 36176                sourceOffset,
 36177                Vector2d.Zero,
 36178                Vector2d.Zero,
 36179                targetOrigin,
 36180                targetRotation,
 36181                targetFeature.Start,
 36182                targetFeature.End,
 36183                requireInteriorProjection: true,
 36184                out Vector2d targetOffset))
 185        {
 18186            return;
 187        }
 188
 18189        Vector2d firstOffset = sourceIsFirst ? sourceOffset : targetOffset;
 18190        Vector2d secondOffset = sourceIsFirst ? targetOffset : sourceOffset;
 18191        firstContactOffsets[contactCount] = firstOffset;
 18192        secondContactOffsets[contactCount] = secondOffset;
 18193        contactCount++;
 18194    }
 195
 196    private static bool TryProjectPointOntoFeature(
 197        Vector2d sourceOrigin,
 198        Vector2d sourceOffset,
 199        Vector2d targetOrigin,
 200        RotationFrame2d targetRotation,
 201        Vector2d featureStart,
 202        Vector2d featureEnd,
 203        bool requireInteriorProjection,
 204        out Vector2d targetOffset)
 205    {
 103206        return TryProjectPointOntoFeature(
 103207            sourceOrigin,
 103208            RotationFrame2d.Identity,
 103209            sourceOffset,
 103210            Vector2d.Zero,
 103211            Vector2d.Zero,
 103212            targetOrigin,
 103213            targetRotation,
 103214            featureStart,
 103215            featureEnd,
 103216            requireInteriorProjection,
 103217            out targetOffset);
 218    }
 219
 220    private static bool TryProjectPointOntoFeature(
 221        Vector2d sourceOrigin,
 222        RotationFrame2d sourceRotation,
 223        Vector2d firstSourceOffset,
 224        Vector2d secondSourceOffset,
 225        Vector2d sourceTranslationOffset,
 226        Vector2d targetOrigin,
 227        RotationFrame2d targetRotation,
 228        Vector2d featureStart,
 229        Vector2d featureEnd,
 230        bool requireInteriorProjection,
 231        out Vector2d targetOffset)
 232    {
 168233        GetTransformedEdge(
 168234            targetRotation,
 168235            featureStart,
 168236            featureEnd,
 168237            out Signed192 edgeX,
 168238            out Signed192 edgeY);
 168239        Signed320 denominator = WideArithmetic.AddSigned320(
 168240            WideArithmetic.MultiplySigned192(edgeX, edgeX),
 168241            WideArithmetic.MultiplySigned192(edgeY, edgeY));
 168242        if (denominator.IsZero)
 243        {
 4244            targetOffset = featureStart;
 4245            return true;
 246        }
 247
 164248        GetWorldPoint(
 164249            sourceOrigin,
 164250            sourceTranslationOffset,
 164251            sourceRotation,
 164252            firstSourceOffset,
 164253            secondSourceOffset,
 164254            out Signed192 sourceWorldX,
 164255            out Signed192 sourceWorldY);
 164256        GetWorldPoint(
 164257            targetOrigin,
 164258            targetRotation,
 164259            featureStart,
 164260            Vector2d.Zero,
 164261            out Signed192 featureWorldX,
 164262            out Signed192 featureWorldY);
 164263        Signed192 sourceX =
 164264            WideArithmetic.SubtractSigned192(
 164265                sourceWorldX,
 164266                featureWorldX);
 164267        Signed192 sourceY =
 164268            WideArithmetic.SubtractSigned192(
 164269                sourceWorldY,
 164270                featureWorldY);
 164271        Signed320 numerator = WideArithmetic.AddSigned320(
 164272            WideArithmetic.MultiplySigned192(sourceX, edgeX),
 164273            WideArithmetic.MultiplySigned192(sourceY, edgeY));
 164274        if (numerator.Sign < 0)
 275        {
 11276            if (requireInteriorProjection)
 277            {
 2278                targetOffset = default;
 2279                return false;
 280            }
 9281            numerator = default;
 282        }
 153283        else if (WideArithmetic.SubtractSigned320(
 153284                     numerator,
 153285                     denominator).Sign > 0)
 286        {
 12287            if (requireInteriorProjection)
 288            {
 3289                targetOffset = default;
 3290                return false;
 291            }
 9292            numerator = denominator;
 293        }
 294
 159295        targetOffset = new Vector2d(
 159296            GetProjectedOffsetCoordinate(
 159297                featureStart.X,
 159298                WideArithmetic.Difference(featureEnd.X, featureStart.X),
 159299                numerator,
 159300                denominator),
 159301            GetProjectedOffsetCoordinate(
 159302                featureStart.Y,
 159303                WideArithmetic.Difference(featureEnd.Y, featureStart.Y),
 159304                numerator,
 159305                denominator));
 159306        return true;
 307    }
 308
 309    private static Fixed64 GetProjectedOffsetCoordinate(
 310        Fixed64 featureStart,
 311        Signed192 edge,
 312        Signed320 parameterNumerator,
 313        Signed320 parameterDenominator)
 314    {
 318315        Signed576 numerator = WideArithmetic.AddSigned576(
 318316            WideArithmetic.MultiplySigned320(
 318317                Signed320.ExtendValue(Signed192.Raw(featureStart)),
 318318                parameterDenominator),
 318319            WideArithmetic.MultiplySigned320(
 318320                Signed320.ExtendValue(edge),
 318321                parameterNumerator));
 322        // A clamped interpolation of two representable local coordinates is
 323        // itself representable; only the wide intermediate needs protection.
 318324        _ = Fixed64.TryGetSignedRawRatio(
 318325            numerator,
 318326            Signed576.ExtendValue(parameterDenominator),
 318327            out Fixed64 coordinate);
 318328        return coordinate;
 329    }
 330
 331    private static void GetDepth(
 332        Signed320 overlap,
 333        Signed320 axisSquared,
 334        out Fixed64 depth,
 335        out bool depthIsClamped)
 336    {
 57337        Signed320 scaledLength =
 57338            WideArithmetic.GetFloorSquareRootScaledByFixed64(
 57339                Signed576.ExtendValue(axisSquared));
 57340        if (!Fixed64.TryGetSignedRawRatio(
 57341                Signed576.ExtendValue(overlap),
 57342                Signed576.ExtendValue(scaledLength),
 57343                out depth))
 344        {
 14345            depth = Fixed64.MaxValue;
 14346            depthIsClamped = true;
 14347            return;
 348        }
 349
 43350        CorrectDepth(overlap, axisSquared, ref depth);
 43351        depthIsClamped = false;
 43352    }
 353
 354    private static void CorrectDepth(
 355        Signed320 overlap,
 356        Signed320 axisSquared,
 357        ref Fixed64 depth)
 358    {
 43359        if (depth == Fixed64.Zero)
 4360            return;
 361
 39362        Signed192 lowerMidpoint = WideArithmetic.SubtractSigned192(
 39363            WideArithmetic.AddSigned192(Signed192.Raw(depth), Signed192.Raw(depth)),
 39364            Signed192.Signed(1L));
 39365        int comparison = CompareDepthToTwiceRaw(
 39366            overlap,
 39367            axisSquared,
 39368            lowerMidpoint);
 39369        long adjustment = (uint)comparison >> 31;
 39370        depth = Fixed64.FromRaw(depth.m_rawValue - adjustment);
 39371    }
 372
 373    private static int CompareDepthToTwiceRaw(
 374        Signed320 overlap,
 375        Signed320 axisSquared,
 376        Signed192 twiceRaw)
 377    {
 39378        Signed320 twiceOverlap = WideArithmetic.AddSigned320(
 39379            overlap,
 39380            overlap);
 39381        Signed576 left = WideArithmetic.MultiplySigned320(
 39382            twiceOverlap,
 39383            twiceOverlap);
 39384        Signed320 thresholdSquared = WideArithmetic.MultiplySigned192(
 39385            twiceRaw,
 39386            twiceRaw);
 39387        Signed576 unscaledRight = WideArithmetic.MultiplySigned320(
 39388            thresholdSquared,
 39389            axisSquared);
 39390        Signed576 scaleSquared = WideArithmetic.MultiplySigned320(
 39391            Signed320.ExtendValue(Signed192.One),
 39392            Signed320.ExtendValue(Signed192.One));
 39393        Signed832 right = WideArithmetic.MultiplySigned576ToSigned832(
 39394            unscaledRight,
 39395            scaleSquared);
 39396        return WideArithmetic.SubtractSigned832(
 39397            Signed832.ExtendValue(left),
 39398            right).Sign;
 399    }
 400
 401    private static void GetTransformedEdge(
 402        RotationFrame2d rotation,
 403        Vector2d start,
 404        Vector2d end,
 405        out Signed192 x,
 406        out Signed192 y)
 407    {
 661408        GetRotatedOffset(
 661409            rotation,
 661410            WideArithmetic.SubtractSigned192(
 661411                Signed192.Raw(end.X),
 661412                Signed192.Raw(start.X)),
 661413            WideArithmetic.SubtractSigned192(
 661414                Signed192.Raw(end.Y),
 661415                Signed192.Raw(start.Y)),
 661416            out x,
 661417            out y);
 661418    }
 419
 420    private static void GetWorldPoint(
 421        Vector2d origin,
 422        RotationFrame2d rotation,
 423        Vector2d firstLocalPoint,
 424        Vector2d secondLocalPoint,
 425        out Signed192 x,
 426        out Signed192 y) =>
 35644427        GetWorldPoint(
 35644428            origin,
 35644429            Vector2d.Zero,
 35644430            rotation,
 35644431            firstLocalPoint,
 35644432            secondLocalPoint,
 35644433            out x,
 35644434            out y);
 435
 436    private static void GetWorldPoint(
 437        Vector2d origin,
 438        Vector2d translationOffset,
 439        RotationFrame2d rotation,
 440        Vector2d firstLocalPoint,
 441        Vector2d secondLocalPoint,
 442        out Signed192 x,
 443        out Signed192 y)
 444    {
 35808445        GetRotatedOffset(
 35808446            rotation,
 35808447            firstLocalPoint,
 35808448            out Signed192 firstRotatedX,
 35808449            out Signed192 firstRotatedY);
 35808450        GetRotatedOffset(
 35808451            rotation,
 35808452            secondLocalPoint,
 35808453            out Signed192 secondRotatedX,
 35808454            out Signed192 secondRotatedY);
 35808455        x = WideArithmetic.AddSigned192(
 35808456            WideArithmetic.AddSigned192(
 35808457                WideArithmetic.AddSigned192(
 35808458                    WideArithmetic.Scale(origin.X),
 35808459                    WideArithmetic.Scale(translationOffset.X)),
 35808460                firstRotatedX),
 35808461            secondRotatedX);
 35808462        y = WideArithmetic.AddSigned192(
 35808463            WideArithmetic.AddSigned192(
 35808464                WideArithmetic.AddSigned192(
 35808465                    WideArithmetic.Scale(origin.Y),
 35808466                    WideArithmetic.Scale(translationOffset.Y)),
 35808467                firstRotatedY),
 35808468            secondRotatedY);
 35808469    }
 470
 471    private static void GetRotatedOffset(
 472        RotationFrame2d rotation,
 473        Vector2d localPoint,
 474        out Signed192 x,
 475        out Signed192 y)
 476    {
 71616477        GetRotatedOffset(
 71616478            rotation,
 71616479            Signed192.Raw(localPoint.X),
 71616480            Signed192.Raw(localPoint.Y),
 71616481            out x,
 71616482            out y);
 71616483    }
 484
 485    private static void GetRotatedOffset(
 486        RotationFrame2d rotation,
 487        Signed192 localX,
 488        Signed192 localY,
 489        out Signed192 x,
 490        out Signed192 y)
 491    {
 72277492        x = Signed192.NarrowValue(
 72277493            WideArithmetic.SubtractSigned320(
 72277494                WideArithmetic.MultiplySigned192(
 72277495                    localX,
 72277496                    rotation.Cosine),
 72277497                WideArithmetic.MultiplySigned192(
 72277498                    localY,
 72277499                    rotation.Sine)));
 72277500        y = Signed192.NarrowValue(
 72277501            WideArithmetic.AddSigned320(
 72277502                WideArithmetic.MultiplySigned192(
 72277503                    localX,
 72277504                    rotation.Sine),
 72277505                WideArithmetic.MultiplySigned192(
 72277506                    localY,
 72277507                    rotation.Cosine)));
 72277508    }
 509
 510    private static void GetDirection(
 511        Vector2d direction,
 512        out WideAxis2d axis)
 513    {
 17514        axis = new WideAxis2d(
 17515            Signed192.Raw(direction.X),
 17516            Signed192.Raw(direction.Y));
 17517    }
 518}

Methods/Properties

get_IsZero()
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192)
op_UnaryNegation(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d)
.cctor()
.ctor(FixedMathSharp.Fixed64)
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192)
get_IsPoint()
.ctor(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
.ctor(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed320,System.Boolean)
GetBoundsClippedToDomain(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetTransformedEdgeDirection(FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
GetRelativePointNumerators(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
IsStrictlyConvex(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetSupportOffset(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetSupportOffset(FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
OrientTargetToSourceNormal(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
GetClosestPointOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetClosestPointOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetSweptPointTargetContactOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetSweptPointTargetContactOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetSweptAnchorTargetContactOffset(FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetSweptConvexTargetContactOffset(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
ContainsPoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
ContainsPoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
TryProjectAnchorOntoFeature(FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Boolean,FixedMathSharp.Vector2d&)
TryGetContactOffsets(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Span`1<FixedMathSharp.Vector2d>,System.Span`1<FixedMathSharp.Vector2d>,System.Int32&,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&,System.Boolean&)
TryGetAreaAndCentroid(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&)
TryGetSignedDoubleAreaAndCentroid(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Signed320&,FixedMathSharp.Vector2d&)
TryKeepAxes(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Boolean,FixedMathSharp.Geometry.WideConvex2dRelations/PenetrationAxis&)
TryKeepAxis(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Boolean,FixedMathSharp.Geometry.WideConvex2dRelations/PenetrationAxis&)
GetSupportFeature(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,System.Boolean,FixedMathSharp.Geometry.WideConvex2dRelations/Feature&)
GetProjectionRange(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
GetProjection(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d)
GetSquaredDistance(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d)
AddProjectedEndpoint(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Geometry.WideConvex2dRelations/Feature,System.Boolean,System.Span`1<FixedMathSharp.Vector2d>,System.Span`1<FixedMathSharp.Vector2d>,System.Int32&)
TryProjectPointOntoFeature(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Boolean,FixedMathSharp.Vector2d&)
TryProjectPointOntoFeature(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Boolean,FixedMathSharp.Vector2d&)
GetProjectedOffsetCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetDepth(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Fixed64&,System.Boolean&)
CorrectDepth(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Fixed64&)
CompareDepthToTwiceRaw(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192)
GetTransformedEdge(FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetWorldPoint(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetWorldPoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetRotatedOffset(FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetRotatedOffset(FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetDirection(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d&)