< Summary

Line coverage
100%
Covered lines: 2013
Uncovered lines: 0
Coverable lines: 2013
Total lines: 2892
Line coverage: 100%
Branch coverage
100%
Covered branches: 228
Total branches: 228
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: TryGetRotatedConeRelation(...)100%88100%
File 1: GetProjectedConeCeilingDistance(...)100%1616100%
File 1: FindProjectedConeCeilingDistance(...)100%44100%
File 1: GetProjectedConeClosestOffset(...)100%22100%
File 1: GetSegmentOffset(...)100%11100%
File 1: KeepCloserOffset(...)100%44100%
File 1: CompareConeDistanceToRadius(...)100%88100%
File 1: GetConeProjectionData(...)100%11100%
File 1: IsPointInConeProjectionWedge(...)100%44100%
File 1: TryCompareConeTangentDistanceToRadius(...)100%44100%
File 1: CompareConeTangentSquaredDistance(...)100%66100%
File 1: CompareRationalDistanceToRadius(...)100%22100%
File 2: .ctor(...)100%11100%
File 2: .ctor(...)100%11100%
File 2: TryGetSphereRelation(...)100%44100%
File 2: TryGetCenteredCapsuleRelation(...)100%11100%
File 2: TryGetCenteredCylinderRelation(...)100%44100%
File 2: TryGetCenteredConeRelation(...)100%66100%
File 2: TryCreateRadiallyExpandedRelation(...)100%44100%
File 2: GetRotatedLocalAxis(...)100%11100%
File 2: GetLocalOffsetNumerator(...)100%11100%
File 2: GetWorldPoint(...)100%11100%
File 2: GetCenteredAxisEndpoints(...)100%11100%
File 2: GetCenteredBasisAxisEndpoints(...)100%11100%
File 2: TryGetRadialGap(...)100%88100%
File 2: GetPointDistance(...)100%11100%
File 2: GetSegmentDistance(...)100%11100%
File 2: GetSegmentDistance(...)100%66100%
File 2: IsWithinRadius(...)100%11100%
File 2: TryGetDistance(...)100%88100%
File 2: CompareDistanceToRaw(...)100%11100%
File 2: CompareDistanceToRaw(...)100%11100%
File 2: CompareDistanceToTwiceRaw(...)100%11100%
File 2: CompareDistanceToTwiceRaw(...)100%11100%
File 2: GetOffset(...)100%11100%
File 2: GetHalfToEvenIncrement(...)100%11100%
File 2: GetLargestPositiveMagnitude(...)100%1010100%
File 3: TryGetProjectedDiskRelation(...)100%1414100%
File 3: GetProjectedDiskCeilingDistance(...)100%1616100%
File 3: FindProjectedDiskCeilingDistance(...)100%44100%
File 3: GetProjectedDiskClosestOffset(...)100%11100%
File 3: GetEllipseClosestOffset(...)100%44100%
File 3: GetEllipseConstraintCoordinate(...)100%11100%
File 3: GetProjectedDiskSegmentEndpoints(...)100%11100%
File 3: CompareProjectedDiskDistanceToRadius(...)100%1414100%
File 3: CountProjectedDiskCircleRoots(...)100%22100%
File 3: CreateProjectedDiskCirclePolynomial(...)100%22100%
File 3: GetProjectedDiskConicCoefficient(...)100%11100%
File 3: GetProjectedDiskRadialCoefficient(...)100%11100%
File 3: GetSquaredPolynomial(...)100%11100%
File 3: MultiplyBySmall(...)100%1010100%
File 3: DoubleSigned832(...)100%11100%
File 3: EvaluateProjectedDiskConic(...)100%11100%
File 4: TryGetOrientedBoxRelation(...)100%66100%
File 4: TryGetTriangleRelation(...)100%22100%
File 4: TryGetConvexRelation(...)100%66100%
File 4: TryCreateRelation(...)100%44100%
File 4: ContainsPoint(...)100%1010100%
File 4: BuildConvexHull(...)100%1212100%
File 4: SortAndDeduplicate(...)100%1010100%
File 4: ComparePoint(...)100%22100%
File 4: GetTurn(...)100%11100%
File 4: Cross(...)100%11100%
File 4: KeepCloser(...)100%22100%
File 4: CompareDistances(...)100%11100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WidePlanarProjection.Cone.cs

