< Summary

Information
Class: FixedMathSharp.Geometry.FixedConvex2dRelations
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Primitives/Relations/FixedConvex2dRelations.cs
Line coverage
100%
Covered lines: 617
Uncovered lines: 0
Coverable lines: 617
Total lines: 1085
Line coverage: 100%
Branch coverage
100%
Covered branches: 92
Total branches: 92
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Primitives/Relations/FixedConvex2dRelations.cs

#LineLine coverage
 1//=======================================================================
 2// FixedConvex2dRelations.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/// Provides exact relations for convex 2D shapes represented by canonical
 14/// origins, scalar rotations, and local vertex offsets.
 15/// </summary>
 16public static class FixedConvex2dRelations
 17{
 18    /// <summary>
 19    /// Returns whether boundary-ordered vertices form a strictly convex
 20    /// polygon in either winding direction.
 21    /// </summary>
 22    public static bool IsStrictlyConvex(
 23        ReadOnlySpan<Vector2d> convexVertexOffsets)
 24    {
 525        ValidateVertexOffsets(convexVertexOffsets);
 526        return WideConvex2dRelations.IsStrictlyConvex(convexVertexOffsets);
 27    }
 28
 29    /// <summary>
 30    /// Returns whether a world-space point lies inside or on a closed convex
 31    /// polygon represented by an origin and origin-relative vertices.
 32    /// </summary>
 33    public static bool ContainsPoint(
 34        Vector2d point,
 35        Vector2d convexOrigin,
 36        ReadOnlySpan<Vector2d> convexVertexOffsets)
 37    {
 1738        ValidateVertexOffsets(convexVertexOffsets);
 1739        return WideConvex2dRelations.ContainsPoint(
 1740            point,
 1741            Vector2d.Zero,
 1742            convexOrigin,
 1743            convexVertexOffsets);
 44    }
 45
 46    /// <summary>
 47    /// Returns whether a world-space point lies inside or on a rotated closed
 48    /// convex polygon represented by a frame and local vertex offsets.
 49    /// </summary>
 50    public static bool ContainsPoint(
 51        Vector2d point,
 52        Vector2d convexOrigin,
 53        Fixed64 convexRotation,
 54        ReadOnlySpan<Vector2d> convexVertexOffsets)
 55    {
 156        ValidateVertexOffsets(convexVertexOffsets);
 157        return WideConvex2dRelations.ContainsPoint(
 158            point,
 159            Vector2d.Zero,
 160            convexOrigin,
 161            convexRotation,
 162            convexVertexOffsets);
 63    }
 64
 65    /// <summary>
 66    /// Finds the polygon-relative closest point to a world-space point without
 67    /// materializing polygon vertices.
 68    /// </summary>
 69    public static Vector2d GetClosestPointOffset(
 70        Vector2d point,
 71        Vector2d convexOrigin,
 72        ReadOnlySpan<Vector2d> convexVertexOffsets)
 73    {
 2374        ValidateVertexOffsets(convexVertexOffsets);
 2375        return WideConvex2dRelations.GetClosestPointOffset(
 2376            point,
 2377            Vector2d.Zero,
 2378            convexOrigin,
 2379            convexVertexOffsets);
 80    }
 81
 82    /// <summary>
 83    /// Finds the closest point on a rotated polygon while retaining that point
 84    /// in the polygon's supplied local frame.
 85    /// </summary>
 86    public static FixedPointAnchor2d GetClosestPointAnchor(
 87        Vector2d point,
 88        Vector2d convexOrigin,
 89        Fixed64 convexRotation,
 90        ReadOnlySpan<Vector2d> convexVertexOffsets)
 91    {
 192        ValidateVertexOffsets(convexVertexOffsets);
 193        return new FixedPointAnchor2d(
 194            convexOrigin,
 195            convexRotation,
 196            WideConvex2dRelations.GetClosestPointOffset(
 197                point,
 198                Vector2d.Zero,
 199                convexOrigin,
 1100                convexRotation,
 1101                convexVertexOffsets));
 102    }
 103
 104    /// <summary>
 105    /// Returns the first authored polygon-relative vertex with the greatest
 106    /// exact projection along a direction.
 107    /// </summary>
 108    public static Vector2d GetSupportOffset(
 109        ReadOnlySpan<Vector2d> convexVertexOffsets,
 110        Vector2d direction)
 111    {
 2112        ValidateVertexOffsets(convexVertexOffsets);
 2113        return WideConvex2dRelations.GetSupportOffset(
 2114            convexVertexOffsets,
 2115            direction);
 116    }
 117
 118    /// <summary>
 119    /// Returns the first local vertex with the greatest exact world-space
 120    /// projection along a direction.
 121    /// </summary>
 122    public static FixedPointAnchor2d GetSupportAnchor(
 123        Vector2d convexOrigin,
 124        Fixed64 convexRotation,
 125        ReadOnlySpan<Vector2d> convexVertexOffsets,
 126        Vector2d direction)
 127    {
 1128        ValidateVertexOffsets(convexVertexOffsets);
 1129        return new FixedPointAnchor2d(
 1130            convexOrigin,
 1131            convexRotation,
 1132            WideConvex2dRelations.GetSupportOffset(
 1133                convexRotation,
 1134                convexVertexOffsets,
 1135                direction));
 136    }
 137
 138    /// <summary>
 139    /// Attempts to derive the area and centroid of a boundary-ordered convex
 140    /// polygon without narrowing cross products or weighted-coordinate sums.
 141    /// </summary>
 142    /// <remarks>
 143    /// Area is nonnegative and clamps to <see cref="Fixed64.MaxValue"/> when
 144    /// the conceptual value exceeds the scalar domain. The centroid uses one
 145    /// final round-half-to-even conversion per component.
 146    /// </remarks>
 147    /// <returns>
 148    /// <see langword="false"/> only when the polygon has exact zero signed
 149    /// area or its final centroid is outside the scalar domain.
 150    /// </returns>
 151    public static bool TryGetAreaAndCentroid(
 152        ReadOnlySpan<Vector2d> convexVertexOffsets,
 153        out Fixed64 area,
 154        out Vector2d centroid)
 155    {
 133156        ValidateVertexOffsets(convexVertexOffsets);
 133157        return WideConvex2dRelations.TryGetAreaAndCentroid(
 133158            convexVertexOffsets,
 133159            out area,
 133160            out centroid);
 161    }
 162
 163    /// <summary>
 164    /// Attempts to build up to two local-frame contact-anchor pairs between
 165    /// two rotated closed convex polygons.
 166    /// </summary>
 167    public static bool TryGetConvexContacts(
 168        Vector2d firstOrigin,
 169        Fixed64 firstRotation,
 170        ReadOnlySpan<Vector2d> firstVertexOffsets,
 171        Vector2d secondOrigin,
 172        Fixed64 secondRotation,
 173        ReadOnlySpan<Vector2d> secondVertexOffsets,
 174        Span<FixedPointAnchor2d> firstContacts,
 175        Span<FixedPointAnchor2d> secondContacts,
 176        out int contactCount,
 177        out Vector2d normal,
 178        out Fixed64 depth,
 179        out bool depthIsClamped)
 180    {
 18181        ValidateVertexOffsets(firstVertexOffsets);
 18182        ValidateVertexOffsets(secondVertexOffsets);
 18183        if (firstContacts.Length < 2)
 184        {
 1185            throw new ArgumentException(
 1186                "Contact output requires capacity for two anchors.",
 1187                nameof(firstContacts));
 188        }
 17189        if (secondContacts.Length < 2)
 190        {
 1191            throw new ArgumentException(
 1192                "Contact output requires capacity for two anchors.",
 1193                nameof(secondContacts));
 194        }
 195
 16196        Span<Vector2d> firstOffsets = stackalloc Vector2d[2];
 16197        Span<Vector2d> secondOffsets = stackalloc Vector2d[2];
 16198        if (!WideConvex2dRelations.TryGetContactOffsets(
 16199                firstOrigin,
 16200                firstRotation,
 16201                firstVertexOffsets,
 16202                secondOrigin,
 16203                secondRotation,
 16204                secondVertexOffsets,
 16205                firstOffsets,
 16206                secondOffsets,
 16207                out contactCount,
 16208                out normal,
 16209                out depth,
 16210                out depthIsClamped))
 211        {
 1212            return false;
 213        }
 214
 74215        for (int i = 0; i < contactCount; i++)
 216        {
 22217            firstContacts[i] = new FixedPointAnchor2d(
 22218                firstOrigin,
 22219                firstRotation,
 22220                firstOffsets[i]);
 22221            secondContacts[i] = new FixedPointAnchor2d(
 22222                secondOrigin,
 22223                secondRotation,
 22224                secondOffsets[i]);
 225        }
 15226        return true;
 227    }
 228
 229    /// <summary>
 230    /// Attempts to build a contact-anchor pair between a conceptual circle and
 231    /// a rotated closed convex polygon.
 232    /// </summary>
 233    /// <remarks>
 234    /// A circle's rotation does not change its geometry, but it defines the
 235    /// rigid local frame of the returned circle anchor.
 236    /// </remarks>
 237    public static bool TryGetCircleContact(
 238        Vector2d circleCenter,
 239        Fixed64 circleRotation,
 240        Fixed64 circleRadius,
 241        Vector2d convexOrigin,
 242        Fixed64 convexRotation,
 243        ReadOnlySpan<Vector2d> convexVertexOffsets,
 244        out FixedPointAnchor2d circleContact,
 245        out FixedPointAnchor2d convexContact,
 246        out Vector2d normal,
 247        out Fixed64 depth,
 248        out bool depthIsClamped)
 249    {
 13250        if (circleRadius < Fixed64.Zero)
 1251            throw new ArgumentOutOfRangeException(nameof(circleRadius));
 12252        ValidateVertexOffsets(convexVertexOffsets);
 253
 11254        Span<FixedPointAnchor2d> circleContacts =
 11255            stackalloc FixedPointAnchor2d[2];
 11256        Span<FixedPointAnchor2d> convexContacts =
 11257            stackalloc FixedPointAnchor2d[2];
 11258        if (!WideCenteredCapsule2dRelations.TryGetContacts(
 11259                circleCenter,
 11260                circleRotation,
 11261                Vector2d.Right,
 11262                Fixed64.Zero,
 11263                circleRadius,
 11264                convexOrigin,
 11265                convexRotation,
 11266                convexVertexOffsets,
 11267                circleContacts,
 11268                convexContacts,
 11269                out _,
 11270                out normal,
 11271                out depth,
 11272                out depthIsClamped))
 273        {
 4274            circleContact = default;
 4275            convexContact = default;
 4276            return false;
 277        }
 278
 7279        circleContact = circleContacts[0];
 7280        convexContact = convexContacts[0];
 7281        return true;
 282    }
 283
 284    private static void ValidateVertexOffsets(
 285        ReadOnlySpan<Vector2d> convexVertexOffsets)
 286    {
 269287        if (convexVertexOffsets.Length < 3)
 288        {
 1289            throw new ArgumentException(
 1290                "A convex polygon requires at least three vertex offsets.",
 1291                nameof(convexVertexOffsets));
 292        }
 268293    }
 294
 295    /// <summary>
 296    /// Finds the first distance where a finite directed segment reaches a
 297    /// closed convex polygon.
 298    /// </summary>
 299    public static bool TryGetSegmentFirstIntersectionDistance(
 300        Vector2d start,
 301        Vector2d direction,
 302        Fixed64 maximumDistance,
 303        Vector2d convexOrigin,
 304        ReadOnlySpan<Vector2d> convexVertexOffsets,
 305        out Fixed64 distance,
 306        out Vector2d normal,
 307        out Vector2d convexContactOffset)
 308    {
 2309        ValidateSweep(direction, maximumDistance);
 2310        ValidateVertexOffsets(convexVertexOffsets);
 2311        if (WideConvex2dRelations.ContainsPoint(
 2312                start,
 2313                Vector2d.Zero,
 2314                convexOrigin,
 2315                convexVertexOffsets))
 316        {
 1317            distance = Fixed64.Zero;
 1318            normal = -direction;
 1319            convexContactOffset =
 1320                WideConvex2dRelations.GetSweptPointTargetContactOffset(
 1321                start,
 1322                Vector2d.Zero,
 1323                Vector2d.Zero,
 1324                convexOrigin,
 1325                convexVertexOffsets,
 1326                normal);
 1327            return true;
 328        }
 329
 1330        return TryGetSweptCenteredCapsuleFirstDistanceCore(
 1331            start,
 1332            Vector2d.Right,
 1333            Fixed64.Zero,
 1334            Fixed64.Zero,
 1335            direction,
 1336            maximumDistance,
 1337            convexOrigin,
 1338            convexVertexOffsets,
 1339            out distance,
 1340            out normal,
 1341            out convexContactOffset);
 342    }
 343
 344    /// <summary>
 345    /// Finds the first distance where a finite directed segment reaches a
 346    /// rotated closed convex polygon.
 347    /// </summary>
 348    public static bool TryGetSegmentFirstIntersectionDistance(
 349        Vector2d start,
 350        Vector2d direction,
 351        Fixed64 maximumDistance,
 352        Vector2d convexOrigin,
 353        Fixed64 convexRotation,
 354        ReadOnlySpan<Vector2d> convexVertexOffsets,
 355        out Fixed64 distance,
 356        out Vector2d normal,
 357        out FixedPointAnchor2d convexContact)
 358    {
 3359        ValidateSweep(direction, maximumDistance);
 3360        ValidateVertexOffsets(convexVertexOffsets);
 361        Vector2d contactOffset;
 3362        if (WideConvex2dRelations.ContainsPoint(
 3363                start,
 3364                Vector2d.Zero,
 3365                convexOrigin,
 3366                convexRotation,
 3367                convexVertexOffsets))
 368        {
 1369            distance = Fixed64.Zero;
 1370            normal = -direction;
 1371            contactOffset =
 1372                WideConvex2dRelations.GetSweptPointTargetContactOffset(
 1373                    start,
 1374                    Vector2d.Zero,
 1375                    Vector2d.Zero,
 1376                    convexOrigin,
 1377                    convexRotation,
 1378                    convexVertexOffsets,
 1379                    normal);
 380        }
 2381        else if (!TryGetSweptCenteredCapsuleFirstDistanceCore(
 2382                     start,
 2383                     Vector2d.Right,
 2384                     Fixed64.Zero,
 2385                     Fixed64.Zero,
 2386                     direction,
 2387                     maximumDistance,
 2388                     convexOrigin,
 2389                     convexRotation,
 2390                     convexVertexOffsets,
 2391                     out distance,
 2392                     out normal,
 2393                     out contactOffset))
 394        {
 1395            convexContact = default;
 1396            return false;
 397        }
 398
 2399        convexContact = new FixedPointAnchor2d(
 2400            convexOrigin,
 2401            convexRotation,
 2402            contactOffset);
 2403        return true;
 404    }
 405
 406    /// <summary>
 407    /// Finds the first distance where a translated conceptual circle reaches a
 408    /// closed convex polygon.
 409    /// </summary>
 410    public static bool TryGetSweptCircleFirstDistance(
 411        Vector2d circleCenter,
 412        Fixed64 circleRadius,
 413        Vector2d direction,
 414        Fixed64 maximumDistance,
 415        Vector2d convexOrigin,
 416        ReadOnlySpan<Vector2d> convexVertexOffsets,
 417        out Fixed64 distance,
 418        out Vector2d normal,
 419        out Vector2d convexContactOffset)
 420    {
 4421        if (circleRadius < Fixed64.Zero)
 1422            throw new ArgumentOutOfRangeException(nameof(circleRadius));
 3423        ValidateSweep(direction, maximumDistance);
 3424        ValidateVertexOffsets(convexVertexOffsets);
 3425        if (TryGetCircleContact(
 3426                circleCenter,
 3427                Fixed64.Zero,
 3428                circleRadius,
 3429                convexOrigin,
 3430                Fixed64.Zero,
 3431                convexVertexOffsets,
 3432                out _,
 3433                out FixedPointAnchor2d initialContact,
 3434                out normal,
 3435                out _,
 3436                out _))
 437        {
 1438            distance = Fixed64.Zero;
 1439            convexContactOffset = initialContact.LocalPoint;
 1440            return true;
 441        }
 442
 2443        return TryGetSweptCenteredCapsuleFirstDistanceCore(
 2444            circleCenter,
 2445            Vector2d.Right,
 2446            Fixed64.Zero,
 2447            circleRadius,
 2448            direction,
 2449            maximumDistance,
 2450            convexOrigin,
 2451            convexVertexOffsets,
 2452            out distance,
 2453            out normal,
 2454            out convexContactOffset);
 455    }
 456
 457    /// <summary>
 458    /// Finds the first distance where a translated conceptual circle reaches
 459    /// a rotated closed convex polygon.
 460    /// </summary>
 461    public static bool TryGetSweptCircleFirstDistance(
 462        Vector2d circleCenter,
 463        Fixed64 circleRadius,
 464        Vector2d direction,
 465        Fixed64 maximumDistance,
 466        Vector2d convexOrigin,
 467        Fixed64 convexRotation,
 468        ReadOnlySpan<Vector2d> convexVertexOffsets,
 469        out Fixed64 distance,
 470        out Vector2d normal,
 471        out FixedPointAnchor2d convexContact)
 472    {
 4473        if (circleRadius < Fixed64.Zero)
 1474            throw new ArgumentOutOfRangeException(nameof(circleRadius));
 3475        ValidateSweep(direction, maximumDistance);
 3476        ValidateVertexOffsets(convexVertexOffsets);
 477        Vector2d contactOffset;
 3478        if (TryGetCircleContact(
 3479                circleCenter,
 3480                Fixed64.Zero,
 3481                circleRadius,
 3482                convexOrigin,
 3483                convexRotation,
 3484                convexVertexOffsets,
 3485                out _,
 3486                out FixedPointAnchor2d initialContact,
 3487                out normal,
 3488                out _,
 3489                out _))
 490        {
 1491            distance = Fixed64.Zero;
 1492            convexContact = initialContact;
 1493            return true;
 494        }
 2495        if (!TryGetSweptCenteredCapsuleFirstDistanceCore(
 2496                circleCenter,
 2497                Vector2d.Right,
 2498                Fixed64.Zero,
 2499                circleRadius,
 2500                direction,
 2501                maximumDistance,
 2502                convexOrigin,
 2503                convexRotation,
 2504                convexVertexOffsets,
 2505                out distance,
 2506                out normal,
 2507                out contactOffset))
 508        {
 1509            convexContact = default;
 1510            return false;
 511        }
 512
 1513        convexContact = new FixedPointAnchor2d(
 1514            convexOrigin,
 1515            convexRotation,
 1516            contactOffset);
 1517        return true;
 518    }
 519
 520    /// <summary>
 521    /// Finds the first distance where a translated centered rotated capsule
 522    /// reaches a rotated closed convex polygon.
 523    /// </summary>
 524    public static bool TryGetSweptCenteredCapsuleFirstDistance(
 525        Vector2d capsuleCenter,
 526        Fixed64 capsuleRotation,
 527        Fixed64 capsuleAxisLength,
 528        Fixed64 capsuleRadius,
 529        Vector2d direction,
 530        Fixed64 maximumDistance,
 531        Vector2d convexOrigin,
 532        Fixed64 convexRotation,
 533        ReadOnlySpan<Vector2d> convexVertexOffsets,
 534        out Fixed64 distance,
 535        out Vector2d normal,
 536        out FixedPointAnchor2d convexContact)
 537    {
 5538        if (capsuleAxisLength < Fixed64.Zero)
 1539            throw new ArgumentOutOfRangeException(nameof(capsuleAxisLength));
 4540        if (capsuleRadius < Fixed64.Zero)
 1541            throw new ArgumentOutOfRangeException(nameof(capsuleRadius));
 3542        ValidateSweep(direction, maximumDistance);
 3543        ValidateVertexOffsets(convexVertexOffsets);
 544
 3545        Span<FixedPointAnchor2d> capsuleContacts =
 3546            stackalloc FixedPointAnchor2d[2];
 3547        Span<FixedPointAnchor2d> convexContacts =
 3548            stackalloc FixedPointAnchor2d[2];
 3549        if (FixedSegment2d.TryGetCenteredCapsuleConvexContacts(
 3550                capsuleCenter,
 3551                capsuleRotation,
 3552                Vector2d.Forward,
 3553                capsuleAxisLength,
 3554                capsuleRadius,
 3555                convexOrigin,
 3556                convexRotation,
 3557                convexVertexOffsets,
 3558                capsuleContacts,
 3559                convexContacts,
 3560                out int contactCount,
 3561                out normal,
 3562                out _,
 3563                out _))
 564        {
 1565            distance = Fixed64.Zero;
 1566            convexContact = convexContacts[contactCount - 1];
 1567            return true;
 568        }
 569
 2570        Vector2d capsuleAxis = new(
 2571            -FixedMath.Sin(capsuleRotation),
 2572            FixedMath.Cos(capsuleRotation));
 2573        if (!TryGetSweptCenteredCapsuleFirstDistanceCore(
 2574                capsuleCenter,
 2575                capsuleAxis,
 2576                capsuleAxisLength,
 2577                capsuleRadius,
 2578                direction,
 2579                maximumDistance,
 2580                convexOrigin,
 2581                convexRotation,
 2582                convexVertexOffsets,
 2583                out distance,
 2584                out normal,
 2585                out Vector2d contactOffset))
 586        {
 1587            convexContact = default;
 1588            return false;
 589        }
 590
 1591        convexContact = new FixedPointAnchor2d(
 1592            convexOrigin,
 1593            convexRotation,
 1594            contactOffset);
 1595        return true;
 596    }
 597
 598    /// <summary>
 599    /// Finds the first distance where a translated conceptual centered
 600    /// capsule reaches a closed convex polygon.
 601    /// </summary>
 602    public static bool TryGetSweptCenteredCapsuleFirstDistance(
 603        Vector2d capsuleCenter,
 604        Vector2d capsuleAxisDirection,
 605        Fixed64 capsuleAxisLength,
 606        Fixed64 capsuleRadius,
 607        Vector2d direction,
 608        Fixed64 maximumDistance,
 609        Vector2d convexOrigin,
 610        ReadOnlySpan<Vector2d> convexVertexOffsets,
 611        out Fixed64 distance,
 612        out Vector2d normal,
 613        out Vector2d convexContactOffset)
 614    {
 5615        ValidateCenteredAxis(
 5616            capsuleAxisDirection,
 5617            capsuleAxisLength);
 3618        if (capsuleRadius < Fixed64.Zero)
 1619            throw new ArgumentOutOfRangeException(nameof(capsuleRadius));
 2620        ValidateSweep(direction, maximumDistance);
 2621        ValidateVertexOffsets(convexVertexOffsets);
 2622        Span<FixedPointAnchor2d> capsuleContacts =
 2623            stackalloc FixedPointAnchor2d[2];
 2624        Span<FixedPointAnchor2d> convexContacts =
 2625            stackalloc FixedPointAnchor2d[2];
 2626        if (WideCenteredCapsule2dRelations.TryGetContacts(
 2627                capsuleCenter,
 2628                Fixed64.Zero,
 2629                capsuleAxisDirection,
 2630                capsuleAxisLength,
 2631                capsuleRadius,
 2632                convexOrigin,
 2633                Fixed64.Zero,
 2634                convexVertexOffsets,
 2635                capsuleContacts,
 2636                convexContacts,
 2637                out int contactCount,
 2638                out normal,
 2639                out _,
 2640                out _))
 641        {
 1642            distance = Fixed64.Zero;
 1643            convexContactOffset =
 1644                convexContacts[contactCount - 1].LocalPoint;
 1645            return true;
 646        }
 647
 1648        return TryGetSweptCenteredCapsuleFirstDistanceCore(
 1649            capsuleCenter,
 1650            capsuleAxisDirection,
 1651            capsuleAxisLength,
 1652            capsuleRadius,
 1653            direction,
 1654            maximumDistance,
 1655            convexOrigin,
 1656            convexVertexOffsets,
 1657            out distance,
 1658            out normal,
 1659            out convexContactOffset);
 660    }
 661
 662    /// <summary>
 663    /// Finds the first distance where a translated conceptual centered capsule
 664    /// reaches a rotated closed convex polygon.
 665    /// </summary>
 666    public static bool TryGetSweptCenteredCapsuleFirstDistance(
 667        Vector2d capsuleCenter,
 668        Vector2d capsuleAxisDirection,
 669        Fixed64 capsuleAxisLength,
 670        Fixed64 capsuleRadius,
 671        Vector2d direction,
 672        Fixed64 maximumDistance,
 673        Vector2d convexOrigin,
 674        Fixed64 convexRotation,
 675        ReadOnlySpan<Vector2d> convexVertexOffsets,
 676        out Fixed64 distance,
 677        out Vector2d normal,
 678        out FixedPointAnchor2d convexContact)
 679    {
 7680        ValidateCenteredAxis(capsuleAxisDirection, capsuleAxisLength);
 7681        if (capsuleRadius < Fixed64.Zero)
 1682            throw new ArgumentOutOfRangeException(nameof(capsuleRadius));
 6683        ValidateSweep(direction, maximumDistance);
 6684        ValidateVertexOffsets(convexVertexOffsets);
 6685        Span<FixedPointAnchor2d> capsuleContacts =
 6686            stackalloc FixedPointAnchor2d[2];
 6687        Span<FixedPointAnchor2d> convexContacts =
 6688            stackalloc FixedPointAnchor2d[2];
 6689        if (WideCenteredCapsule2dRelations.TryGetContacts(
 6690                capsuleCenter,
 6691                Fixed64.Zero,
 6692                capsuleAxisDirection,
 6693                capsuleAxisLength,
 6694                capsuleRadius,
 6695                convexOrigin,
 6696                convexRotation,
 6697                convexVertexOffsets,
 6698                capsuleContacts,
 6699                convexContacts,
 6700                out int contactCount,
 6701                out normal,
 6702                out _,
 6703                out _))
 704        {
 2705            distance = Fixed64.Zero;
 2706            convexContact = convexContacts[contactCount - 1];
 2707            return true;
 708        }
 709
 4710        if (!TryGetSweptCenteredCapsuleFirstDistanceCore(
 4711                capsuleCenter,
 4712                capsuleAxisDirection,
 4713                capsuleAxisLength,
 4714                capsuleRadius,
 4715                direction,
 4716                maximumDistance,
 4717                convexOrigin,
 4718                convexRotation,
 4719                convexVertexOffsets,
 4720                out distance,
 4721                out normal,
 4722                out Vector2d contactOffset))
 723        {
 2724            convexContact = default;
 2725            return false;
 726        }
 727
 2728        convexContact = new FixedPointAnchor2d(
 2729            convexOrigin,
 2730            convexRotation,
 2731            contactOffset);
 2732        return true;
 733    }
 734
 735    /// <summary>
 736    /// Finds the first distance where a translated closed convex polygon
 737    /// reaches another closed convex polygon.
 738    /// </summary>
 739    public static bool TryGetSweptConvexFirstDistance(
 740        Vector2d moverOrigin,
 741        ReadOnlySpan<Vector2d> moverVertexOffsets,
 742        Vector2d direction,
 743        Fixed64 maximumDistance,
 744        Vector2d targetOrigin,
 745        ReadOnlySpan<Vector2d> targetVertexOffsets,
 746        out Fixed64 distance,
 747        out Vector2d normal,
 748        out Vector2d targetContactOffset) =>
 5749        TryGetSweptConvexFirstDistanceCore(
 5750            moverOrigin,
 5751            Fixed64.Zero,
 5752            moverVertexOffsets,
 5753            direction,
 5754            maximumDistance,
 5755            targetOrigin,
 5756            Fixed64.Zero,
 5757            targetVertexOffsets,
 5758            out distance,
 5759            out normal,
 5760            out targetContactOffset);
 761
 762    /// <summary>
 763    /// Finds the first distance where a translated rotated convex polygon
 764    /// reaches another rotated closed convex polygon.
 765    /// </summary>
 766    public static bool TryGetSweptConvexFirstDistance(
 767        Vector2d moverOrigin,
 768        Fixed64 moverRotation,
 769        ReadOnlySpan<Vector2d> moverVertexOffsets,
 770        Vector2d direction,
 771        Fixed64 maximumDistance,
 772        Vector2d targetOrigin,
 773        Fixed64 targetRotation,
 774        ReadOnlySpan<Vector2d> targetVertexOffsets,
 775        out Fixed64 distance,
 776        out Vector2d normal,
 777        out FixedPointAnchor2d targetContact)
 778    {
 3779        if (!TryGetSweptConvexFirstDistanceCore(
 3780                moverOrigin,
 3781                moverRotation,
 3782                moverVertexOffsets,
 3783                direction,
 3784                maximumDistance,
 3785                targetOrigin,
 3786                targetRotation,
 3787                targetVertexOffsets,
 3788                out distance,
 3789                out normal,
 3790                out Vector2d targetContactOffset))
 791        {
 1792            targetContact = default;
 1793            return false;
 794        }
 795
 2796        targetContact = new FixedPointAnchor2d(
 2797            targetOrigin,
 2798            targetRotation,
 2799            targetContactOffset);
 2800        return true;
 801    }
 802
 803    private static bool TryGetSweptConvexFirstDistanceCore(
 804        Vector2d moverOrigin,
 805        Fixed64 moverRotation,
 806        ReadOnlySpan<Vector2d> moverVertexOffsets,
 807        Vector2d direction,
 808        Fixed64 maximumDistance,
 809        Vector2d targetOrigin,
 810        Fixed64 targetRotation,
 811        ReadOnlySpan<Vector2d> targetVertexOffsets,
 812        out Fixed64 distance,
 813        out Vector2d normal,
 814        out Vector2d targetContactOffset)
 815    {
 8816        ValidateVertexOffsets(moverVertexOffsets);
 8817        ValidateVertexOffsets(targetVertexOffsets);
 8818        ValidateSweep(direction, maximumDistance);
 6819        Span<Vector2d> moverContacts = stackalloc Vector2d[2];
 6820        Span<Vector2d> targetContacts = stackalloc Vector2d[2];
 6821        if (WideConvex2dRelations.TryGetContactOffsets(
 6822                moverOrigin,
 6823                moverRotation,
 6824                moverVertexOffsets,
 6825                targetOrigin,
 6826                targetRotation,
 6827                targetVertexOffsets,
 6828                moverContacts,
 6829                targetContacts,
 6830                out int contactCount,
 6831                out normal,
 6832                out _,
 6833                out _))
 834        {
 2835            distance = Fixed64.Zero;
 2836            targetContactOffset = targetContacts[contactCount - 1];
 2837            return true;
 838        }
 839
 4840        bool found = false;
 4841        distance = default;
 4842        normal = default;
 4843        targetContactOffset = default;
 4844        for (int moverIndex = 0;
 20845            moverIndex < moverVertexOffsets.Length;
 16846            moverIndex++)
 847        {
 16848            Vector2d moverStart = moverVertexOffsets[moverIndex];
 16849            Vector2d moverEnd = moverVertexOffsets[
 16850                moverIndex + 1 == moverVertexOffsets.Length
 16851                    ? 0
 16852                    : moverIndex + 1];
 16853            for (int targetIndex = 0;
 80854                targetIndex < targetVertexOffsets.Length;
 64855                targetIndex++)
 856            {
 64857                Vector2d targetStart = targetVertexOffsets[targetIndex];
 64858                Vector2d targetEnd = targetVertexOffsets[
 64859                    targetIndex + 1 == targetVertexOffsets.Length
 64860                        ? 0
 64861                        : targetIndex + 1];
 64862                if (WideFiniteAxisIntersection
 64863                    .TryGetSweptOriginOffsetSegmentsFirstDistance(
 64864                        moverOrigin,
 64865                        moverRotation,
 64866                        moverStart,
 64867                        moverEnd,
 64868                        Fixed64.Zero,
 64869                        direction,
 64870                        maximumDistance,
 64871                        targetOrigin,
 64872                        targetRotation,
 64873                        targetStart,
 64874                        targetEnd,
 64875                        Fixed64.Zero,
 64876                        out Fixed64 candidateDistance,
 64877                        out Vector2d candidateNormal))
 878                {
 36879                    candidateNormal = OrientSweepNormal(
 36880                        candidateNormal,
 36881                        direction);
 36882                    Vector2d candidateTranslation =
 36883                        direction * candidateDistance;
 36884                    candidateNormal =
 36885                        WideConvex2dRelations.OrientTargetToSourceNormal(
 36886                            candidateNormal,
 36887                            moverOrigin,
 36888                            candidateTranslation,
 36889                            targetOrigin);
 36890                    if (!ShouldReplaceSweepCandidate(
 36891                            candidateDistance,
 36892                            candidateNormal,
 36893                            direction,
 36894                            found,
 36895                            distance,
 36896                            normal))
 897                    {
 898                        continue;
 899                    }
 6900                    found = true;
 6901                    distance = candidateDistance;
 6902                    normal = candidateNormal;
 903                }
 904            }
 905        }
 906
 4907        if (!found)
 1908            return false;
 909
 3910        targetContactOffset =
 3911            WideConvex2dRelations.GetSweptConvexTargetContactOffset(
 3912            moverOrigin,
 3913            moverRotation,
 3914            moverVertexOffsets,
 3915            direction * distance,
 3916            targetOrigin,
 3917            targetRotation,
 3918            targetVertexOffsets,
 3919            normal);
 3920        return true;
 921    }
 922
 923    private static bool TryGetSweptCenteredCapsuleFirstDistanceCore(
 924        Vector2d center,
 925        Vector2d axisDirection,
 926        Fixed64 axisLength,
 927        Fixed64 radius,
 928        Vector2d direction,
 929        Fixed64 maximumDistance,
 930        Vector2d convexOrigin,
 931        ReadOnlySpan<Vector2d> convexVertexOffsets,
 932        out Fixed64 distance,
 933        out Vector2d normal,
 934        out Vector2d convexContactOffset) =>
 4935        TryGetSweptCenteredCapsuleFirstDistanceCore(
 4936            center,
 4937            axisDirection,
 4938            axisLength,
 4939            radius,
 4940            direction,
 4941            maximumDistance,
 4942            convexOrigin,
 4943            Fixed64.Zero,
 4944            convexVertexOffsets,
 4945            out distance,
 4946            out normal,
 4947            out convexContactOffset);
 948
 949    private static bool TryGetSweptCenteredCapsuleFirstDistanceCore(
 950        Vector2d center,
 951        Vector2d axisDirection,
 952        Fixed64 axisLength,
 953        Fixed64 radius,
 954        Vector2d direction,
 955        Fixed64 maximumDistance,
 956        Vector2d convexOrigin,
 957        Fixed64 convexRotation,
 958        ReadOnlySpan<Vector2d> convexVertexOffsets,
 959        out Fixed64 distance,
 960        out Vector2d normal,
 961        out Vector2d convexContactOffset)
 962    {
 14963        bool found = false;
 14964        distance = default;
 14965        normal = default;
 14966        convexContactOffset = default;
 140967        for (int i = 0; i < convexVertexOffsets.Length; i++)
 968        {
 56969            Vector2d start = convexVertexOffsets[i];
 56970            Vector2d end = convexVertexOffsets[
 56971                i + 1 == convexVertexOffsets.Length ? 0 : i + 1];
 56972            if (WideFiniteAxisIntersection
 56973                .TryGetSweptCenteredCapsuleOriginOffsetSegmentFirstDistance(
 56974                    center,
 56975                    axisDirection,
 56976                    axisLength,
 56977                    radius,
 56978                    direction,
 56979                    maximumDistance,
 56980                    convexOrigin,
 56981                    convexRotation,
 56982                    start,
 56983                    end,
 56984                    Fixed64.Zero,
 56985                    out Fixed64 candidateDistance,
 56986                    out Vector2d candidateNormal))
 987            {
 25988                candidateNormal = OrientSweepNormal(
 25989                    candidateNormal,
 25990                    direction);
 25991                Vector2d candidateTranslation =
 25992                    direction * candidateDistance;
 25993                candidateNormal =
 25994                    WideConvex2dRelations.OrientTargetToSourceNormal(
 25995                        candidateNormal,
 25996                        center,
 25997                        candidateTranslation,
 25998                        convexOrigin);
 25999                if (!ShouldReplaceSweepCandidate(
 251000                        candidateDistance,
 251001                        candidateNormal,
 251002                        direction,
 251003                        found,
 251004                        distance,
 251005                        normal))
 1006                {
 1007                    continue;
 1008                }
 141009                found = true;
 141010                distance = candidateDistance;
 141011                normal = candidateNormal;
 1012            }
 1013        }
 1014
 141015        if (!found)
 51016            return false;
 1017
 91018        FixedPointAnchor2d sourceSupport =
 91019            WideFiniteAxisIntersection.GetCenteredCapsuleSupportAnchor(
 91020                center,
 91021                Fixed64.Zero,
 91022                axisDirection,
 91023                axisLength,
 91024                radius,
 91025                -normal);
 91026        convexContactOffset =
 91027            WideConvex2dRelations.GetSweptAnchorTargetContactOffset(
 91028            sourceSupport,
 91029            direction * distance,
 91030            convexOrigin,
 91031            convexRotation,
 91032            convexVertexOffsets,
 91033            normal);
 91034        return true;
 1035    }
 1036
 1037    private static bool ShouldReplaceSweepCandidate(
 1038        Fixed64 candidateDistance,
 1039        Vector2d candidateNormal,
 1040        Vector2d direction,
 1041        bool found,
 1042        Fixed64 bestDistance,
 1043        Vector2d bestNormal) =>
 611044        !found
 611045        || candidateDistance < bestDistance
 611046        || (candidateDistance == bestDistance
 611047            && Vector2d.Dot(candidateNormal, direction)
 611048                < Vector2d.Dot(bestNormal, direction));
 1049
 1050    private static Vector2d OrientSweepNormal(
 1051        Vector2d normal,
 1052        Vector2d direction) =>
 611053        Vector2d.Dot(normal, direction) > Fixed64.Zero
 611054            ? -normal
 611055            : normal;
 1056
 1057    private static void ValidateSweep(
 1058        Vector2d direction,
 1059        Fixed64 maximumDistance)
 1060    {
 301061        if (!direction.IsNormalized())
 11062            throw new ArgumentException(
 11063                "Sweep direction must be normalized.",
 11064                nameof(direction));
 291065        if (maximumDistance < Fixed64.Zero)
 1066        {
 11067            throw new ArgumentOutOfRangeException(
 11068                nameof(maximumDistance));
 1069        }
 281070    }
 1071
 1072    private static void ValidateCenteredAxis(
 1073        Vector2d axisDirection,
 1074        Fixed64 axisLength)
 1075    {
 121076        if (!axisDirection.IsNormalized())
 1077        {
 11078            throw new ArgumentException(
 11079                "Axis direction must be normalized.",
 11080                nameof(axisDirection));
 1081        }
 111082        if (axisLength < Fixed64.Zero)
 11083            throw new ArgumentOutOfRangeException(nameof(axisLength));
 101084    }
 1085}

Methods/Properties

IsStrictlyConvex(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
ContainsPoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
ContainsPoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetClosestPointOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetClosestPointAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetSupportOffset(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetSupportAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
TryGetAreaAndCentroid(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&)
TryGetConvexContacts(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Span`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,System.Span`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,System.Int32&,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&,System.Boolean&)
TryGetCircleContact(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&,System.Boolean&)
ValidateVertexOffsets(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
TryGetSegmentFirstIntersectionDistance(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryGetSegmentFirstIntersectionDistance(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetSweptCircleFirstDistance(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryGetSweptCircleFirstDistance(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetSweptCenteredCapsuleFirstDistance(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetSweptCenteredCapsuleFirstDistance(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryGetSweptCenteredCapsuleFirstDistance(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetSweptConvexFirstDistance(FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryGetSweptConvexFirstDistance(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetSweptConvexFirstDistanceCore(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryGetSweptCenteredCapsuleFirstDistanceCore(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryGetSweptCenteredCapsuleFirstDistanceCore(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
ShouldReplaceSweepCandidate(FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Boolean,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d)
OrientSweepNormal(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
ValidateSweep(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
ValidateCenteredAxis(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)