#LineLine coverage
 1//=======================================================================
 2// WidePlanarProjection.Cone.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/// Exact projected-cone hull admission and tangent-segment reduction.
 14/// </content>
 15internal static partial class WidePlanarProjection
 16{
 17    private const int ConeComparisonWordCount = 56;
 18
 19    private static bool TryGetRotatedConeRelation(
 20        Vector2d circleCenter,
 21        Fixed64 circleRadius,
 22        RationalPoint baseCenter,
 23        RationalPoint apex,
 24        Signed192 coordinateDenominator,
 25        Signed192 axisDenominator,
 26        Signed192 axisX,
 27        Signed192 axisY,
 28        Signed192 axisZ,
 29        Fixed64 coneHeight,
 30        Fixed64 coneRadius,
 31        out PlanarProjectionRelation relation)
 32    {
 1233        RationalDistance baseDistance = GetPointDistance(
 1234            circleCenter,
 1235            coordinateDenominator,
 1236            baseCenter);
 1237        RationalDistance apexDistance = GetPointDistance(
 1238            circleCenter,
 1239            coordinateDenominator,
 1240            apex);
 1241        GetConeProjectionData(
 1242            baseDistance,
 1243            coordinateDenominator,
 1244            axisDenominator,
 1245            axisX,
 1246            axisY,
 1247            axisZ,
 1248            coneHeight,
 1249            coneRadius,
 1250            out Signed320 planarAxisSquared,
 1251            out Signed320 axisSquared,
 1252            out Signed576 delta,
 1253            out Signed576 axisProjection,
 1254            out Signed576 perpendicularProjection,
 1255            out Signed576 apexProjectionGap);
 56
 1257        int maximumComparison = CompareConeDistanceToRadius(
 1258            baseDistance,
 1259            apexDistance,
 1260            coordinateDenominator,
 1261            axisDenominator,
 1262            axisX,
 1263            axisY,
 1264            axisZ,
 1265            coneHeight,
 1266            coneRadius,
 1267            planarAxisSquared,
 1268            axisSquared,
 1269            delta,
 1270            axisProjection,
 1271            perpendicularProjection,
 1272            apexProjectionGap,
 1273            Signed192.Raw(circleRadius),
 1274            radiusDenominator: 1);
 1275        if (maximumComparison > 0)
 76        {
 277            relation = default;
 278            return false;
 79        }
 80
 1081        int zeroComparison = CompareConeDistanceToRadius(
 1082            baseDistance,
 1083            apexDistance,
 1084            coordinateDenominator,
 1085            axisDenominator,
 1086            axisX,
 1087            axisY,
 1088            axisZ,
 1089            coneHeight,
 1090            coneRadius,
 1091            planarAxisSquared,
 1092            axisSquared,
 1093            delta,
 1094            axisProjection,
 1095            perpendicularProjection,
 1096            apexProjectionGap,
 1097            default,
 1098            radiusDenominator: 1);
 1099        if (zeroComparison <= 0)
 100        {
 2101            relation = PlanarProjectionRelation.Contained;
 2102            return true;
 103        }
 104
 8105        GetProjectedConeClosestOffset(
 8106            baseDistance,
 8107            apexDistance,
 8108            coordinateDenominator,
 8109            axisX,
 8110            axisY,
 8111            axisZ,
 8112            coneRadius,
 8113            out Fixed64 approximateDistance,
 8114            out Vector2d direction);
 8115        long low = GetProjectedConeCeilingDistance(
 8116            baseDistance,
 8117            apexDistance,
 8118            coordinateDenominator,
 8119            axisDenominator,
 8120            axisX,
 8121            axisY,
 8122            axisZ,
 8123            coneHeight,
 8124            coneRadius,
 8125            planarAxisSquared,
 8126            axisSquared,
 8127            delta,
 8128            axisProjection,
 8129            perpendicularProjection,
 8130            apexProjectionGap,
 8131            circleRadius,
 8132            approximateDistance);
 133
 8134        long floor = low - 1L;
 8135        Signed192 midpointNumerator = WideArithmetic.AddSigned192(
 8136            WideArithmetic.AddSigned192(
 8137                Signed192.Signed(floor),
 8138                Signed192.Signed(floor)),
 8139            Signed192.Signed(1L));
 8140        int midpointComparison = CompareConeDistanceToRadius(
 8141            baseDistance,
 8142            apexDistance,
 8143            coordinateDenominator,
 8144            axisDenominator,
 8145            axisX,
 8146            axisY,
 8147            axisZ,
 8148            coneHeight,
 8149            coneRadius,
 8150            planarAxisSquared,
 8151            axisSquared,
 8152            delta,
 8153            axisProjection,
 8154            perpendicularProjection,
 8155            apexProjectionGap,
 8156            midpointNumerator,
 8157            radiusDenominator: 2);
 8158        long rounded = midpointComparison < 0
 8159            ? floor
 8160            : midpointComparison > 0
 8161                ? low
 8162                : floor + (floor & 1L);
 8163        Fixed64 distance = Fixed64.FromRaw(rounded);
 8164        relation = new PlanarProjectionRelation(
 8165            distance,
 8166            direction * distance,
 8167            direction);
 8168        return true;
 169    }
 170
 171    private static long GetProjectedConeCeilingDistance(
 172        RationalDistance baseDistance,
 173        RationalDistance apexDistance,
 174        Signed192 coordinateDenominator,
 175        Signed192 axisDenominator,
 176        Signed192 axisX,
 177        Signed192 axisY,
 178        Signed192 axisZ,
 179        Fixed64 coneHeight,
 180        Fixed64 coneRadius,
 181        Signed320 planarAxisSquared,
 182        Signed320 axisSquared,
 183        Signed576 delta,
 184        Signed576 axisProjection,
 185        Signed576 perpendicularProjection,
 186        Signed576 apexProjectionGap,
 187        Fixed64 maximum,
 188        Fixed64 approximate)
 189    {
 8190        long candidate = approximate.m_rawValue;
 8191        if (candidate > maximum.m_rawValue)
 1192            candidate = maximum.m_rawValue;
 193
 8194        int comparison = CompareConeDistanceToRadius(
 8195            baseDistance,
 8196            apexDistance,
 8197            coordinateDenominator,
 8198            axisDenominator,
 8199            axisX,
 8200            axisY,
 8201            axisZ,
 8202            coneHeight,
 8203            coneRadius,
 8204            planarAxisSquared,
 8205            axisSquared,
 8206            delta,
 8207            axisProjection,
 8208            perpendicularProjection,
 8209            apexProjectionGap,
 8210            Signed192.Signed(candidate),
 8211            radiusDenominator: 1);
 8212        if (comparison <= 0)
 213        {
 3214            long high = candidate;
 3215            long step = 1L;
 14216            while (high > 1L)
 217            {
 13218                long probe = high > step ? high - step : 0L;
 13219                if (probe == 0L
 13220                    || CompareConeDistanceToRadius(
 13221                        baseDistance,
 13222                        apexDistance,
 13223                        coordinateDenominator,
 13224                        axisDenominator,
 13225                        axisX,
 13226                        axisY,
 13227                        axisZ,
 13228                        coneHeight,
 13229                        coneRadius,
 13230                        planarAxisSquared,
 13231                        axisSquared,
 13232                        delta,
 13233                        axisProjection,
 13234                        perpendicularProjection,
 13235                        apexProjectionGap,
 13236                        Signed192.Signed(probe),
 13237                        radiusDenominator: 1) > 0)
 238                {
 2239                    return FindProjectedConeCeilingDistance(
 2240                        baseDistance,
 2241                        apexDistance,
 2242                        coordinateDenominator,
 2243                        axisDenominator,
 2244                        axisX,
 2245                        axisY,
 2246                        axisZ,
 2247                        coneHeight,
 2248                        coneRadius,
 2249                        planarAxisSquared,
 2250                        axisSquared,
 2251                        delta,
 2252                        axisProjection,
 2253                        perpendicularProjection,
 2254                        apexProjectionGap,
 2255                        probe + 1L,
 2256                        high);
 257                }
 258
 11259                high = probe;
 11260                step = (long)Math.Min(
 11261                    (ulong)step << 1,
 11262                    (ulong)high);
 263            }
 264
 1265            return 1L;
 266        }
 267
 5268        long low = candidate + 1L;
 5269        long upper = maximum.m_rawValue;
 5270        long upwardStep = 1L;
 10271        while (low < upper)
 272        {
 9273            long remaining = upper - candidate;
 9274            long probe = candidate + Math.Min(
 9275                upwardStep,
 9276                remaining);
 9277            if (CompareConeDistanceToRadius(
 9278                baseDistance,
 9279                apexDistance,
 9280                coordinateDenominator,
 9281                axisDenominator,
 9282                axisX,
 9283                axisY,
 9284                axisZ,
 9285                coneHeight,
 9286                coneRadius,
 9287                planarAxisSquared,
 9288                axisSquared,
 9289                delta,
 9290                axisProjection,
 9291                perpendicularProjection,
 9292                apexProjectionGap,
 9293                Signed192.Signed(probe),
 9294                radiusDenominator: 1) <= 0)
 295            {
 4296                return FindProjectedConeCeilingDistance(
 4297                    baseDistance,
 4298                    apexDistance,
 4299                    coordinateDenominator,
 4300                    axisDenominator,
 4301                    axisX,
 4302                    axisY,
 4303                    axisZ,
 4304                    coneHeight,
 4305                    coneRadius,
 4306                    planarAxisSquared,
 4307                    axisSquared,
 4308                    delta,
 4309                    axisProjection,
 4310                    perpendicularProjection,
 4311                    apexProjectionGap,
 4312                    low,
 4313                    probe);
 314            }
 315
 5316            low = probe + 1L;
 5317            upwardStep = (long)Math.Min(
 5318                (ulong)upwardStep << 1,
 5319                (ulong)(upper - candidate));
 320        }
 321
 1322        return upper;
 323    }
 324
 325    private static long FindProjectedConeCeilingDistance(
 326        RationalDistance baseDistance,
 327        RationalDistance apexDistance,
 328        Signed192 coordinateDenominator,
 329        Signed192 axisDenominator,
 330        Signed192 axisX,
 331        Signed192 axisY,
 332        Signed192 axisZ,
 333        Fixed64 coneHeight,
 334        Fixed64 coneRadius,
 335        Signed320 planarAxisSquared,
 336        Signed320 axisSquared,
 337        Signed576 delta,
 338        Signed576 axisProjection,
 339        Signed576 perpendicularProjection,
 340        Signed576 apexProjectionGap,
 341        long low,
 342        long high)
 343    {
 18344        while (low < high)
 345        {
 12346            long middle = low + ((high - low) >> 1);
 12347            int comparison = CompareConeDistanceToRadius(
 12348                baseDistance,
 12349                apexDistance,
 12350                coordinateDenominator,
 12351                axisDenominator,
 12352                axisX,
 12353                axisY,
 12354                axisZ,
 12355                coneHeight,
 12356                coneRadius,
 12357                planarAxisSquared,
 12358                axisSquared,
 12359                delta,
 12360                axisProjection,
 12361                perpendicularProjection,
 12362                apexProjectionGap,
 12363                Signed192.Signed(middle),
 12364                radiusDenominator: 1);
 12365            if (comparison <= 0)
 5366                high = middle;
 367            else
 7368                low = middle + 1L;
 369        }
 370
 6371        return low;
 372    }
 373
 374    private static void GetProjectedConeClosestOffset(
 375        RationalDistance baseDistance,
 376        RationalDistance apexDistance,
 377        Signed192 coordinateDenominator,
 378        Signed192 axisX,
 379        Signed192 axisY,
 380        Signed192 axisZ,
 381        Fixed64 coneRadius,
 382        out Fixed64 approximateDistance,
 383        out Vector2d direction)
 384    {
 8385        Signed320 baseX = Signed320.NarrowValue(baseDistance.X);
 8386        Signed320 baseZ = Signed320.NarrowValue(baseDistance.Z);
 8387        Signed320 apexX = WideArithmetic.SubtractSigned320(
 8388            Signed320.NarrowValue(apexDistance.X),
 8389            baseX);
 8390        Signed320 apexZ = WideArithmetic.SubtractSigned320(
 8391            Signed320.NarrowValue(apexDistance.Z),
 8392            baseZ);
 8393        Signed320 scaledRadius = WideArithmetic.MultiplySigned192(
 8394            coordinateDenominator,
 8395            Signed192.Raw(coneRadius));
 8396        Signed320 scale = GetLargestPositiveMagnitude(
 8397            baseX,
 8398            baseZ,
 8399            apexX,
 8400            apexZ,
 8401            scaledRadius);
 8402        Vector2d query = new(
 8403            -Fixed64.GetSignedRatio(baseX, scale),
 8404            -Fixed64.GetSignedRatio(baseZ, scale));
 8405        Vector2d apex = new(
 8406            Fixed64.GetSignedRatio(apexX, scale),
 8407            Fixed64.GetSignedRatio(apexZ, scale));
 8408        Vector2d axis = WideNormalization.GetNormalized(axisX, axisZ);
 8409        Vector2d perpendicular = new(-axis.Y, axis.X);
 8410        Vector2d localQuery = new(
 8411            Vector2d.Dot(query, axis),
 8412            Vector2d.Dot(query, perpendicular));
 8413        Fixed64 apexLength = Vector2d.Dot(apex, axis);
 8414        Fixed64 radius = Fixed64.GetSignedRatio(scaledRadius, scale);
 8415        Fixed64 minor = radius * FixedMath.Abs(
 8416            WideNormalization.GetNormalized(
 8417                axisX,
 8418                axisY,
 8419                axisZ).Y);
 420        Vector2d localOffset;
 8421        if (apexLength <= minor)
 422        {
 3423            localOffset = GetEllipseClosestOffset(
 3424                localQuery.X,
 3425                localQuery.Y,
 3426                minor,
 3427                radius);
 428        }
 429        else
 430        {
 5431            Fixed64 tangentX = Fixed64.MultiplyDivide(
 5432                minor,
 5433                minor,
 5434                apexLength,
 5435                out _);
 5436            Fixed64 ratio = tangentX / apexLength;
 5437            Fixed64 tangentY = radius * FixedMath.Sqrt(
 5438                FixedMath.Max(
 5439                    Fixed64.Zero,
 5440                    Fixed64.One - ratio));
 5441            Vector2d ellipseOffset = GetEllipseClosestOffset(
 5442                localQuery.X,
 5443                localQuery.Y,
 5444                minor,
 5445                radius);
 5446            Vector2d ellipsePoint = localQuery + ellipseOffset;
 5447            bool found = ellipsePoint.X <= tangentX;
 5448            localOffset = ellipseOffset;
 5449            KeepCloserOffset(
 5450                new Vector2d(apexLength, Fixed64.Zero) - localQuery,
 5451                ref found,
 5452                ref localOffset);
 5453            KeepCloserOffset(
 5454                GetSegmentOffset(
 5455                    localQuery,
 5456                    new Vector2d(tangentX, tangentY),
 5457                    new Vector2d(apexLength, Fixed64.Zero)),
 5458                ref found,
 5459                ref localOffset);
 5460            KeepCloserOffset(
 5461                GetSegmentOffset(
 5462                    localQuery,
 5463                    new Vector2d(tangentX, -tangentY),
 5464                    new Vector2d(apexLength, Fixed64.Zero)),
 5465                ref found,
 5466                ref localOffset);
 467        }
 468
 8469        Vector2d worldOffset =
 8470            axis * localOffset.X + perpendicular * localOffset.Y;
 8471        direction = worldOffset.Normalized;
 8472        Signed576 distanceNumerator =
 8473            WideArithmetic.MultiplySigned320(
 8474                scale,
 8475                Signed320.ExtendValue(
 8476                    Signed192.Raw(worldOffset.Magnitude)));
 8477        _ = Fixed64.TryGetSignedRawRatio(
 8478            distanceNumerator,
 8479            Signed576.ExtendValue(
 8480                WideArithmetic.MultiplySigned192(
 8481                    coordinateDenominator,
 8482                    Signed192.Raw(Fixed64.One))),
 8483            out approximateDistance);
 8484    }
 485
 486    private static Vector2d GetSegmentOffset(
 487        Vector2d point,
 488        Vector2d first,
 489        Vector2d second)
 490    {
 10491        Vector2d edge = second - first;
 10492        Fixed64 projection = FixedMath.Clamp(
 10493            Vector2d.Dot(point - first, edge) / edge.MagnitudeSquared,
 10494            Fixed64.Zero,
 10495            Fixed64.One);
 10496        return first + edge * projection - point;
 497    }
 498
 499    private static void KeepCloserOffset(
 500        Vector2d candidate,
 501        ref bool found,
 502        ref Vector2d best)
 503    {
 15504        if (!found || candidate.MagnitudeSquared < best.MagnitudeSquared)
 505        {
 8506            found = true;
 8507            best = candidate;
 508        }
 15509    }
 510
 511    private static int CompareConeDistanceToRadius(
 512        RationalDistance baseDistance,
 513        RationalDistance apexDistance,
 514        Signed192 coordinateDenominator,
 515        Signed192 axisDenominator,
 516        Signed192 axisX,
 517        Signed192 axisY,
 518        Signed192 axisZ,
 519        Fixed64 coneHeight,
 520        Fixed64 coneRadius,
 521        Signed320 planarAxisSquared,
 522        Signed320 axisSquared,
 523        Signed576 delta,
 524        Signed576 axisProjection,
 525        Signed576 perpendicularProjection,
 526        Signed576 apexProjectionGap,
 527        Signed192 radiusNumerator,
 528        int radiusDenominator)
 529    {
 71530        int baseComparison = CompareProjectedDiskDistanceToRadius(
 71531            baseDistance,
 71532            coordinateDenominator,
 71533            axisX,
 71534            axisY,
 71535            axisZ,
 71536            coneRadius,
 71537            radiusNumerator,
 71538            radiusDenominator);
 71539        if (delta.Sign <= 0)
 30540            return baseComparison;
 541
 41542        if (IsPointInConeProjectionWedge(
 41543                coordinateDenominator,
 41544                axisDenominator,
 41545                axisY,
 41546                coneHeight,
 41547                coneRadius,
 41548                planarAxisSquared,
 41549                delta,
 41550                axisProjection,
 41551                perpendicularProjection,
 41552                apexProjectionGap))
 553        {
 4554            return radiusNumerator.IsZero ? 0 : -1;
 555        }
 556
 37557        int comparison = Math.Min(
 37558            baseComparison,
 37559            CompareRationalDistanceToRadius(
 37560                apexDistance,
 37561                radiusNumerator,
 37562                radiusDenominator));
 37563        if (TryCompareConeTangentDistanceToRadius(
 37564                coordinateDenominator,
 37565                coneHeight,
 37566                coneRadius,
 37567                planarAxisSquared,
 37568                axisSquared,
 37569                delta,
 37570                perpendicularProjection,
 37571                apexProjectionGap,
 37572                radiusNumerator,
 37573                radiusDenominator,
 37574                out int tangentComparison))
 575        {
 20576            comparison = Math.Min(
 20577                comparison,
 20578                tangentComparison);
 579        }
 580
 37581        return comparison;
 582    }
 583
 584    private static void GetConeProjectionData(
 585        RationalDistance baseDistance,
 586        Signed192 coordinateDenominator,
 587        Signed192 axisDenominator,
 588        Signed192 axisX,
 589        Signed192 axisY,
 590        Signed192 axisZ,
 591        Fixed64 coneHeight,
 592        Fixed64 coneRadius,
 593        out Signed320 planarAxisSquared,
 594        out Signed320 axisSquared,
 595        out Signed576 delta,
 596        out Signed576 axisProjection,
 597        out Signed576 perpendicularProjection,
 598        out Signed576 apexProjectionGap)
 599    {
 12600        Signed320 relativeX = WideArithmetic.SubtractSigned320(
 12601            default,
 12602            Signed320.NarrowValue(baseDistance.X));
 12603        Signed320 relativeZ = WideArithmetic.SubtractSigned320(
 12604            default,
 12605            Signed320.NarrowValue(baseDistance.Z));
 12606        Signed320 axisX2 = WideArithmetic.MultiplySigned192(
 12607            axisX,
 12608            axisX);
 12609        Signed320 axisY2 = WideArithmetic.MultiplySigned192(
 12610            axisY,
 12611            axisY);
 12612        Signed320 axisZ2 = WideArithmetic.MultiplySigned192(
 12613            axisZ,
 12614            axisZ);
 12615        planarAxisSquared = WideArithmetic.AddSigned320(
 12616            axisX2,
 12617            axisZ2);
 12618        axisSquared = WideArithmetic.AddSigned320(
 12619            planarAxisSquared,
 12620            axisY2);
 12621        Signed320 heightSquared = WideArithmetic.MultiplySigned192(
 12622            Signed192.Raw(coneHeight),
 12623            Signed192.Raw(coneHeight));
 12624        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 12625            Signed192.Raw(coneRadius),
 12626            Signed192.Raw(coneRadius));
 12627        delta = WideArithmetic.SubtractSigned576(
 12628            WideArithmetic.MultiplySigned320(
 12629                heightSquared,
 12630                planarAxisSquared),
 12631            WideArithmetic.MultiplySigned320(
 12632                radiusSquared,
 12633                axisY2));
 12634        axisProjection = WideArithmetic.AddSigned576(
 12635            WideArithmetic.MultiplySigned320(
 12636                relativeX,
 12637                Signed320.ExtendValue(axisX)),
 12638            WideArithmetic.MultiplySigned320(
 12639                relativeZ,
 12640                Signed320.ExtendValue(axisZ)));
 12641        perpendicularProjection = WideArithmetic.SubtractSigned576(
 12642            WideArithmetic.MultiplySigned320(
 12643                relativeZ,
 12644                Signed320.ExtendValue(axisX)),
 12645            WideArithmetic.MultiplySigned320(
 12646                relativeX,
 12647                Signed320.ExtendValue(axisZ)));
 12648        Signed576 heightTerm = WideArithmetic.MultiplySigned576(
 12649            WideArithmetic.MultiplySigned576(
 12650                Signed576.ExtendValue(planarAxisSquared),
 12651                Signed192.Raw(coneHeight)),
 12652            coordinateDenominator);
 12653        Signed576 projectionTerm = WideArithmetic.MultiplySigned576(
 12654            axisProjection,
 12655            axisDenominator);
 12656        apexProjectionGap = WideArithmetic.SubtractSigned576(
 12657            heightTerm,
 12658            projectionTerm);
 12659    }
 660
 661    private static bool IsPointInConeProjectionWedge(
 662        Signed192 coordinateDenominator,
 663        Signed192 axisDenominator,
 664        Signed192 axisY,
 665        Fixed64 coneHeight,
 666        Fixed64 coneRadius,
 667        Signed320 planarAxisSquared,
 668        Signed576 delta,
 669        Signed576 axisProjection,
 670        Signed576 perpendicularProjection,
 671        Signed576 apexProjectionGap)
 672    {
 41673        if (apexProjectionGap.Sign < 0)
 9674            return false;
 675
 32676        Signed576 tangentStartLeft = WideArithmetic.MultiplySigned576(
 32677            WideArithmetic.MultiplySigned576(
 32678                axisProjection,
 32679                Signed192.Raw(coneHeight)),
 32680            axisDenominator);
 32681        Signed576 tangentStartRight = WideArithmetic.MultiplySigned576(
 32682            WideArithmetic.MultiplySigned320(
 32683                WideArithmetic.MultiplySigned192(
 32684                    Signed192.Raw(coneRadius),
 32685                    Signed192.Raw(coneRadius)),
 32686                WideArithmetic.MultiplySigned192(
 32687                    axisY,
 32688                    axisY)),
 32689            coordinateDenominator);
 32690        if (WideArithmetic.SubtractSigned576(
 32691                tangentStartLeft,
 32692                tangentStartRight).Sign < 0)
 693        {
 8694            return false;
 695        }
 696
 24697        Signed576 absolutePerpendicular =
 24698            WideArithmetic.Absolute(perpendicularProjection);
 24699        Signed576 radiusGap = WideArithmetic.MultiplySigned576(
 24700            apexProjectionGap,
 24701            Signed192.Raw(coneRadius));
 24702        return WideArithmetic.CompareSignedLinearRadicalToZero(
 24703                   Signed832.ExtendValue(
 24704                       WideArithmetic.SubtractSigned576(
 24705                           default,
 24706                           radiusGap)),
 24707                   Signed704.ExtendValue(absolutePerpendicular),
 24708                   delta,
 24709                   Signed320.ExtendValue(Signed192.Signed(1L))) <= 0;
 710    }
 711
 712    private static bool TryCompareConeTangentDistanceToRadius(
 713        Signed192 coordinateDenominator,
 714        Fixed64 coneHeight,
 715        Fixed64 coneRadius,
 716        Signed320 planarAxisSquared,
 717        Signed320 axisSquared,
 718        Signed576 delta,
 719        Signed576 perpendicularProjection,
 720        Signed576 apexProjectionGap,
 721        Signed192 radiusNumerator,
 722        int radiusDenominator,
 723        out int comparison)
 724    {
 37725        Signed576 absolutePerpendicular =
 37726            WideArithmetic.Absolute(perpendicularProjection);
 37727        Signed576 radiusPerpendicular = WideArithmetic.MultiplySigned576(
 37728            absolutePerpendicular,
 37729            Signed192.Raw(coneRadius));
 37730        Signed704 lowerRational =
 37731            WideArithmetic.MultiplySigned576ToSigned704(
 37732                radiusPerpendicular,
 37733                axisSquared);
 37734        int lowerGate = WideArithmetic.CompareSignedLinearRadicalToZero(
 37735            Signed832.ExtendValue(lowerRational),
 37736            Signed704.ExtendValue(apexProjectionGap),
 37737            delta,
 37738            Signed320.ExtendValue(Signed192.Signed(1L)));
 37739        if (lowerGate <= 0)
 740        {
 9741            comparison = default;
 9742            return false;
 743        }
 744
 28745        Signed320 sideSquared = WideArithmetic.AddSigned320(
 28746            WideArithmetic.MultiplySigned192(
 28747                Signed192.Raw(coneHeight),
 28748                Signed192.Raw(coneHeight)),
 28749            WideArithmetic.MultiplySigned192(
 28750                Signed192.Raw(coneRadius),
 28751                Signed192.Raw(coneRadius)));
 28752        Signed576 upperCoefficient = WideArithmetic.SubtractSigned576(
 28753            WideArithmetic.MultiplySigned576(
 28754                apexProjectionGap,
 28755                Signed192.Raw(coneHeight)),
 28756            WideArithmetic.MultiplySigned576(
 28757                WideArithmetic.MultiplySigned320(
 28758                    sideSquared,
 28759                    planarAxisSquared),
 28760                coordinateDenominator));
 28761        Signed576 heightRadiusPerpendicular =
 28762            WideArithmetic.MultiplySigned576(
 28763                absolutePerpendicular,
 28764                Signed192.Raw(coneHeight),
 28765                Signed192.Raw(coneRadius));
 28766        Signed704 upperRational =
 28767            WideArithmetic.MultiplySigned576ToSigned704(
 28768                heightRadiusPerpendicular,
 28769                axisSquared);
 28770        int upperGate = WideArithmetic.CompareSignedLinearRadicalToZero(
 28771            Signed832.ExtendValue(upperRational),
 28772            Signed704.ExtendValue(upperCoefficient),
 28773            delta,
 28774            Signed320.ExtendValue(Signed192.Signed(1L)));
 28775        if (upperGate >= 0)
 776        {
 8777            comparison = default;
 8778            return false;
 779        }
 780
 20781        Signed576 radiusGap = WideArithmetic.MultiplySigned576(
 20782            apexProjectionGap,
 20783            Signed192.Raw(coneRadius));
 20784        comparison = CompareConeTangentSquaredDistance(
 20785            absolutePerpendicular,
 20786            delta,
 20787            radiusGap,
 20788            coordinateDenominator,
 20789            planarAxisSquared,
 20790            sideSquared,
 20791            radiusNumerator,
 20792            radiusDenominator);
 20793        return true;
 794    }
 795
 796    private static int CompareConeTangentSquaredDistance(
 797        Signed576 radicalCoefficient,
 798        Signed576 radicand,
 799        Signed576 rationalMagnitude,
 800        Signed192 coordinateDenominator,
 801        Signed320 planarAxisSquared,
 802        Signed320 sideSquared,
 803        Signed192 radiusNumerator,
 804        int radiusDenominator)
 805    {
 20806        Span<ulong> first = stackalloc ulong[ConeComparisonWordCount];
 20807        Span<ulong> second = stackalloc ulong[ConeComparisonWordCount];
 20808        Span<ulong> third = stackalloc ulong[ConeComparisonWordCount];
 20809        Span<ulong> result = stackalloc ulong[ConeComparisonWordCount];
 20810        Span<ulong> other = stackalloc ulong[ConeComparisonWordCount];
 20811        Span<ulong> coefficient = stackalloc ulong[ConeComparisonWordCount];
 20812        Span<ulong> delta = stackalloc ulong[ConeComparisonWordCount];
 20813        Span<ulong> rational = stackalloc ulong[ConeComparisonWordCount];
 20814        Span<ulong> radius = stackalloc ulong[ConeComparisonWordCount];
 20815        Span<ulong> denominator = stackalloc ulong[ConeComparisonWordCount];
 20816        Span<ulong> planar = stackalloc ulong[ConeComparisonWordCount];
 20817        Span<ulong> side = stackalloc ulong[ConeComparisonWordCount];
 20818        first.Clear();
 20819        second.Clear();
 20820        third.Clear();
 20821        result.Clear();
 20822        other.Clear();
 20823        coefficient.Clear();
 20824        delta.Clear();
 20825        rational.Clear();
 20826        radius.Clear();
 20827        denominator.Clear();
 20828        planar.Clear();
 20829        side.Clear();
 20830        WideArithmetic.GetMagnitude(radicalCoefficient, coefficient);
 20831        WideArithmetic.GetMagnitude(radicand, delta);
 20832        WideArithmetic.GetMagnitude(rationalMagnitude, rational);
 20833        WideArithmetic.GetMagnitude(
 20834            radiusNumerator,
 20835            out radius[2],
 20836            out radius[1],
 20837            out radius[0]);
 20838        WideArithmetic.GetMagnitude(
 20839            coordinateDenominator,
 20840            out denominator[2],
 20841            out denominator[1],
 20842            out denominator[0]);
 20843        WideArithmetic.GetMagnitude(
 20844            planarAxisSquared,
 20845            out planar[4],
 20846            out planar[3],
 20847            out planar[2],
 20848            out planar[1],
 20849            out planar[0]);
 20850        WideArithmetic.GetMagnitude(
 20851            sideSquared,
 20852            out side[4],
 20853            out side[3],
 20854            out side[2],
 20855            out side[1],
 20856            out side[0]);
 857
 20858        WideArithmetic.MultiplyMagnitudes(
 20859            coefficient,
 20860            coefficient,
 20861            first);
 20862        WideArithmetic.MultiplyMagnitudes(first, delta, second);
 20863        WideArithmetic.MultiplyMagnitudes(rational, rational, first);
 20864        WideArithmetic.AddEqualMagnitudes(second, first, result);
 20865        if (radiusDenominator == 2)
 866        {
 3867            result.CopyTo(first);
 3868            WideArithmetic.AddEqualMagnitudes(first, first, second);
 3869            WideArithmetic.AddEqualMagnitudes(second, second, result);
 870        }
 871
 20872        WideArithmetic.MultiplyMagnitudes(radius, radius, first);
 20873        WideArithmetic.MultiplyMagnitudes(
 20874            denominator,
 20875            denominator,
 20876            second);
 20877        WideArithmetic.MultiplyMagnitudes(first, second, third);
 20878        WideArithmetic.MultiplyMagnitudes(planar, planar, first);
 20879        WideArithmetic.MultiplyMagnitudes(third, first, second);
 20880        WideArithmetic.MultiplyMagnitudes(second, side, other);
 881
 20882        int rationalComparison =
 20883            WideArithmetic.CompareMagnitudeEqualLength(result, other);
 20884        if (rationalComparison <= 0)
 1885            return -1;
 19886        WideArithmetic.SubtractEqualMagnitudes(
 19887            result,
 19888            other,
 19889            rational);
 890
 19891        WideArithmetic.GetMagnitude(rationalMagnitude, result);
 19892        WideArithmetic.MultiplyMagnitudes(coefficient, result, first);
 19893        first.CopyTo(second);
 19894        WideArithmetic.AddEqualMagnitudes(second, second, first);
 19895        if (radiusDenominator == 2)
 896        {
 3897            first.CopyTo(second);
 3898            WideArithmetic.AddEqualMagnitudes(second, second, first);
 3899            first.CopyTo(second);
 3900            WideArithmetic.AddEqualMagnitudes(second, second, first);
 901        }
 19902        WideArithmetic.MultiplyMagnitudes(first, first, second);
 19903        WideArithmetic.MultiplyMagnitudes(second, delta, other);
 19904        WideArithmetic.MultiplyMagnitudes(rational, rational, result);
 19905        return WideArithmetic.CompareMagnitudeEqualLength(result, other);
 906    }
 907
 908    private static int CompareRationalDistanceToRadius(
 909        RationalDistance distance,
 910        Signed192 radiusNumerator,
 911        int radiusDenominator) =>
 37912        radiusDenominator == 1
 37913            ? CompareDistanceToRaw(distance, radiusNumerator)
 37914            : CompareDistanceToTwiceRaw(distance, radiusNumerator);
 915
 916}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WidePlanarProjection.cs

#LineLine coverage
 1//=======================================================================
 2// WidePlanarProjection.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/// Owns exact point relations to complete X/Z projections without
 14/// materializing conceptual world-space features.
 15/// </summary>
 16internal static partial class WidePlanarProjection
 17{
 18    #region Nested Types
 19
 20    private readonly struct RationalPoint
 21    {
 22        internal RationalPoint(Signed320 x, Signed320 z)
 23        {
 13124            X = x;
 13125            Z = z;
 13126        }
 27
 28        internal readonly Signed320 X;
 29        internal readonly Signed320 Z;
 30    }
 31
 32    private readonly struct RationalDistance
 33    {
 34        internal RationalDistance(
 35            Signed576 x,
 36            Signed576 z,
 37            Signed576 denominator)
 38        {
 8739            X = x;
 8740            Z = z;
 8741            Denominator = denominator;
 8742            SquaredDistance = WideArithmetic.AddSigned832(
 8743                WideArithmetic.MultiplySigned576ToSigned832(x, x),
 8744                WideArithmetic.MultiplySigned576ToSigned832(z, z));
 8745        }
 46
 47        internal readonly Signed576 X;
 48        internal readonly Signed576 Z;
 49        internal readonly Signed576 Denominator;
 50        internal readonly Signed832 SquaredDistance;
 51    }
 52
 53    #endregion
 54
 55    internal static bool TryGetSphereRelation(
 56        Vector2d circleCenter,
 57        Fixed64 circleRadius,
 58        Vector3d sphereCenter,
 59        Fixed64 sphereRadius,
 60        out PlanarProjectionRelation relation)
 61    {
 362        Vector2d projectedCenter = new(
 363            sphereCenter.X,
 364            sphereCenter.Z);
 365        if (WideGeometry.CompareDistanceToRadiusSum(
 366                circleCenter,
 367                projectedCenter,
 368                circleRadius,
 369                sphereRadius) > 0)
 70        {
 171            relation = default;
 172            return false;
 73        }
 74
 275        if (WideGeometry.CompareDistanceToRadiusSum(
 276                circleCenter,
 277                projectedCenter,
 278                Fixed64.Zero,
 279                sphereRadius) <= 0)
 80        {
 181            relation = PlanarProjectionRelation.Contained;
 182            return true;
 83        }
 84
 185        _ = WideFiniteAxisIntersection.TryGetDistanceToCenteredCapsule(
 186            circleCenter,
 187            projectedCenter,
 188            Vector2d.Right,
 189            Fixed64.Zero,
 190            sphereRadius,
 191            out Fixed64 distance);
 92
 193        Vector2d normal =
 194            WideNormalization.GetDirection(projectedCenter, circleCenter);
 195        relation = new PlanarProjectionRelation(
 196            distance,
 197            -normal * distance,
 198            -normal);
 199        return true;
 100    }
 101
 102    internal static bool TryGetCenteredCapsuleRelation(
 103        Vector2d circleCenter,
 104        Fixed64 circleRadius,
 105        Vector3d capsuleCenter,
 106        FixedQuaternion capsuleRotation,
 107        Vector3d capsuleLocalAxis,
 108        Fixed64 capsuleAxisLength,
 109        Fixed64 capsuleRadius,
 110        out PlanarProjectionRelation relation)
 111    {
 6112        WideRationalBasis3d basis = new(capsuleRotation);
 6113        GetRotatedLocalAxis(
 6114            basis,
 6115            capsuleLocalAxis,
 6116            out Signed320 axisX,
 6117            out _,
 6118            out Signed320 axisZ);
 6119        GetCenteredAxisEndpoints(
 6120            capsuleCenter,
 6121            basis.Denominator,
 6122            axisX,
 6123            axisZ,
 6124            capsuleAxisLength,
 6125            out Signed192 axisDenominator,
 6126            out RationalPoint first,
 6127            out RationalPoint second);
 6128        RationalDistance axisDistance = GetSegmentDistance(
 6129            circleCenter,
 6130            axisDenominator,
 6131            first,
 6132            second);
 6133        return TryCreateRadiallyExpandedRelation(
 6134            axisDistance,
 6135            capsuleRadius,
 6136            circleRadius,
 6137            out relation);
 138    }
 139
 140    internal static bool TryGetCenteredCylinderRelation(
 141        Vector2d circleCenter,
 142        Fixed64 circleRadius,
 143        Vector3d cylinderCenter,
 144        FixedQuaternion cylinderRotation,
 145        Fixed64 cylinderAxisLength,
 146        Fixed64 cylinderRadius,
 147        out PlanarProjectionRelation relation)
 148    {
 16149        WideRationalBasis3d basis = new(cylinderRotation);
 16150        Signed192 axisX = basis.Yx;
 16151        Signed192 axisY = basis.Yy;
 16152        Signed192 axisZ = basis.Yz;
 16153        GetCenteredBasisAxisEndpoints(
 16154            cylinderCenter,
 16155            basis.Denominator,
 16156            axisX,
 16157            axisZ,
 16158            cylinderAxisLength,
 16159            out Signed192 axisDenominator,
 16160            out RationalPoint first,
 16161            out RationalPoint second);
 16162        RationalDistance axisDistance = GetSegmentDistance(
 16163            circleCenter,
 16164            axisDenominator,
 16165            first,
 16166            second,
 16167            out int feature);
 16168        if (feature == 0)
 169        {
 3170            return TryCreateRadiallyExpandedRelation(
 3171                axisDistance,
 3172                cylinderRadius,
 3173                circleRadius,
 3174                out relation);
 175        }
 176
 13177        return TryGetProjectedDiskRelation(
 13178            circleCenter,
 13179            circleRadius,
 13180            feature < 0 ? first : second,
 13181            axisDenominator,
 13182            axisX,
 13183            axisY,
 13184            axisZ,
 13185            cylinderRadius,
 13186            out relation);
 187    }
 188
 189    internal static bool TryGetCenteredConeRelation(
 190        Vector2d circleCenter,
 191        Fixed64 circleRadius,
 192        Vector3d coneCenter,
 193        FixedQuaternion coneRotation,
 194        Fixed64 coneHeight,
 195        Fixed64 coneRadius,
 196        out PlanarProjectionRelation relation)
 197    {
 14198        WideRationalBasis3d basis = new(coneRotation);
 14199        Signed192 axisX = basis.Yx;
 14200        Signed192 axisY = basis.Yy;
 14201        Signed192 axisZ = basis.Yz;
 14202        GetCenteredBasisAxisEndpoints(
 14203            coneCenter,
 14204            basis.Denominator,
 14205            axisX,
 14206            axisZ,
 14207            coneHeight,
 14208            out Signed192 axisDenominator,
 14209            out RationalPoint baseCenter,
 14210            out RationalPoint apex);
 14211        if (axisY.IsZero)
 212        {
 1213            GetProjectedDiskSegmentEndpoints(
 1214                baseCenter,
 1215                axisX,
 1216                axisZ,
 1217                coneRadius,
 1218                out RationalPoint first,
 1219                out RationalPoint second);
 1220            Span<RationalPoint> triangle =
 1221                stackalloc RationalPoint[3];
 1222            triangle[0] = first;
 1223            triangle[1] = second;
 1224            triangle[2] = apex;
 1225            return TryGetConvexRelation(
 1226                circleCenter,
 1227                circleRadius,
 1228                axisDenominator,
 1229                triangle,
 1230                out relation);
 231        }
 13232        if (axisX.IsZero && axisZ.IsZero)
 233        {
 1234            return TryGetProjectedDiskRelation(
 1235                circleCenter,
 1236                circleRadius,
 1237                baseCenter,
 1238                axisDenominator,
 1239                axisX,
 1240                axisY,
 1241                axisZ,
 1242                coneRadius,
 1243                out relation);
 244        }
 245
 12246        return TryGetRotatedConeRelation(
 12247            circleCenter,
 12248            circleRadius,
 12249            baseCenter,
 12250            apex,
 12251            axisDenominator,
 12252            basis.Denominator,
 12253            axisX,
 12254            axisY,
 12255            axisZ,
 12256            coneHeight,
 12257            coneRadius,
 12258            out relation);
 259    }
 260
 261    private static bool TryCreateRadiallyExpandedRelation(
 262        RationalDistance axisDistance,
 263        Fixed64 shapeRadius,
 264        Fixed64 queryRadius,
 265        out PlanarProjectionRelation relation)
 266    {
 11267        Signed576 shapeRadiusNumerator =
 11268            WideArithmetic.MultiplySigned576(
 11269                axisDistance.Denominator,
 11270                Signed192.Raw(shapeRadius));
 11271        Signed832 shapeRadiusSquared =
 11272            WideArithmetic.MultiplySigned576ToSigned832(
 11273                shapeRadiusNumerator,
 11274                shapeRadiusNumerator);
 11275        if (WideArithmetic.SubtractSigned832(
 11276                axisDistance.SquaredDistance,
 11277                shapeRadiusSquared).Sign <= 0)
 278        {
 2279            relation = PlanarProjectionRelation.Contained;
 2280            return true;
 281        }
 282
 9283        if (!TryGetRadialGap(
 9284                axisDistance,
 9285                shapeRadius,
 9286                queryRadius,
 9287                out Fixed64 distance))
 288        {
 2289            relation = default;
 2290            return false;
 291        }
 292
 7293        Vector2d direction = WideNormalization.GetNormalized(
 7294            axisDistance.X,
 7295            axisDistance.Z);
 7296        Vector2d offset = direction * distance;
 7297        relation = new PlanarProjectionRelation(
 7298            distance,
 7299            offset,
 7300            direction);
 7301        return true;
 302    }
 303
 304    private static void GetRotatedLocalAxis(
 305        WideRationalBasis3d basis,
 306        Vector3d localAxis,
 307        out Signed320 x,
 308        out Signed320 y,
 309        out Signed320 z)
 310    {
 6311        x = GetLocalOffsetNumerator(
 6312            basis.Xx,
 6313            basis.Yx,
 6314            basis.Zx,
 6315            localAxis);
 6316        y = GetLocalOffsetNumerator(
 6317            basis.Xy,
 6318            basis.Yy,
 6319            basis.Zy,
 6320            localAxis);
 6321        z = GetLocalOffsetNumerator(
 6322            basis.Xz,
 6323            basis.Yz,
 6324            basis.Zz,
 6325            localAxis);
 6326    }
 327
 328    private static Signed320 GetLocalOffsetNumerator(
 329        Signed192 x,
 330        Signed192 y,
 331        Signed192 z,
 332        Vector3d localPoint) =>
 128333        WideArithmetic.AddSigned320(
 128334            WideArithmetic.AddSigned320(
 128335                WideArithmetic.MultiplySigned192(
 128336                    x,
 128337                    Signed192.Raw(localPoint.X)),
 128338                WideArithmetic.MultiplySigned192(
 128339                    y,
 128340                    Signed192.Raw(localPoint.Y))),
 128341            WideArithmetic.MultiplySigned192(
 128342                z,
 128343                Signed192.Raw(localPoint.Z)));
 344
 345    private static RationalPoint GetWorldPoint(
 346        Vector3d origin,
 347        WideRationalBasis3d basis,
 348        Vector3d localPoint) =>
 55349        new(
 55350            WideArithmetic.AddSigned320(
 55351                WideArithmetic.MultiplySigned192(
 55352                    Signed192.Raw(origin.X),
 55353                    basis.Denominator),
 55354                GetLocalOffsetNumerator(
 55355                    basis.Xx,
 55356                    basis.Yx,
 55357                    basis.Zx,
 55358                    localPoint)),
 55359            WideArithmetic.AddSigned320(
 55360                WideArithmetic.MultiplySigned192(
 55361                    Signed192.Raw(origin.Z),
 55362                    basis.Denominator),
 55363                GetLocalOffsetNumerator(
 55364                    basis.Xz,
 55365                    basis.Yz,
 55366                    basis.Zz,
 55367                    localPoint)));
 368
 369    private static void GetCenteredAxisEndpoints(
 370        Vector3d center,
 371        Signed192 denominator,
 372        Signed320 axisX,
 373        Signed320 axisZ,
 374        Fixed64 axisLength,
 375        out Signed192 axisDenominator,
 376        out RationalPoint first,
 377        out RationalPoint second)
 378    {
 6379        Signed192 halfLengthNumerator =
 6380            Signed192.Signed(axisLength.m_rawValue);
 6381        axisDenominator = Signed192.NarrowValue(
 6382            WideArithmetic.AddSigned320(
 6383                WideArithmetic.MultiplySigned192(
 6384                    denominator,
 6385                    Signed192.Raw(Fixed64.One)),
 6386                WideArithmetic.MultiplySigned192(
 6387                    denominator,
 6388                    Signed192.Raw(Fixed64.One))));
 6389        Signed320 centerX = WideArithmetic.MultiplySigned192(
 6390            Signed192.Raw(center.X),
 6391            axisDenominator);
 6392        Signed320 centerZ = WideArithmetic.MultiplySigned192(
 6393            Signed192.Raw(center.Z),
 6394            axisDenominator);
 6395        Signed320 offsetX = Signed320.NarrowValue(
 6396            WideArithmetic.MultiplySigned320(
 6397                axisX,
 6398                Signed320.ExtendValue(halfLengthNumerator)));
 6399        Signed320 offsetZ = Signed320.NarrowValue(
 6400            WideArithmetic.MultiplySigned320(
 6401                axisZ,
 6402                Signed320.ExtendValue(halfLengthNumerator)));
 6403        first = new RationalPoint(
 6404            WideArithmetic.SubtractSigned320(centerX, offsetX),
 6405            WideArithmetic.SubtractSigned320(centerZ, offsetZ));
 6406        second = new RationalPoint(
 6407            WideArithmetic.AddSigned320(centerX, offsetX),
 6408            WideArithmetic.AddSigned320(centerZ, offsetZ));
 6409    }
 410
 411    private static void GetCenteredBasisAxisEndpoints(
 412        Vector3d center,
 413        Signed192 denominator,
 414        Signed192 axisX,
 415        Signed192 axisZ,
 416        Fixed64 axisLength,
 417        out Signed192 axisDenominator,
 418        out RationalPoint first,
 419        out RationalPoint second)
 420    {
 30421        axisDenominator = WideArithmetic.AddSigned192(
 30422            denominator,
 30423            denominator);
 30424        Signed320 centerX = WideArithmetic.MultiplySigned192(
 30425            Signed192.Raw(center.X),
 30426            axisDenominator);
 30427        Signed320 centerZ = WideArithmetic.MultiplySigned192(
 30428            Signed192.Raw(center.Z),
 30429            axisDenominator);
 30430        Signed320 offsetX = WideArithmetic.MultiplySigned192(
 30431            axisX,
 30432            Signed192.Raw(axisLength));
 30433        Signed320 offsetZ = WideArithmetic.MultiplySigned192(
 30434            axisZ,
 30435            Signed192.Raw(axisLength));
 30436        first = new RationalPoint(
 30437            WideArithmetic.SubtractSigned320(centerX, offsetX),
 30438            WideArithmetic.SubtractSigned320(centerZ, offsetZ));
 30439        second = new RationalPoint(
 30440            WideArithmetic.AddSigned320(centerX, offsetX),
 30441            WideArithmetic.AddSigned320(centerZ, offsetZ));
 30442    }
 443
 444    private static bool TryGetRadialGap(
 445        RationalDistance distance,
 446        Fixed64 shapeRadius,
 447        Fixed64 maximumGap,
 448        out Fixed64 gap)
 449    {
 9450        Signed192 shapeRaw = Signed192.Raw(shapeRadius);
 9451        Signed192 maximumRaw = WideArithmetic.AddSigned192(
 9452            shapeRaw,
 9453            Signed192.Raw(maximumGap));
 9454        if (CompareDistanceToRaw(distance, maximumRaw) > 0)
 455        {
 2456            gap = default;
 2457            return false;
 458        }
 459
 7460        long low = 0L;
 7461        long high = maximumGap.m_rawValue;
 175462        while (low < high)
 463        {
 168464            long difference = high - low;
 168465            long middle =
 168466                low + (difference >> 1) + (difference & 1L);
 168467            Signed192 candidate = WideArithmetic.AddSigned192(
 168468                shapeRaw,
 168469                Signed192.Signed(middle));
 168470            if (CompareDistanceToRaw(distance, candidate) >= 0)
 151471                low = middle;
 472            else
 17473                high = middle - 1L;
 474        }
 475
 7476        if (low != maximumGap.m_rawValue)
 477        {
 3478            Signed192 midpoint = WideArithmetic.AddSigned192(
 3479                WideArithmetic.AddSigned192(
 3480                    WideArithmetic.AddSigned192(shapeRaw, shapeRaw),
 3481                    WideArithmetic.AddSigned192(
 3482                        Signed192.Signed(low),
 3483                        Signed192.Signed(low))),
 3484                Signed192.Signed(1L));
 3485            int comparison =
 3486                CompareDistanceToTwiceRaw(distance, midpoint);
 3487            low += GetHalfToEvenIncrement(comparison, low);
 488        }
 489
 7490        gap = Fixed64.FromRaw(low);
 7491        return true;
 492    }
 493
 494    private static RationalDistance GetPointDistance(
 495        Vector2d point,
 496        Signed192 denominator,
 497        RationalPoint target)
 498    {
 47499        Signed320 x = WideArithmetic.SubtractSigned320(
 47500            target.X,
 47501            WideArithmetic.MultiplySigned192(
 47502                Signed192.Raw(point.X),
 47503                denominator));
 47504        Signed320 z = WideArithmetic.SubtractSigned320(
 47505            target.Z,
 47506            WideArithmetic.MultiplySigned192(
 47507                Signed192.Raw(point.Y),
 47508                denominator));
 47509        return new RationalDistance(
 47510            Signed576.ExtendValue(x),
 47511            Signed576.ExtendValue(z),
 47512            Signed576.ExtendValue(
 47513                Signed320.ExtendValue(denominator)));
 514    }
 515
 516    private static RationalDistance GetSegmentDistance(
 517        Vector2d point,
 518        Signed192 denominator,
 519        RationalPoint first,
 520        RationalPoint second) =>
 34521        GetSegmentDistance(
 34522            point,
 34523            denominator,
 34524            first,
 34525            second,
 34526            out _);
 527
 528    private static RationalDistance GetSegmentDistance(
 529        Vector2d point,
 530        Signed192 denominator,
 531        RationalPoint first,
 532        RationalPoint second,
 533        out int feature)
 534    {
 50535        Signed320 firstX = WideArithmetic.SubtractSigned320(
 50536            first.X,
 50537            WideArithmetic.MultiplySigned192(
 50538                Signed192.Raw(point.X),
 50539                denominator));
 50540        Signed320 firstZ = WideArithmetic.SubtractSigned320(
 50541            first.Z,
 50542            WideArithmetic.MultiplySigned192(
 50543                Signed192.Raw(point.Y),
 50544                denominator));
 50545        Signed320 edgeX = WideArithmetic.SubtractSigned320(
 50546            second.X,
 50547            first.X);
 50548        Signed320 edgeZ = WideArithmetic.SubtractSigned320(
 50549            second.Z,
 50550            first.Z);
 50551        Signed576 edgeSquared = WideArithmetic.AddSigned576(
 50552            WideArithmetic.MultiplySigned320(edgeX, edgeX),
 50553            WideArithmetic.MultiplySigned320(edgeZ, edgeZ));
 50554        if (edgeSquared.IsZero)
 555        {
 10556            feature = -1;
 10557            return new RationalDistance(
 10558                Signed576.ExtendValue(firstX),
 10559                Signed576.ExtendValue(firstZ),
 10560                Signed576.ExtendValue(
 10561                    Signed320.ExtendValue(denominator)));
 562        }
 563
 40564        Signed576 projection = WideArithmetic.SubtractSigned576(
 40565            default,
 40566            WideArithmetic.AddSigned576(
 40567                WideArithmetic.MultiplySigned320(firstX, edgeX),
 40568                WideArithmetic.MultiplySigned320(firstZ, edgeZ)));
 40569        if (projection.Sign <= 0)
 570        {
 20571            feature = -1;
 20572            return new RationalDistance(
 20573                Signed576.ExtendValue(firstX),
 20574                Signed576.ExtendValue(firstZ),
 20575                Signed576.ExtendValue(
 20576                    Signed320.ExtendValue(denominator)));
 577        }
 20578        if (WideArithmetic.SubtractSigned576(
 20579                projection,
 20580                edgeSquared).Sign >= 0)
 581        {
 10582            feature = 1;
 10583            return GetPointDistance(point, denominator, second);
 584        }
 585
 10586        feature = 0;
 10587        Signed576 x = WideArithmetic.AddSigned576(
 10588            WideArithmetic.MultiplySigned576(
 10589                edgeSquared,
 10590                Signed192.NarrowValue(firstX)),
 10591            WideArithmetic.MultiplySigned576(
 10592                projection,
 10593                Signed192.NarrowValue(edgeX)));
 10594        Signed576 z = WideArithmetic.AddSigned576(
 10595            WideArithmetic.MultiplySigned576(
 10596                edgeSquared,
 10597                Signed192.NarrowValue(firstZ)),
 10598            WideArithmetic.MultiplySigned576(
 10599                projection,
 10600                Signed192.NarrowValue(edgeZ)));
 10601        Signed576 combinedDenominator =
 10602            WideArithmetic.MultiplySigned576(
 10603                edgeSquared,
 10604                denominator);
 10605        return new RationalDistance(x, z, combinedDenominator);
 606    }
 607
 608    private static bool IsWithinRadius(
 609        RationalDistance distance,
 610        Fixed64 radius)
 611    {
 8612        Signed576 scaledRadius = WideArithmetic.MultiplySigned576(
 8613            distance.Denominator,
 8614            Signed192.Raw(radius));
 8615        Signed832 squaredRadius =
 8616            WideArithmetic.MultiplySigned576ToSigned832(
 8617                scaledRadius,
 8618                scaledRadius);
 8619        return WideArithmetic.SubtractSigned832(
 8620            distance.SquaredDistance,
 8621            squaredRadius).Sign <= 0;
 622    }
 623
 624    private static bool TryGetDistance(
 625        RationalDistance distance,
 626        Fixed64 maximum,
 627        out Fixed64 result)
 628    {
 8629        if (!IsWithinRadius(distance, maximum))
 630        {
 2631            result = default;
 2632            return false;
 633        }
 634
 6635        long low = 0L;
 6636        long high = maximum.m_rawValue;
 203637        while (low < high)
 638        {
 197639            long difference = high - low;
 197640            long middle =
 197641                low + (difference >> 1) + (difference & 1L);
 197642            if (CompareDistanceToRaw(distance, middle) >= 0)
 165643                low = middle;
 644            else
 32645                high = middle - 1L;
 646        }
 647
 6648        if (low != maximum.m_rawValue)
 649        {
 2650            long doubledLow = low + low;
 2651            int midpointComparison =
 2652                CompareDistanceToTwiceRaw(
 2653                    distance,
 2654                    doubledLow + 1L);
 2655            low += GetHalfToEvenIncrement(midpointComparison, low);
 656        }
 657
 6658        result = Fixed64.FromRaw(low);
 6659        return true;
 660    }
 661
 662    private static int CompareDistanceToRaw(
 663        RationalDistance distance,
 664        long raw) =>
 197665        CompareDistanceToRaw(
 197666            distance,
 197667            Signed192.Signed(raw));
 668
 669    private static int CompareDistanceToRaw(
 670        RationalDistance distance,
 671        Signed192 raw)
 672    {
 449673        Signed576 scaled = WideArithmetic.MultiplySigned576(
 449674            distance.Denominator,
 449675            raw);
 449676        Signed832 squared = WideArithmetic.MultiplySigned576ToSigned832(
 449677            scaled,
 449678            scaled);
 449679        return WideArithmetic.SubtractSigned832(
 449680            distance.SquaredDistance,
 449681            squared).Sign;
 682    }
 683
 684    private static int CompareDistanceToTwiceRaw(
 685        RationalDistance distance,
 686        long twiceRaw) =>
 2687        CompareDistanceToTwiceRaw(
 2688            distance,
 2689            Signed192.Signed(twiceRaw));
 690
 691    private static int CompareDistanceToTwiceRaw(
 692        RationalDistance distance,
 693        Signed192 twiceRaw)
 694    {
 20695        Signed832 fourDistance = WideArithmetic.AddSigned832(
 20696            WideArithmetic.AddSigned832(
 20697                distance.SquaredDistance,
 20698                distance.SquaredDistance),
 20699            WideArithmetic.AddSigned832(
 20700                distance.SquaredDistance,
 20701                distance.SquaredDistance));
 20702        Signed576 scaled = WideArithmetic.MultiplySigned576(
 20703            distance.Denominator,
 20704            twiceRaw);
 20705        Signed832 squared = WideArithmetic.MultiplySigned576ToSigned832(
 20706            scaled,
 20707            scaled);
 20708        return WideArithmetic.SubtractSigned832(
 20709            fourDistance,
 20710            squared).Sign;
 711    }
 712
 713    private static Vector2d GetOffset(RationalDistance distance)
 714    {
 6715        _ = Fixed64.TryGetSignedRawRatio(
 6716            distance.X,
 6717            distance.Denominator,
 6718            out Fixed64 x);
 6719        _ = Fixed64.TryGetSignedRawRatio(
 6720            distance.Z,
 6721            distance.Denominator,
 6722            out Fixed64 z);
 6723        return new Vector2d(x, z);
 724    }
 725
 726    private static long GetHalfToEvenIncrement(
 727        int midpointComparison,
 728        long lowerRaw)
 729    {
 5730        int negative = (int)((uint)midpointComparison >> 31);
 5731        int nonzero = (int)(
 5732            (uint)(midpointComparison | -midpointComparison) >> 31);
 5733        int positive = nonzero & (negative ^ 1);
 5734        int zero = nonzero ^ 1;
 5735        return (long)positive | ((long)zero & (lowerRaw & 1L));
 736    }
 737
 738    private static Signed320 GetLargestPositiveMagnitude(
 739        Signed320 first,
 740        Signed320 second,
 741        Signed320 third,
 742        Signed320 fourth,
 743        Signed320 fifth)
 744    {
 16745        Signed320 largest =
 16746            WideArithmetic.CompareMagnitude(first, second) >= 0
 16747                ? first
 16748                : second;
 16749        if (WideArithmetic.CompareMagnitude(largest, third) < 0)
 4750            largest = third;
 16751        if (WideArithmetic.CompareMagnitude(largest, fourth) < 0)
 4752            largest = fourth;
 16753        if (WideArithmetic.CompareMagnitude(largest, fifth) < 0)
 2754            largest = fifth;
 16755        return largest.Sign < 0
 16756            ? WideArithmetic.SubtractSigned320(default, largest)
 16757            : largest;
 758    }
 759}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WidePlanarProjection.Disk.cs

#LineLine coverage
 1//=======================================================================
 2// WidePlanarProjection.Disk.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/// Exact projected-disk admission and correctly rounded planar distance.
 14/// </content>
 15internal static partial class WidePlanarProjection
 16{
 17    private static bool TryGetProjectedDiskRelation(
 18        Vector2d circleCenter,
 19        Fixed64 circleRadius,
 20        RationalPoint diskCenter,
 21        Signed192 coordinateDenominator,
 22        Signed192 axisX,
 23        Signed192 axisY,
 24        Signed192 axisZ,
 25        Fixed64 diskRadius,
 26        out PlanarProjectionRelation relation)
 27    {
 1428        if (axisY.IsZero)
 29        {
 130            GetProjectedDiskSegmentEndpoints(
 131                diskCenter,
 132                axisX,
 133                axisZ,
 134                diskRadius,
 135                out RationalPoint first,
 136                out RationalPoint second);
 137            return TryCreateRelation(
 138                GetSegmentDistance(
 139                    circleCenter,
 140                    coordinateDenominator,
 141                    first,
 142                    second),
 143                circleRadius,
 144                out relation);
 45        }
 46
 1347        RationalDistance centerDistance = GetPointDistance(
 1348            circleCenter,
 1349            coordinateDenominator,
 1350            diskCenter);
 1351        if (axisX.IsZero && axisZ.IsZero)
 52        {
 253            return TryCreateRadiallyExpandedRelation(
 254                centerDistance,
 255                diskRadius,
 256                circleRadius,
 257                out relation);
 58        }
 59
 1160        int maximumComparison = CompareProjectedDiskDistanceToRadius(
 1161            centerDistance,
 1162            coordinateDenominator,
 1163            axisX,
 1164            axisY,
 1165            axisZ,
 1166            diskRadius,
 1167            Signed192.Raw(circleRadius),
 1168            radiusDenominator: 1);
 1169        if (maximumComparison > 0)
 70        {
 171            relation = default;
 172            return false;
 73        }
 74
 1075        int zeroComparison = CompareProjectedDiskDistanceToRadius(
 1076            centerDistance,
 1077            coordinateDenominator,
 1078            axisX,
 1079            axisY,
 1080            axisZ,
 1081            diskRadius,
 1082            default,
 1083            radiusDenominator: 1);
 1084        if (zeroComparison <= 0)
 85        {
 286            relation = PlanarProjectionRelation.Contained;
 287            return true;
 88        }
 89
 890        GetProjectedDiskClosestOffset(
 891            centerDistance,
 892            coordinateDenominator,
 893            axisX,
 894            axisY,
 895            axisZ,
 896            diskRadius,
 897            out Fixed64 approximateDistance,
 898            out Vector2d direction);
 899        long low = GetProjectedDiskCeilingDistance(
 8100            centerDistance,
 8101            coordinateDenominator,
 8102            axisX,
 8103            axisY,
 8104            axisZ,
 8105            diskRadius,
 8106            circleRadius,
 8107            approximateDistance);
 108
 8109        long floor = low - 1L;
 8110        Signed192 midpointNumerator = WideArithmetic.AddSigned192(
 8111            WideArithmetic.AddSigned192(
 8112                Signed192.Signed(floor),
 8113                Signed192.Signed(floor)),
 8114            Signed192.Signed(1L));
 8115        int midpointComparison = CompareProjectedDiskDistanceToRadius(
 8116            centerDistance,
 8117            coordinateDenominator,
 8118            axisX,
 8119            axisY,
 8120            axisZ,
 8121            diskRadius,
 8122            midpointNumerator,
 8123            radiusDenominator: 2);
 8124        long rounded = midpointComparison < 0
 8125            ? floor
 8126            : midpointComparison > 0
 8127                ? low
 8128                : floor + (floor & 1L);
 8129        Fixed64 distance = Fixed64.FromRaw(rounded);
 8130        relation = new PlanarProjectionRelation(
 8131            distance,
 8132            direction * distance,
 8133            direction);
 8134        return true;
 135    }
 136
 137    private static long GetProjectedDiskCeilingDistance(
 138        RationalDistance centerDistance,
 139        Signed192 coordinateDenominator,
 140        Signed192 axisX,
 141        Signed192 axisY,
 142        Signed192 axisZ,
 143        Fixed64 diskRadius,
 144        Fixed64 maximum,
 145        Fixed64 approximate)
 146    {
 8147        long candidate = approximate.m_rawValue;
 8148        if (candidate > maximum.m_rawValue)
 2149            candidate = maximum.m_rawValue;
 150
 8151        int comparison = CompareProjectedDiskDistanceToRadius(
 8152            centerDistance,
 8153            coordinateDenominator,
 8154            axisX,
 8155            axisY,
 8156            axisZ,
 8157            diskRadius,
 8158            Signed192.Signed(candidate),
 8159            radiusDenominator: 1);
 8160        if (comparison <= 0)
 161        {
 4162            long high = candidate;
 4163            long step = 1L;
 14164            while (high > 1L)
 165            {
 12166                long probe = high > step ? high - step : 0L;
 12167                if (probe == 0L
 12168                    || CompareProjectedDiskDistanceToRadius(
 12169                        centerDistance,
 12170                        coordinateDenominator,
 12171                        axisX,
 12172                        axisY,
 12173                        axisZ,
 12174                        diskRadius,
 12175                        Signed192.Signed(probe),
 12176                        radiusDenominator: 1) > 0)
 177                {
 2178                    return FindProjectedDiskCeilingDistance(
 2179                        centerDistance,
 2180                        coordinateDenominator,
 2181                        axisX,
 2182                        axisY,
 2183                        axisZ,
 2184                        diskRadius,
 2185                        probe + 1L,
 2186                        high);
 187                }
 188
 10189                high = probe;
 10190                step = (long)Math.Min(
 10191                    (ulong)step << 1,
 10192                    (ulong)high);
 193            }
 194
 2195            return 1L;
 196        }
 197
 4198        long low = candidate + 1L;
 4199        long upper = maximum.m_rawValue;
 4200        long upwardStep = 1L;
 6201        while (low < upper)
 202        {
 3203            long remaining = upper - candidate;
 3204            long probe = candidate + Math.Min(
 3205                upwardStep,
 3206                remaining);
 3207            if (CompareProjectedDiskDistanceToRadius(
 3208                centerDistance,
 3209                coordinateDenominator,
 3210                axisX,
 3211                axisY,
 3212                axisZ,
 3213                diskRadius,
 3214                Signed192.Signed(probe),
 3215                radiusDenominator: 1) <= 0)
 216            {
 1217                return FindProjectedDiskCeilingDistance(
 1218                    centerDistance,
 1219                    coordinateDenominator,
 1220                    axisX,
 1221                    axisY,
 1222                    axisZ,
 1223                    diskRadius,
 1224                    low,
 1225                    probe);
 226            }
 227
 2228            low = probe + 1L;
 2229            upwardStep = (long)Math.Min(
 2230                (ulong)upwardStep << 1,
 2231                (ulong)(upper - candidate));
 232        }
 233
 3234        return upper;
 235    }
 236
 237    private static long FindProjectedDiskCeilingDistance(
 238        RationalDistance centerDistance,
 239        Signed192 coordinateDenominator,
 240        Signed192 axisX,
 241        Signed192 axisY,
 242        Signed192 axisZ,
 243        Fixed64 diskRadius,
 244        long low,
 245        long high)
 246    {
 13247        while (low < high)
 248        {
 10249            long middle = low + ((high - low) >> 1);
 10250            int comparison = CompareProjectedDiskDistanceToRadius(
 10251                centerDistance,
 10252                coordinateDenominator,
 10253                axisX,
 10254                axisY,
 10255                axisZ,
 10256                diskRadius,
 10257                Signed192.Signed(middle),
 10258                radiusDenominator: 1);
 10259            if (comparison <= 0)
 5260                high = middle;
 261            else
 5262                low = middle + 1L;
 263        }
 264
 3265        return low;
 266    }
 267
 268    private static void GetProjectedDiskClosestOffset(
 269        RationalDistance centerDistance,
 270        Signed192 coordinateDenominator,
 271        Signed192 axisX,
 272        Signed192 axisY,
 273        Signed192 axisZ,
 274        Fixed64 diskRadius,
 275        out Fixed64 approximateDistance,
 276        out Vector2d direction)
 277    {
 8278        Signed320 relativeX = Signed320.NarrowValue(centerDistance.X);
 8279        Signed320 relativeZ = Signed320.NarrowValue(centerDistance.Z);
 8280        Signed320 scaledRadius = WideArithmetic.MultiplySigned192(
 8281            coordinateDenominator,
 8282            Signed192.Raw(diskRadius));
 8283        Signed320 scale = GetLargestPositiveMagnitude(
 8284            relativeX,
 8285            relativeZ,
 8286            default,
 8287            scaledRadius,
 8288            default);
 8289        Fixed64 queryX = -Fixed64.GetSignedRatio(relativeX, scale);
 8290        Fixed64 queryZ = -Fixed64.GetSignedRatio(relativeZ, scale);
 8291        Fixed64 radius = Fixed64.GetSignedRatio(scaledRadius, scale);
 8292        Vector2d axis = WideNormalization.GetNormalized(axisX, axisZ);
 8293        Vector2d perpendicular = new(-axis.Y, axis.X);
 8294        Fixed64 along = Vector2d.Dot(new Vector2d(queryX, queryZ), axis);
 8295        Fixed64 across = Vector2d.Dot(
 8296            new Vector2d(queryX, queryZ),
 8297            perpendicular);
 8298        Fixed64 axisYRatio = FixedMath.Abs(
 8299            WideNormalization.GetNormalized(
 8300                axisX,
 8301                axisY,
 8302                axisZ).Y);
 8303        Fixed64 minor = radius * axisYRatio;
 8304        Vector2d localOffset = GetEllipseClosestOffset(
 8305            along,
 8306            across,
 8307            minor,
 8308            radius);
 8309        Vector2d worldOffset =
 8310            axis * localOffset.X + perpendicular * localOffset.Y;
 8311        direction = worldOffset.Normalized;
 312
 8313        Signed576 distanceNumerator =
 8314            WideArithmetic.MultiplySigned320(
 8315                scale,
 8316                Signed320.ExtendValue(
 8317                    Signed192.Raw(worldOffset.Magnitude)));
 8318        _ = Fixed64.TryGetSignedRawRatio(
 8319            distanceNumerator,
 8320            Signed576.ExtendValue(
 8321                WideArithmetic.MultiplySigned192(
 8322                    coordinateDenominator,
 8323                    Signed192.Raw(Fixed64.One))),
 8324            out approximateDistance);
 8325    }
 326
 327    private static Vector2d GetEllipseClosestOffset(
 328        Fixed64 queryX,
 329        Fixed64 queryY,
 330        Fixed64 radiusX,
 331        Fixed64 radiusY)
 332    {
 16333        Fixed64 radiusXSquared = radiusX * radiusX;
 16334        Fixed64 radiusYSquared = radiusY * radiusY;
 16335        Fixed64 low = Fixed64.Zero;
 16336        Fixed64 high = Fixed64.Two;
 544337        while (high.m_rawValue - low.m_rawValue > 1L)
 338        {
 528339            Fixed64 middle = Fixed64.FromRaw(
 528340                low.m_rawValue
 528341                + ((high.m_rawValue - low.m_rawValue) >> 1));
 528342            Fixed64 x = GetEllipseConstraintCoordinate(
 528343                radiusX,
 528344                queryX,
 528345                middle + radiusXSquared);
 528346            Fixed64 y = GetEllipseConstraintCoordinate(
 528347                radiusY,
 528348                queryY,
 528349                middle + radiusYSquared);
 528350            if (x * x + y * y > Fixed64.One)
 185351                low = middle;
 352            else
 343353                high = middle;
 354        }
 355
 16356        Fixed64 closestX = Fixed64.MultiplyDivide(
 16357            radiusXSquared,
 16358            queryX,
 16359            high + radiusXSquared,
 16360            out _);
 16361        Fixed64 closestY = Fixed64.MultiplyDivide(
 16362            radiusYSquared,
 16363            queryY,
 16364            high + radiusYSquared,
 16365            out _);
 16366        return new Vector2d(
 16367            closestX - queryX,
 16368            closestY - queryY);
 369    }
 370
 371    private static Fixed64 GetEllipseConstraintCoordinate(
 372        Fixed64 radius,
 373        Fixed64 query,
 374        Fixed64 denominator) =>
 1056375        Fixed64.MultiplyDivide(
 1056376            radius,
 1056377            query,
 1056378            denominator,
 1056379            out _);
 380
 381    private static void GetProjectedDiskSegmentEndpoints(
 382        RationalPoint diskCenter,
 383        Signed192 axisX,
 384        Signed192 axisZ,
 385        Fixed64 diskRadius,
 386        out RationalPoint first,
 387        out RationalPoint second)
 388    {
 2389        Signed192 scaledRadius = WideArithmetic.AddSigned192(
 2390            Signed192.Raw(diskRadius),
 2391            Signed192.Raw(diskRadius));
 392
 2393        Signed320 offsetX = WideArithmetic.MultiplySigned192(
 2394            WideArithmetic.SubtractSigned192(
 2395                default,
 2396                axisZ),
 2397            scaledRadius);
 2398        Signed320 offsetZ = WideArithmetic.MultiplySigned192(
 2399            axisX,
 2400            scaledRadius);
 2401        first = new RationalPoint(
 2402            WideArithmetic.AddSigned320(
 2403                diskCenter.X,
 2404                offsetX),
 2405            WideArithmetic.AddSigned320(
 2406                diskCenter.Z,
 2407                offsetZ));
 2408        second = new RationalPoint(
 2409            WideArithmetic.SubtractSigned320(
 2410                diskCenter.X,
 2411                offsetX),
 2412            WideArithmetic.SubtractSigned320(
 2413                diskCenter.Z,
 2414                offsetZ));
 2415    }
 416
 417    private static int CompareProjectedDiskDistanceToRadius(
 418        RationalDistance centerDistance,
 419        Signed192 coordinateDenominator,
 420        Signed192 axisX,
 421        Signed192 axisY,
 422        Signed192 axisZ,
 423        Fixed64 diskRadius,
 424        Signed192 radiusNumerator,
 425        int radiusDenominator)
 426    {
 132427        Signed320 relativeX = Signed320.NarrowValue(
 132428            centerDistance.X);
 132429        Signed320 relativeZ = Signed320.NarrowValue(
 132430            centerDistance.Z);
 132431        int centerSign = EvaluateProjectedDiskConic(
 132432            relativeX,
 132433            relativeZ,
 132434            coordinateDenominator,
 132435            axisX,
 132436            axisY,
 132437            axisZ,
 132438            diskRadius);
 132439        if (centerSign <= 0)
 4440            return radiusNumerator.IsZero ? 0 : -1;
 128441        if (radiusNumerator.IsZero)
 20442            return 1;
 443
 108444        int rootCount = CountProjectedDiskCircleRoots(
 108445            relativeX,
 108446            relativeZ,
 108447            coordinateDenominator,
 108448            axisX,
 108449            axisY,
 108450            axisZ,
 108451            diskRadius,
 108452            radiusNumerator,
 108453            radiusDenominator);
 108454        if (rootCount != 0)
 55455            return rootCount == 1 ? 0 : -1;
 456
 53457        int centerDistanceComparison = radiusDenominator == 1
 53458            ? CompareDistanceToRaw(
 53459                centerDistance,
 53460                radiusNumerator)
 53461            : CompareDistanceToTwiceRaw(
 53462                centerDistance,
 53463                radiusNumerator);
 53464        return centerDistanceComparison <= 0 ? -1 : 1;
 465    }
 466
 467    private static int CountProjectedDiskCircleRoots(
 468        Signed320 relativeX,
 469        Signed320 relativeZ,
 470        Signed192 coordinateDenominator,
 471        Signed192 axisX,
 472        Signed192 axisY,
 473        Signed192 axisZ,
 474        Fixed64 diskRadius,
 475        Signed192 radiusNumerator,
 476        int radiusDenominator)
 477    {
 108478        CreateProjectedDiskCirclePolynomial(
 108479            relativeX,
 108480            relativeZ,
 108481            coordinateDenominator,
 108482            axisX,
 108483            axisY,
 108484            axisZ,
 108485            diskRadius,
 108486            radiusNumerator,
 108487            radiusDenominator,
 108488            1,
 108489            0,
 108490            out Signed832 constant,
 108491            out Signed832 linear,
 108492            out Signed832 quadratic,
 108493            out Signed832 cubic,
 108494            out Signed832 quartic);
 108495        if (quartic.Sign == 0)
 496        {
 1497            CreateProjectedDiskCirclePolynomial(
 1498                relativeX,
 1499                relativeZ,
 1500                coordinateDenominator,
 1501                axisX,
 1502                axisY,
 1503                axisZ,
 1504                diskRadius,
 1505                radiusNumerator,
 1506                radiusDenominator,
 1507                -1,
 1508                0,
 1509                out constant,
 1510                out linear,
 1511                out quadratic,
 1512                out cubic,
 1513                out quartic);
 514        }
 515
 108516        return WideFiniteAxisIntersection.CountProjectionDomainQuarticRoots(
 108517            constant,
 108518            linear,
 108519            quadratic,
 108520            cubic,
 108521            quartic);
 522    }
 523
 524    private static void CreateProjectedDiskCirclePolynomial(
 525        Signed320 relativeX,
 526        Signed320 relativeZ,
 527        Signed192 coordinateDenominator,
 528        Signed192 axisX,
 529        Signed192 axisY,
 530        Signed192 axisZ,
 531        Fixed64 diskRadius,
 532        Signed192 radiusNumerator,
 533        int radiusDenominator,
 534        int directionX,
 535        int directionZ,
 536        out Signed832 constant,
 537        out Signed832 linear,
 538        out Signed832 quadratic,
 539        out Signed832 cubic,
 540        out Signed832 quartic)
 541    {
 109542        Signed320 radiusScale = WideArithmetic.MultiplySigned192(
 109543            radiusNumerator,
 109544            coordinateDenominator);
 109545        Signed320 scaledX = MultiplyBySmall(
 109546            relativeX,
 109547            radiusDenominator);
 109548        Signed320 scaledZ = MultiplyBySmall(
 109549            relativeZ,
 109550            radiusDenominator);
 109551        Signed320 radialX = MultiplyBySmall(
 109552            radiusScale,
 109553            directionX);
 109554        Signed320 radialZ = MultiplyBySmall(
 109555            radiusScale,
 109556            directionZ);
 109557        Signed320 perpendicularX = MultiplyBySmall(
 109558            radiusScale,
 109559            -directionZ * 2);
 109560        Signed320 perpendicularZ = MultiplyBySmall(
 109561            radiusScale,
 109562            directionX * 2);
 109563        Signed320 x0 = WideArithmetic.AddSigned320(
 109564            scaledX,
 109565            radialX);
 109566        Signed320 x1 = perpendicularX;
 109567        Signed320 x2 = WideArithmetic.SubtractSigned320(
 109568            scaledX,
 109569            radialX);
 109570        Signed320 z0 = WideArithmetic.AddSigned320(
 109571            scaledZ,
 109572            radialZ);
 109573        Signed320 z1 = perpendicularZ;
 109574        Signed320 z2 = WideArithmetic.SubtractSigned320(
 109575            scaledZ,
 109576            radialZ);
 577
 109578        Signed320 axisY2 = WideArithmetic.MultiplySigned192(
 109579            axisY,
 109580            axisY);
 109581        GetSquaredPolynomial(
 109582            x0,
 109583            x1,
 109584            x2,
 109585            out Signed576 xSquared0,
 109586            out Signed576 xSquared1,
 109587            out Signed576 xSquared2,
 109588            out Signed576 xSquared3,
 109589            out Signed576 xSquared4);
 109590        GetSquaredPolynomial(
 109591            z0,
 109592            z1,
 109593            z2,
 109594            out Signed576 zSquared0,
 109595            out Signed576 zSquared1,
 109596            out Signed576 zSquared2,
 109597            out Signed576 zSquared3,
 109598            out Signed576 zSquared4);
 109599        Signed576 dot0 = WideArithmetic.AddSigned576(
 109600            WideArithmetic.MultiplySigned320(
 109601                x0,
 109602                Signed320.ExtendValue(axisX)),
 109603            WideArithmetic.MultiplySigned320(
 109604                z0,
 109605                Signed320.ExtendValue(axisZ)));
 109606        Signed576 dot1 = WideArithmetic.AddSigned576(
 109607            WideArithmetic.MultiplySigned320(
 109608                x1,
 109609                Signed320.ExtendValue(axisX)),
 109610            WideArithmetic.MultiplySigned320(
 109611                z1,
 109612                Signed320.ExtendValue(axisZ)));
 109613        Signed576 dot2 = WideArithmetic.AddSigned576(
 109614            WideArithmetic.MultiplySigned320(
 109615                x2,
 109616                Signed320.ExtendValue(axisX)),
 109617            WideArithmetic.MultiplySigned320(
 109618                z2,
 109619                Signed320.ExtendValue(axisZ)));
 620
 109621        Signed192 commonDenominator = coordinateDenominator;
 109622        if (radiusDenominator == 2)
 623        {
 16624            commonDenominator = WideArithmetic.AddSigned192(
 16625                commonDenominator,
 16626                commonDenominator);
 627        }
 109628        Signed320 diskRadiusSquared = WideArithmetic.MultiplySigned192(
 109629            Signed192.Raw(diskRadius),
 109630            Signed192.Raw(diskRadius));
 109631        Signed576 diskAndAxis = WideArithmetic.MultiplySigned320(
 109632            diskRadiusSquared,
 109633            axisY2);
 109634        Signed320 denominatorSquared =
 109635            WideArithmetic.MultiplySigned192(
 109636                commonDenominator,
 109637                commonDenominator);
 109638        Signed832 limit =
 109639            WideArithmetic.MultiplySigned576ToSigned832(
 109640                diskAndAxis,
 109641                denominatorSquared);
 642
 109643        constant = WideArithmetic.SubtractSigned832(
 109644            GetProjectedDiskConicCoefficient(
 109645                xSquared0,
 109646                zSquared0,
 109647                axisY2,
 109648                dot0,
 109649                dot0),
 109650            limit);
 109651        linear = WideArithmetic.AddSigned832(
 109652            GetProjectedDiskRadialCoefficient(
 109653                xSquared1,
 109654                zSquared1,
 109655                axisY2),
 109656            DoubleSigned832(
 109657                WideArithmetic.MultiplySigned576ToSigned832(
 109658                    dot0,
 109659                    dot1)));
 109660        quadratic = WideArithmetic.AddSigned832(
 109661            GetProjectedDiskConicCoefficient(
 109662                xSquared2,
 109663                zSquared2,
 109664                axisY2,
 109665                dot1,
 109666                dot1),
 109667            DoubleSigned832(
 109668                WideArithmetic.MultiplySigned576ToSigned832(
 109669                    dot0,
 109670                    dot2)));
 109671        quadratic = WideArithmetic.SubtractSigned832(
 109672            quadratic,
 109673            DoubleSigned832(limit));
 109674        cubic = WideArithmetic.AddSigned832(
 109675            GetProjectedDiskRadialCoefficient(
 109676                xSquared3,
 109677                zSquared3,
 109678                axisY2),
 109679            DoubleSigned832(
 109680                WideArithmetic.MultiplySigned576ToSigned832(
 109681                    dot1,
 109682                    dot2)));
 109683        quartic = WideArithmetic.SubtractSigned832(
 109684            GetProjectedDiskConicCoefficient(
 109685                xSquared4,
 109686                zSquared4,
 109687                axisY2,
 109688                dot2,
 109689                dot2),
 109690            limit);
 109691    }
 692
 693    private static Signed832 GetProjectedDiskConicCoefficient(
 694        Signed576 xSquared,
 695        Signed576 zSquared,
 696        Signed320 axisYSquared,
 697        Signed576 firstDot,
 698        Signed576 secondDot) =>
 327699        WideArithmetic.AddSigned832(
 327700            GetProjectedDiskRadialCoefficient(
 327701                xSquared,
 327702                zSquared,
 327703                axisYSquared),
 327704            WideArithmetic.MultiplySigned576ToSigned832(
 327705                firstDot,
 327706                secondDot));
 707
 708    private static Signed832 GetProjectedDiskRadialCoefficient(
 709        Signed576 xSquared,
 710        Signed576 zSquared,
 711        Signed320 axisYSquared) =>
 545712        WideArithmetic.MultiplySigned576ToSigned832(
 545713            WideArithmetic.AddSigned576(
 545714                xSquared,
 545715                zSquared),
 545716            axisYSquared);
 717
 718    private static void GetSquaredPolynomial(
 719        Signed320 constant,
 720        Signed320 linear,
 721        Signed320 quadratic,
 722        out Signed576 result0,
 723        out Signed576 result1,
 724        out Signed576 result2,
 725        out Signed576 result3,
 726        out Signed576 result4)
 727    {
 218728        result0 = WideArithmetic.MultiplySigned320(
 218729            constant,
 218730            constant);
 218731        result1 = WideArithmetic.AddSigned576(
 218732            WideArithmetic.MultiplySigned320(
 218733                constant,
 218734                linear),
 218735            WideArithmetic.MultiplySigned320(
 218736                constant,
 218737                linear));
 218738        result2 = WideArithmetic.AddSigned576(
 218739            WideArithmetic.MultiplySigned320(
 218740                linear,
 218741                linear),
 218742            WideArithmetic.AddSigned576(
 218743                WideArithmetic.MultiplySigned320(
 218744                    constant,
 218745                    quadratic),
 218746                WideArithmetic.MultiplySigned320(
 218747                    constant,
 218748                    quadratic)));
 218749        result3 = WideArithmetic.AddSigned576(
 218750            WideArithmetic.MultiplySigned320(
 218751                linear,
 218752                quadratic),
 218753            WideArithmetic.MultiplySigned320(
 218754                linear,
 218755                quadratic));
 218756        result4 = WideArithmetic.MultiplySigned320(
 218757            quadratic,
 218758            quadratic);
 218759    }
 760
 761    private static Signed320 MultiplyBySmall(
 762        Signed320 value,
 763        int multiplier)
 764    {
 654765        if (multiplier == 0)
 218766            return default;
 436767        Signed320 result = multiplier < 0
 436768            ? WideArithmetic.SubtractSigned320(default, value)
 436769            : value;
 436770        return multiplier is 2 or -2
 436771            ? WideArithmetic.AddSigned320(result, result)
 436772            : result;
 773    }
 774
 775    private static Signed832 DoubleSigned832(Signed832 value) =>
 436776        WideArithmetic.AddSigned832(value, value);
 777
 778    private static int EvaluateProjectedDiskConic(
 779        Signed320 relativeX,
 780        Signed320 relativeZ,
 781        Signed192 coordinateDenominator,
 782        Signed192 axisX,
 783        Signed192 axisY,
 784        Signed192 axisZ,
 785        Fixed64 diskRadius)
 786    {
 132787        Signed576 distanceSquared = WideArithmetic.AddSigned576(
 132788            WideArithmetic.MultiplySigned320(
 132789                relativeX,
 132790                relativeX),
 132791            WideArithmetic.MultiplySigned320(
 132792                relativeZ,
 132793                relativeZ));
 132794        Signed576 dot = WideArithmetic.AddSigned576(
 132795            WideArithmetic.MultiplySigned320(
 132796                relativeX,
 132797                Signed320.ExtendValue(axisX)),
 132798            WideArithmetic.MultiplySigned320(
 132799                relativeZ,
 132800                Signed320.ExtendValue(axisZ)));
 132801        Signed320 axisY2 = WideArithmetic.MultiplySigned192(
 132802            axisY,
 132803            axisY);
 132804        Signed832 left = WideArithmetic.AddSigned832(
 132805            WideArithmetic.MultiplySigned576ToSigned832(
 132806                distanceSquared,
 132807                axisY2),
 132808            WideArithmetic.MultiplySigned576ToSigned832(
 132809                dot,
 132810                dot));
 132811        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 132812            Signed192.Raw(diskRadius),
 132813            Signed192.Raw(diskRadius));
 132814        Signed576 radiusAndAxis = WideArithmetic.MultiplySigned320(
 132815            radiusSquared,
 132816            axisY2);
 132817        Signed320 denominatorSquared =
 132818            WideArithmetic.MultiplySigned192(
 132819                coordinateDenominator,
 132820                coordinateDenominator);
 132821        Signed832 right =
 132822            WideArithmetic.MultiplySigned576ToSigned832(
 132823                radiusAndAxis,
 132824                denominatorSquared);
 132825        return WideArithmetic.SubtractSigned832(left, right).Sign;
 826    }
 827}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WidePlanarProjection.Polygon.cs

#LineLine coverage
 1//=======================================================================
 2// WidePlanarProjection.Polygon.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/// Exact rational polygon projection and closest-feature reduction.
 14/// </content>
 15internal static partial class WidePlanarProjection
 16{
 17    private const int DistanceComparisonWordCount = 36;
 18
 19    internal static bool TryGetOrientedBoxRelation(
 20        Vector2d circleCenter,
 21        Fixed64 circleRadius,
 22        FixedOrientedBox box,
 23        out PlanarProjectionRelation relation)
 24    {
 525        WideRationalBasis3d basis = new(box.Orientation);
 526        Span<RationalPoint> corners = stackalloc RationalPoint[8];
 527        int index = 0;
 3028        for (int x = -1; x <= 1; x += 2)
 29        {
 6030            for (int y = -1; y <= 1; y += 2)
 31            {
 12032                for (int z = -1; z <= 1; z += 2)
 33                {
 4034                    corners[index++] = GetWorldPoint(
 4035                        box.Center,
 4036                        basis,
 4037                        new Vector3d(
 4038                            x * box.HalfExtents.X,
 4039                            y * box.HalfExtents.Y,
 4040                            z * box.HalfExtents.Z));
 41                }
 42            }
 43        }
 44
 545        Span<RationalPoint> hull = stackalloc RationalPoint[8];
 546        int count = BuildConvexHull(corners, hull);
 547        return TryGetConvexRelation(
 548            circleCenter,
 549            circleRadius,
 550            basis.Denominator,
 551            hull[..count],
 552            out relation);
 53    }
 54
 55    internal static bool TryGetTriangleRelation(
 56        Vector2d circleCenter,
 57        Fixed64 circleRadius,
 58        FixedTriangle triangle,
 59        Vector3d triangleOrigin,
 60        FixedQuaternion triangleRotation,
 61        out PlanarProjectionRelation relation)
 62    {
 563        WideRationalBasis3d basis = new(triangleRotation);
 564        Span<RationalPoint> vertices = stackalloc RationalPoint[3];
 565        vertices[0] = GetWorldPoint(
 566            triangleOrigin,
 567            basis,
 568            triangle.A);
 569        vertices[1] = GetWorldPoint(
 570            triangleOrigin,
 571            basis,
 572            triangle.B);
 573        vertices[2] = GetWorldPoint(
 574            triangleOrigin,
 575            basis,
 576            triangle.C);
 77
 578        if (ContainsPoint(
 579                circleCenter,
 580                basis.Denominator,
 581                vertices))
 82        {
 183            relation = PlanarProjectionRelation.Contained;
 184            return true;
 85        }
 86
 487        RationalDistance best = GetSegmentDistance(
 488            circleCenter,
 489            basis.Denominator,
 490            vertices[0],
 491            vertices[1]);
 492        KeepCloser(
 493            GetSegmentDistance(
 494                circleCenter,
 495                basis.Denominator,
 496                vertices[1],
 497                vertices[2]),
 498            ref best);
 499        KeepCloser(
 4100            GetSegmentDistance(
 4101                circleCenter,
 4102                basis.Denominator,
 4103                vertices[2],
 4104                vertices[0]),
 4105            ref best);
 4106        return TryCreateRelation(
 4107            best,
 4108            circleRadius,
 4109            out relation);
 110    }
 111
 112    private static bool TryGetConvexRelation(
 113        Vector2d circleCenter,
 114        Fixed64 circleRadius,
 115        Signed192 denominator,
 116        ReadOnlySpan<RationalPoint> vertices,
 117        out PlanarProjectionRelation relation)
 118    {
 6119        if (ContainsPoint(
 6120                circleCenter,
 6121                denominator,
 6122                vertices))
 123        {
 2124            relation = PlanarProjectionRelation.Contained;
 2125            return true;
 126        }
 127
 4128        RationalDistance best = GetSegmentDistance(
 4129            circleCenter,
 4130            denominator,
 4131            vertices[0],
 4132            vertices[1]);
 30133        for (int index = 1; index < vertices.Length; index++)
 134        {
 11135            KeepCloser(
 11136                GetSegmentDistance(
 11137                    circleCenter,
 11138                    denominator,
 11139                    vertices[index],
 11140                    vertices[
 11141                        index + 1 == vertices.Length
 11142                            ? 0
 11143                            : index + 1]),
 11144                ref best);
 145        }
 146
 4147        return TryCreateRelation(
 4148            best,
 4149            circleRadius,
 4150            out relation);
 151    }
 152
 153    private static bool TryCreateRelation(
 154        RationalDistance distance,
 155        Fixed64 circleRadius,
 156        out PlanarProjectionRelation relation)
 157    {
 9158        if (distance.SquaredDistance.IsZero)
 159        {
 1160            relation = PlanarProjectionRelation.Contained;
 1161            return true;
 162        }
 163
 8164        if (!TryGetDistance(
 8165                distance,
 8166                circleRadius,
 8167                out Fixed64 result))
 168        {
 2169            relation = default;
 2170            return false;
 171        }
 172
 6173        relation = new PlanarProjectionRelation(
 6174            result,
 6175            GetOffset(distance),
 6176            WideNormalization.GetNormalized(
 6177                distance.X,
 6178                distance.Z));
 6179        return true;
 180    }
 181
 182    private static bool ContainsPoint(
 183        Vector2d point,
 184        Signed192 denominator,
 185        ReadOnlySpan<RationalPoint> vertices)
 186    {
 11187        int winding = 0;
 11188        Signed320 pointX = WideArithmetic.MultiplySigned192(
 11189            Signed192.Raw(point.X),
 11190            denominator);
 11191        Signed320 pointZ = WideArithmetic.MultiplySigned192(
 11192            Signed192.Raw(point.Y),
 11193            denominator);
 78194        for (int index = 0; index < vertices.Length; index++)
 195        {
 34196            RationalPoint first = vertices[index];
 34197            RationalPoint second = vertices[
 34198                index + 1 == vertices.Length ? 0 : index + 1];
 34199            Signed576 cross = Cross(
 34200                WideArithmetic.SubtractSigned320(
 34201                    second.X,
 34202                    first.X),
 34203                WideArithmetic.SubtractSigned320(
 34204                    second.Z,
 34205                    first.Z),
 34206                WideArithmetic.SubtractSigned320(
 34207                    pointX,
 34208                    first.X),
 34209                WideArithmetic.SubtractSigned320(
 34210                    pointZ,
 34211                    first.Z));
 34212            int sign = cross.Sign;
 34213            if (sign == 0)
 214                continue;
 26215            if (winding == 0)
 9216                winding = sign;
 17217            else if (winding != sign)
 6218                return false;
 219        }
 220
 5221        return winding != 0;
 222    }
 223
 224    private static int BuildConvexHull(
 225        Span<RationalPoint> points,
 226        Span<RationalPoint> hull)
 227    {
 5228        SortAndDeduplicate(points, out int uniqueCount);
 5229        Span<RationalPoint> work =
 5230            stackalloc RationalPoint[16];
 5231        int count = 0;
 50232        for (int index = 0; index < uniqueCount; index++)
 233        {
 25234            while (count >= 2
 25235                   && GetTurn(
 25236                       work[count - 2],
 25237                       work[count - 1],
 25238                       points[index]) <= 0)
 239            {
 5240                count--;
 241            }
 20242            work[count++] = points[index];
 243        }
 244
 5245        int lowerCount = count;
 40246        for (int index = uniqueCount - 2; index >= 0; index--)
 247        {
 20248            while (count > lowerCount
 20249                   && GetTurn(
 20250                       work[count - 2],
 20251                       work[count - 1],
 20252                       points[index]) <= 0)
 253            {
 5254                count--;
 255            }
 15256            work[count++] = points[index];
 257        }
 258
 5259        count--;
 5260        work[..count].CopyTo(hull);
 5261        return count;
 262    }
 263
 264    private static void SortAndDeduplicate(
 265        Span<RationalPoint> points,
 266        out int count)
 267    {
 80268        for (int index = 1; index < points.Length; index++)
 269        {
 35270            RationalPoint value = points[index];
 35271            int destination = index;
 65272            while (destination > 0
 65273                   && ComparePoint(
 65274                       value,
 65275                       points[destination - 1]) < 0)
 276            {
 30277                points[destination] =
 30278                    points[destination - 1];
 30279                destination--;
 280            }
 35281            points[destination] = value;
 282        }
 283
 5284        count = 1;
 80285        for (int index = 1; index < points.Length; index++)
 286        {
 35287            if (ComparePoint(points[index], points[count - 1]) == 0)
 288                continue;
 15289            points[count++] = points[index];
 290        }
 5291    }
 292
 293    private static int ComparePoint(
 294        RationalPoint first,
 295        RationalPoint second)
 296    {
 97297        int comparison = WideArithmetic.SubtractSigned320(
 97298            first.X,
 97299            second.X).Sign;
 97300        return comparison != 0
 97301            ? comparison
 97302            : WideArithmetic.SubtractSigned320(
 97303                first.Z,
 97304                second.Z).Sign;
 305    }
 306
 307    private static int GetTurn(
 308        RationalPoint first,
 309        RationalPoint second,
 310        RationalPoint third) =>
 20311        Cross(
 20312            WideArithmetic.SubtractSigned320(
 20313                second.X,
 20314                first.X),
 20315            WideArithmetic.SubtractSigned320(
 20316                second.Z,
 20317                first.Z),
 20318            WideArithmetic.SubtractSigned320(
 20319                third.X,
 20320                second.X),
 20321            WideArithmetic.SubtractSigned320(
 20322                third.Z,
 20323                second.Z)).Sign;
 324
 325    private static Signed576 Cross(
 326        Signed320 firstX,
 327        Signed320 firstZ,
 328        Signed320 secondX,
 329        Signed320 secondZ) =>
 54330        WideArithmetic.SubtractSigned576(
 54331            WideArithmetic.MultiplySigned320(
 54332                firstX,
 54333                secondZ),
 54334            WideArithmetic.MultiplySigned320(
 54335                firstZ,
 54336                secondX));
 337
 338    private static void KeepCloser(
 339        RationalDistance candidate,
 340        ref RationalDistance best)
 341    {
 19342        if (CompareDistances(candidate, best) < 0)
 5343            best = candidate;
 19344    }
 345
 346    private static int CompareDistances(
 347        RationalDistance first,
 348        RationalDistance second)
 349    {
 19350        Signed832 firstDenominatorSquared =
 19351            WideArithmetic.MultiplySigned576ToSigned832(
 19352                first.Denominator,
 19353                first.Denominator);
 19354        Signed832 secondDenominatorSquared =
 19355            WideArithmetic.MultiplySigned576ToSigned832(
 19356                second.Denominator,
 19357                second.Denominator);
 19358        Span<ulong> firstSquaredMagnitude = stackalloc ulong[13];
 19359        Span<ulong> secondSquaredMagnitude = stackalloc ulong[13];
 19360        Span<ulong> firstDenominatorMagnitude = stackalloc ulong[13];
 19361        Span<ulong> secondDenominatorMagnitude = stackalloc ulong[13];
 19362        WideArithmetic.GetMagnitude(
 19363            first.SquaredDistance,
 19364            firstSquaredMagnitude);
 19365        WideArithmetic.GetMagnitude(
 19366            second.SquaredDistance,
 19367            secondSquaredMagnitude);
 19368        WideArithmetic.GetMagnitude(
 19369            firstDenominatorSquared,
 19370            firstDenominatorMagnitude);
 19371        WideArithmetic.GetMagnitude(
 19372            secondDenominatorSquared,
 19373            secondDenominatorMagnitude);
 19374        Span<ulong> left =
 19375            stackalloc ulong[DistanceComparisonWordCount];
 19376        Span<ulong> right =
 19377            stackalloc ulong[DistanceComparisonWordCount];
 19378        WideArithmetic.MultiplyMagnitudes(
 19379            firstSquaredMagnitude,
 19380            secondDenominatorMagnitude,
 19381            left);
 19382        WideArithmetic.MultiplyMagnitudes(
 19383            secondSquaredMagnitude,
 19384            firstDenominatorMagnitude,
 19385            right);
 19386        return WideArithmetic.CompareMagnitudeEqualLength(
 19387            left,
 19388            right);
 389    }
 390}

Methods/Properties

TryGetRotatedConeRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.PlanarProjectionRelation&)
GetProjectedConeCeilingDistance(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
FindProjectedConeCeilingDistance(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Int64,System.Int64)
GetProjectedConeClosestOffset(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&)
GetSegmentOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
KeepCloserOffset(FixedMathSharp.Vector2d,System.Boolean&,FixedMathSharp.Vector2d&)
CompareConeDistanceToRadius(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192,System.Int32)
GetConeProjectionData(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
IsPointInConeProjectionWedge(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
TryCompareConeTangentDistanceToRadius(FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192,System.Int32,System.Int32&)
CompareConeTangentSquaredDistance(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192,System.Int32)
CompareRationalDistanceToRadius(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,System.Int32)
.ctor(FixedMathSharp.Signed320,FixedMathSharp.Signed320)
.ctor(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
TryGetSphereRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.PlanarProjectionRelation&)
TryGetCenteredCapsuleRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.PlanarProjectionRelation&)
TryGetCenteredCylinderRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.PlanarProjectionRelation&)
TryGetCenteredConeRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.PlanarProjectionRelation&)
TryCreateRadiallyExpandedRelation(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.PlanarProjectionRelation&)
GetRotatedLocalAxis(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
GetLocalOffsetNumerator(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector3d)
GetWorldPoint(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d)
GetCenteredAxisEndpoints(FixedMathSharp.Vector3d,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Fixed64,FixedMathSharp.Signed192&,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint&,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint&)
GetCenteredBasisAxisEndpoints(FixedMathSharp.Vector3d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Signed192&,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint&,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint&)
TryGetRadialGap(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
GetPointDistance(FixedMathSharp.Vector2d,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint)
GetSegmentDistance(FixedMathSharp.Vector2d,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint)
GetSegmentDistance(FixedMathSharp.Vector2d,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,System.Int32&)
IsWithinRadius(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Fixed64)
TryGetDistance(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
CompareDistanceToRaw(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,System.Int64)
CompareDistanceToRaw(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192)
CompareDistanceToTwiceRaw(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,System.Int64)
CompareDistanceToTwiceRaw(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192)
GetOffset(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance)
GetHalfToEvenIncrement(System.Int32,System.Int64)
GetLargestPositiveMagnitude(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
TryGetProjectedDiskRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.PlanarProjectionRelation&)
GetProjectedDiskCeilingDistance(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
FindProjectedDiskCeilingDistance(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,System.Int64,System.Int64)
GetProjectedDiskClosestOffset(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&)
GetEllipseClosestOffset(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetEllipseConstraintCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetProjectedDiskSegmentEndpoints(FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint&,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint&)
CompareProjectedDiskDistanceToRadius(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,System.Int32)
CountProjectedDiskCircleRoots(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,System.Int32)
CreateProjectedDiskCirclePolynomial(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,System.Int32,System.Int32,System.Int32,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
GetProjectedDiskConicCoefficient(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
GetProjectedDiskRadialCoefficient(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed320)
GetSquaredPolynomial(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
MultiplyBySmall(FixedMathSharp.Signed320,System.Int32)
DoubleSigned832(FixedMathSharp.Signed832)
EvaluateProjectedDiskConic(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64)
TryGetOrientedBoxRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedOrientedBox,FixedMathSharp.Geometry.PlanarProjectionRelation&)
TryGetTriangleRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.PlanarProjectionRelation&)
TryGetConvexRelation(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint>,FixedMathSharp.Geometry.PlanarProjectionRelation&)
TryCreateRelation(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.PlanarProjectionRelation&)
ContainsPoint(FixedMathSharp.Vector2d,FixedMathSharp.Signed192,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint>)
BuildConvexHull(System.Span`1<FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint>,System.Span`1<FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint>)
SortAndDeduplicate(System.Span`1<FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint>,System.Int32&)
ComparePoint(FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint)
GetTurn(FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint,FixedMathSharp.Geometry.WidePlanarProjection/RationalPoint)
Cross(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
KeepCloser(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance&)
CompareDistances(FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance,FixedMathSharp.Geometry.WidePlanarProjection/RationalDistance)