< Summary

Line coverage
100%
Covered lines: 814
Uncovered lines: 0
Coverable lines: 814
Total lines: 1398
Line coverage: 100%
Branch coverage
100%
Covered branches: 200
Total branches: 200
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: TryRaycastCompound(...)100%66100%
File 1: TrySweepCircleCompound(...)100%66100%
File 1: TrySweepMoverCompound(...)100%44100%
File 1: TrySweepMoverAgainstCompound(...)100%66100%
File 2: TrySweepCapsuleMover(...)100%88100%
File 2: TrySweepConvexMoverAgainstCapsule(...)100%44100%
File 2: TrySweepConvexMoverAgainstConvex(...)100%44100%
File 2: TryBuildCapsuleTargetSweepHit(...)100%22100%
File 3: TryOverlapCircle(...)100%1212100%
File 3: TryOverlapCircleCenteredCapsule(...)100%44100%
File 3: TryOverlapPolygon(...)100%11100%
File 3: ValidateAabbSize(...)100%22100%
File 3: ValidateConvexQueryPolygon(...)100%11100%
File 3: CalculateAverageCenter(...)100%11100%
File 3: TryRaycast(...)100%2020100%
File 3: TrySweepCircle(...)100%2222100%
File 3: TrySweepMoverShape(...)100%1818100%
File 3: TryRaycastCircle(...)100%22100%
File 3: TrySweepCircleCircle(...)100%22100%
File 3: TryRaycastCapsule(...)100%22100%
File 3: TrySweepCircleCapsule(...)100%44100%
File 3: TryOverlapCircleCompound(...)100%66100%
File 3: TryOverlapConvexArea(...)100%66100%
File 3: TryOverlapConvexAreaCompound(...)100%66100%
File 3: TryOverlapConvexAreaCircle(...)100%22100%
File 3: TryOverlapConvexAreaCapsule(...)100%22100%
File 3: TryOverlapConvexAreaConvex(...)100%22100%
File 3: TryBuildCenteredCapsuleAreaHit(...)100%22100%
File 3: GetCenteredCapsuleSurfaceAnchor(...)100%11100%
File 3: TryBuildConvexAreaHit(...)100%66100%
File 3: TryRaycastConvex(...)100%22100%
File 3: TrySweepCircleConvex(...)100%22100%
File 3: TrySweepConvexMoverAgainstCircle(...)100%44100%
File 4: TryOffsetPoint(...)100%22100%
File 4: ContainsPointExact(...)100%88100%
File 4: GetConvexVertexOffsets(...)100%44100%
File 4: TryKeepEarlierHit(...)100%22100%
File 4: TryKeepCloserHit(...)100%22100%
File 4: SegmentBoundsOverlap(...)100%66100%
File 4: SweepBoundsOverlap(...)100%66100%
File 4: ResolveQueryFallbackNormal(...)100%22100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/2D/QueryDetection2D.Compound.cs

#LineLine coverage
 1//=======================================================================
 2// QueryDetection2D.Compound.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using Gravitas.Colliders;
 10
 11namespace Gravitas.Queries;
 12
 13internal static partial class QueryDetection2D
 14{
 15    private static bool TryRaycastCompound(
 16        Vector2d start,
 17        Vector2d end,
 18        LSCompoundCollider2D compound,
 19        out Physics2DHit hit)
 20    {
 421        bool found = false;
 422        Physics2DHit best = default;
 23
 2624        for (int i = 0; i < compound.PartCount; i++)
 25        {
 926            LSCollider2D part = compound.GetPartCollider(i);
 927            if (!TryRaycast(start, end, part, out Physics2DHit candidate))
 28                continue;
 29
 630            TryKeepEarlierHit(candidate, ref found, ref best);
 31        }
 32
 433        if (!found)
 34        {
 135            hit = default;
 136            return false;
 37        }
 38
 339        hit = new Physics2DHit(compound, best.Anchor, best.Normal, best.Distance);
 340        return true;
 41    }
 42
 43    private static bool TrySweepCircleCompound(
 44        Vector2d start,
 45        Vector2d end,
 46        Fixed64 radius,
 47        LSCompoundCollider2D compound,
 48        out Physics2DHit hit)
 49    {
 750        bool found = false;
 751        Physics2DHit best = default;
 52
 3853        for (int i = 0; i < compound.PartCount; i++)
 54        {
 1255            LSCollider2D part = compound.GetPartCollider(i);
 1256            if (!TrySweepCircle(start, end, radius, part, out Physics2DHit candidate))
 57                continue;
 58
 959            TryKeepEarlierHit(candidate, ref found, ref best);
 60        }
 61
 762        if (!found)
 63        {
 164            hit = default;
 165            return false;
 66        }
 67
 668        hit = new Physics2DHit(compound, best.Anchor, best.Normal, best.Distance);
 669        return true;
 70    }
 71
 72    private static bool TrySweepMoverCompound(
 73        LSCompoundCollider2D mover,
 74        Vector2d displacement,
 75        LSCollider2D target,
 76        out Physics2DHit hit)
 77    {
 478        bool found = false;
 479        Physics2DHit best = default;
 80
 2281        for (int i = 0; i < mover.PartCount; i++)
 82        {
 783            LSCollider2D part = mover.GetPartCollider(i);
 784            if (!TrySweepMoverShape(part, displacement, target, out Physics2DHit candidate))
 85                continue;
 86
 287            TryKeepEarlierHit(candidate, ref found, ref best);
 88        }
 89
 490        hit = best;
 491        return found;
 92    }
 93
 94    private static bool TrySweepMoverAgainstCompound(
 95        LSCollider2D mover,
 96        Vector2d displacement,
 97        LSCompoundCollider2D target,
 98        out Physics2DHit hit)
 99    {
 3100        bool found = false;
 3101        Physics2DHit best = default;
 102
 18103        for (int i = 0; i < target.PartCount; i++)
 104        {
 6105            LSCollider2D part = target.GetPartCollider(i);
 6106            if (!TrySweepMoverShape(mover, displacement, part, out Physics2DHit candidate))
 107                continue;
 108
 4109            TryKeepCloserHit(candidate, ref found, ref best);
 110        }
 111
 3112        if (!found)
 113        {
 1114            hit = default;
 1115            return false;
 116        }
 117
 2118        hit = new Physics2DHit(target, best.Anchor, best.Normal, best.Distance);
 2119        return true;
 120    }
 121}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/2D/QueryDetection2D.ConvexSweeps.cs

#LineLine coverage
 1//=======================================================================
 2// QueryDetection2D.ConvexSweeps.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using FixedMathSharp.Geometry;
 10using Gravitas.Colliders;
 11using Gravitas.CollisionHandling;
 12using System;
 13
 14namespace Gravitas.Queries;
 15
 16internal static partial class QueryDetection2D
 17{
 18    private static bool TrySweepCapsuleMover(
 19        LSCapsuleCollider2D mover,
 20        Vector2d displacement,
 21        Fixed64 length,
 22        LSCollider2D target,
 23        out Physics2DHit hit)
 24    {
 23125        if (CollisionDetection2D.TryCollide(mover, target, out Contact2D overlap))
 26        {
 127            hit = new Physics2DHit(target, overlap.AnchorB, -overlap.Normal, Fixed64.Zero);
 128            return true;
 29        }
 30
 23031        Vector2d direction = displacement.Normalized;
 32
 23033        if (target is LSCircleCollider2D circle)
 34        {
 335            bool found = FixedSegment2d.TryGetSweptCenteredCapsuleSegmentFirstDistance(
 336                mover.Center,
 337                mover.Rotation,
 338                mover.AxisLength,
 339                mover.ScaledRadius,
 340                direction,
 341                length,
 342                new FixedSegment2d(circle.Center, circle.Center),
 343                circle.ScaledRadius,
 344                out Fixed64 distance,
 345                out Vector2d normal);
 346            return TryBuildCapsuleTargetSweepHit(
 347                mover,
 348                direction,
 349                target,
 350                circle.Center,
 351                circle.Rotation,
 352                Fixed64.Zero,
 353                circle.ScaledRadius,
 354                found,
 355                distance,
 356                normal,
 357                out hit);
 58        }
 59
 22760        if (target is LSCapsuleCollider2D targetCapsule)
 61        {
 562            bool found = FixedSegment2d.TryGetSweptCenteredCapsulesFirstDistance(
 563                mover.Center,
 564                mover.Rotation,
 565                mover.AxisLength,
 566                mover.ScaledRadius,
 567                direction,
 568                length,
 569                targetCapsule.Center,
 570                targetCapsule.Rotation,
 571                targetCapsule.AxisLength,
 572                targetCapsule.ScaledRadius,
 573                out Fixed64 distance,
 574                out Vector2d normal);
 575            return TryBuildCapsuleTargetSweepHit(
 576                mover,
 577                direction,
 578                target,
 579                targetCapsule.Center,
 580                targetCapsule.Rotation,
 581                targetCapsule.AxisLength,
 582                targetCapsule.ScaledRadius,
 583                found,
 584                distance,
 585                normal,
 586                out hit);
 87        }
 88
 22289        Span<Vector2d> scratch = stackalloc Vector2d[4];
 22290        ReadOnlySpan<Vector2d> targetOffsets =
 22291            GetConvexVertexOffsets(target, scratch);
 22292        if (!FixedConvex2dRelations.TryGetSweptCenteredCapsuleFirstDistance(
 22293                mover.Center,
 22294                mover.Rotation,
 22295                mover.AxisLength,
 22296                mover.ScaledRadius,
 22297                direction,
 22298                length,
 22299                target.Center,
 222100                target.ConvexRotation,
 222101                targetOffsets,
 222102                out Fixed64 convexDistance,
 222103                out Vector2d convexNormal,
 222104                out FixedPointAnchor2d targetContact))
 105        {
 5106            hit = default;
 5107            return false;
 108        }
 109
 217110        hit = new Physics2DHit(
 217111            target,
 217112            new ContactAnchor2D(targetContact),
 217113            convexNormal,
 217114            convexDistance);
 217115        return true;
 116    }
 117
 118    private static bool TrySweepConvexMoverAgainstCapsule(
 119        LSCollider2D mover,
 120        Vector2d displacement,
 121        Fixed64 displacementLength,
 122        LSCapsuleCollider2D target,
 123        out Physics2DHit hit)
 124    {
 3125        if (CollisionDetection2D.TryCollide(mover, target, out Contact2D overlap))
 126        {
 1127            hit = new Physics2DHit(target, overlap.AnchorB, -overlap.Normal, Fixed64.Zero);
 1128            return true;
 129        }
 130
 2131        if (!TrySweepCapsuleMover(
 2132                target,
 2133                -displacement,
 2134                displacementLength,
 2135                mover,
 2136                out Physics2DHit reverseHit))
 137        {
 1138            hit = default;
 1139            return false;
 140        }
 141
 1142        Vector2d reverseDirection = -displacement / displacementLength;
 143        // A reported first hit lies between the admitted start center and the
 144        // in-domain target feature, so the impact center is representable.
 1145        _ = TryOffsetPoint(
 1146            target.Center,
 1147            reverseDirection,
 1148            reverseHit.Distance,
 1149            out Vector2d movedCapsuleCenter);
 150
 1151        Span<Vector2d> moverScratch = stackalloc Vector2d[4];
 1152        ReadOnlySpan<Vector2d> moverOffsets =
 1153            GetConvexVertexOffsets(mover, moverScratch);
 1154        Span<FixedPointAnchor2d> capsuleContacts =
 1155            stackalloc FixedPointAnchor2d[2];
 1156        Span<FixedPointAnchor2d> convexContacts =
 1157            stackalloc FixedPointAnchor2d[2];
 1158        _ = FixedSegment2d.TryGetCenteredCapsuleConvexContacts(
 1159            movedCapsuleCenter,
 1160            target.Rotation,
 1161            Vector2d.Forward,
 1162            target.AxisLength,
 1163            target.ScaledRadius,
 1164            mover.Center,
 1165            mover.ConvexRotation,
 1166            moverOffsets,
 1167            capsuleContacts,
 1168            convexContacts,
 1169            out int contactCount,
 1170            out Vector2d normal,
 1171            out _,
 1172            out _);
 173
 1174        hit = new Physics2DHit(
 1175            target,
 1176            new ContactAnchor2D(
 1177                target.Center,
 1178                capsuleContacts[contactCount - 1].Rotation,
 1179                capsuleContacts[contactCount - 1].LocalPoint,
 1180                capsuleContacts[contactCount - 1].LocalDisplacement),
 1181            normal,
 1182            reverseHit.Distance);
 1183        return true;
 184    }
 185
 186    private static bool TrySweepConvexMoverAgainstConvex(
 187        LSCollider2D mover,
 188        Vector2d displacement,
 189        Fixed64 segmentLength,
 190        LSCollider2D target,
 191        out Physics2DHit hit)
 192    {
 14193        if (CollisionDetection2D.TryCollide(mover, target, out Contact2D overlap))
 194        {
 2195            hit = new Physics2DHit(target, overlap.AnchorB, -overlap.Normal, Fixed64.Zero);
 2196            return true;
 197        }
 198
 12199        Vector2d direction = displacement.Normalized;
 12200        Span<Vector2d> moverScratch = stackalloc Vector2d[4];
 12201        Span<Vector2d> targetScratch = stackalloc Vector2d[4];
 12202        ReadOnlySpan<Vector2d> moverOffsets =
 12203            GetConvexVertexOffsets(mover, moverScratch);
 12204        ReadOnlySpan<Vector2d> targetOffsets =
 12205            GetConvexVertexOffsets(target, targetScratch);
 12206        if (!FixedConvex2dRelations.TryGetSweptConvexFirstDistance(
 12207                mover.Center,
 12208                mover.ConvexRotation,
 12209                moverOffsets,
 12210                direction,
 12211                segmentLength,
 12212                target.Center,
 12213                target.ConvexRotation,
 12214                targetOffsets,
 12215                out Fixed64 distance,
 12216                out Vector2d normal,
 12217                out FixedPointAnchor2d targetContact))
 218        {
 8219            hit = default;
 8220            return false;
 221        }
 222
 4223        hit = new Physics2DHit(
 4224            target,
 4225            new ContactAnchor2D(targetContact),
 4226            normal,
 4227            distance);
 4228        return true;
 229    }
 230
 231    private static bool TryBuildCapsuleTargetSweepHit(
 232        LSCapsuleCollider2D mover,
 233        Vector2d direction,
 234        LSCollider2D target,
 235        Vector2d targetCenter,
 236        Fixed64 targetRotation,
 237        Fixed64 targetAxisLength,
 238        Fixed64 targetRadius,
 239        bool found,
 240        Fixed64 distance,
 241        Vector2d moverToTargetNormal,
 242        out Physics2DHit hit)
 243    {
 8244        if (!found)
 245        {
 1246            hit = default;
 1247            return false;
 248        }
 249
 250        // The swept-capsule solver only reports a first distance whose impact
 251        // center and exact contact are representable in the admitted frames.
 7252        _ = TryOffsetPoint(
 7253            mover.Center,
 7254            direction,
 7255            distance,
 7256            out Vector2d movedCenter);
 7257        _ = FixedSegment2d.TryGetCenteredCapsulesContact(
 7258            movedCenter,
 7259            mover.Rotation,
 7260            mover.AxisLength,
 7261            mover.ScaledRadius,
 7262            targetCenter,
 7263            targetRotation,
 7264            targetAxisLength,
 7265            targetRadius,
 7266            moverToTargetNormal,
 7267            out FixedContactAnchors2d contact);
 268
 7269        hit = new Physics2DHit(
 7270            target,
 7271            new ContactAnchor2D(contact.SecondAnchor),
 7272            -contact.Normal,
 7273            distance);
 7274        return true;
 275    }
 276}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/2D/QueryDetection2D.cs

#LineLine coverage
 1//=======================================================================
 2// QueryDetection2D.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using FixedMathSharp.Geometry;
 10using Gravitas.Colliders;
 11using Gravitas.CollisionHandling;
 12using System;
 13
 14namespace Gravitas.Queries;
 15
 16/// <summary>
 17/// Deterministic pure 2D shape checks used by query services.
 18/// </summary>
 19internal static partial class QueryDetection2D
 20{
 21    internal static bool TryOverlapCircle(
 22        Vector2d center,
 23        Fixed64 radius,
 24        LSCollider2D collider,
 25        out Physics2DHit hit)
 26    {
 2251027        SwiftThrowHelper.ThrowIfArgument(radius < Fixed64.Zero, nameof(radius), "2D query radius cannot be negative.");
 28
 2251029        if (collider is LSCompoundCollider2D compound)
 430            return TryOverlapCircleCompound(center, radius, compound, out hit);
 2250631        if (collider is LSCircleCollider2D circle)
 2174332            return TryOverlapCircleCenteredCapsule(
 2174333                center,
 2174334                radius,
 2174335                circle.Center,
 2174336                circle.Rotation,
 2174337                Fixed64.Zero,
 2174338                circle.ScaledRadius,
 2174339                circle,
 2174340                out hit);
 76341        if (collider is LSCapsuleCollider2D capsule)
 37342            return TryOverlapCircleCenteredCapsule(
 37343                center,
 37344                radius,
 37345                capsule.Center,
 37346                capsule.Rotation,
 37347                capsule.AxisLength,
 37348                capsule.ScaledRadius,
 37349                capsule,
 37350                out hit);
 39051        if (collider is not IConvexVertexSource2D)
 52        {
 253            hit = default;
 254            return false;
 55        }
 56
 38857        Span<Vector2d> scratch = stackalloc Vector2d[4];
 38858        ReadOnlySpan<Vector2d> vertexOffsets =
 38859            GetConvexVertexOffsets(collider, scratch);
 38860        if (!FixedConvex2dRelations.TryGetCircleContact(
 38861                center,
 38862                Fixed64.Zero,
 38863                radius,
 38864                collider.Center,
 38865                collider.ConvexRotation,
 38866                vertexOffsets,
 38867                out _,
 38868                out FixedPointAnchor2d contactAnchor,
 38869                out Vector2d circleToColliderNormal,
 38870                out Fixed64 depth,
 38871                out _))
 72        {
 21273            hit = default;
 21274            return false;
 75        }
 76
 17677        bool containsCenter = FixedConvex2dRelations.ContainsPoint(
 17678            center,
 17679            collider.Center,
 17680            collider.ConvexRotation,
 17681            vertexOffsets);
 17682        Fixed64 distance = Fixed64.Zero;
 17683        Vector2d normal = -circleToColliderNormal;
 17684        if (!containsCenter)
 16885            distance = radius - depth;
 86
 17687        hit = new Physics2DHit(
 17688            collider,
 17689            new ContactAnchor2D(contactAnchor),
 17690            normal,
 17691            distance);
 17692        return true;
 93    }
 94
 95    private static bool TryOverlapCircleCenteredCapsule(
 96        Vector2d queryCenter,
 97        Fixed64 queryRadius,
 98        Vector2d targetCenter,
 99        Fixed64 targetRotation,
 100        Fixed64 targetAxisLength,
 101        Fixed64 targetRadius,
 102        LSCollider2D target,
 103        out Physics2DHit hit)
 104    {
 22116105        if (!FixedSegment2d.TryGetCenteredCapsulesContact(
 22116106                queryCenter,
 22116107                Fixed64.Zero,
 22116108                Fixed64.Zero,
 22116109                queryRadius,
 22116110                targetCenter,
 22116111                targetRotation,
 22116112                targetAxisLength,
 22116113                targetRadius,
 22116114                ResolveQueryFallbackNormal(queryCenter, targetCenter),
 22116115                out FixedContactAnchors2d contact))
 116        {
 7365117            hit = default;
 7365118            return false;
 119        }
 120
 14751121        Fixed64 distance = FixedSegment2d.GetDistanceToCenteredCapsule(
 14751122            queryCenter,
 14751123            targetCenter,
 14751124            targetRotation,
 14751125            targetAxisLength,
 14751126            targetRadius);
 127
 14751128        hit = new Physics2DHit(
 14751129            target,
 14751130            new ContactAnchor2D(contact.SecondAnchor),
 14751131            queryCenter == targetCenter
 14751132                ? ResolveQueryFallbackNormal(queryCenter, targetCenter)
 14751133                : -contact.Normal,
 14751134            distance);
 14751135        return true;
 136    }
 137
 138    internal static bool TryOverlapPolygon(
 139        ReadOnlySpan<Vector2d> vertices,
 140        Vector2d center,
 141        LSCollider2D collider,
 142        out Physics2DHit hit)
 143    {
 7801144        return TryOverlapConvexArea(center, vertices, collider, out hit);
 145    }
 146
 147    internal static void ValidateAabbSize(Vector2d size)
 148    {
 1687149        SwiftThrowHelper.ThrowIfArgument(
 1687150            size.X <= Fixed64.Zero || size.Y <= Fixed64.Zero,
 1687151            nameof(size),
 1687152            "2D AABB query size components must be greater than zero.");
 1685153    }
 154
 155    internal static void ValidateConvexQueryPolygon(ReadOnlySpan<Vector2d> vertices)
 156    {
 17157        SwiftThrowHelper.ThrowIfArgument(vertices.Length < 3, nameof(vertices), "2D polygon query must contain at least 
 17158        SwiftThrowHelper.ThrowIfArgument(
 17159            !FixedConvex2dRelations.IsStrictlyConvex(vertices),
 17160            nameof(vertices),
 17161            "2D polygon query vertices must form a strictly convex boundary.");
 17162    }
 163
 164    internal static Vector2d CalculateAverageCenter(ReadOnlySpan<Vector2d> vertices) =>
 13165        Vector2d.GetAverage(vertices);
 166
 167    internal static bool TryRaycast(Vector2d start, Vector2d end, LSCollider2D collider, out Physics2DHit hit)
 168    {
 14208169        if (!Vector2d.TrySubtract(end, start, out Vector2d segment))
 170        {
 1171            hit = default;
 1172            return false;
 173        }
 174
 14207175        if (segment == Vector2d.Zero || !SegmentBoundsOverlap(start, end, collider))
 176        {
 31177            hit = default;
 31178            return false;
 179        }
 180
 14176181        if (!Vector2d.TryGetMagnitude(segment, out Fixed64 segmentLength))
 182        {
 1183            hit = default;
 1184            return false;
 185        }
 186
 14175187        if (collider is LSCompoundCollider2D compound)
 4188            return TryRaycastCompound(start, end, compound, out hit);
 189
 14171190        if (ContainsPointExact(collider, start))
 191        {
 15192            hit = new Physics2DHit(
 15193                collider,
 15194                start,
 15195                ResolveQueryFallbackNormal(start, collider.Center),
 15196                Fixed64.Zero);
 15197            return true;
 198        }
 199
 14156200        if (collider is LSCircleCollider2D circle)
 13595201            return TryRaycastCircle(start, end, segmentLength, circle, out hit);
 561202        if (collider is LSCapsuleCollider2D capsule)
 271203            return TryRaycastCapsule(start, end, segmentLength, capsule, out hit);
 290204        if (collider is not LSAABBoxCollider2D
 290205            && collider is not LSPolygonCollider2D)
 206        {
 4207            hit = default;
 4208            return false;
 209        }
 210
 286211        Vector2d direction = segment.Normalized;
 286212        return TryRaycastConvex(start, direction, segmentLength, collider, out hit);
 213    }
 214
 215    internal static bool TrySweepCircle(
 216        Vector2d start,
 217        Vector2d end,
 218        Fixed64 radius,
 219        LSCollider2D collider,
 220        out Physics2DHit hit)
 221    {
 8274222        if (!Vector2d.TrySubtract(end, start, out Vector2d segment))
 223        {
 1224            hit = default;
 1225            return false;
 226        }
 227
 8273228        if (segment == Vector2d.Zero || !SweepBoundsOverlap(start, end, radius, collider))
 229        {
 76230            hit = default;
 76231            return false;
 232        }
 233
 8197234        if (!Vector2d.TryGetMagnitude(segment, out Fixed64 segmentLength)
 8197235            || segmentLength <= Fixed64.Epsilon)
 236        {
 3237            hit = default;
 3238            return false;
 239        }
 240
 8194241        if (collider is LSCompoundCollider2D compound)
 7242            return TrySweepCircleCompound(start, end, radius, compound, out hit);
 243
 8187244        if (TryOverlapCircle(start, radius, collider, out Physics2DHit overlapHit))
 245        {
 613246            hit = new Physics2DHit(collider, start, overlapHit.Normal, Fixed64.Zero);
 613247            return true;
 248        }
 249
 7574250        if (collider is LSCircleCollider2D circle)
 7094251            return TrySweepCircleCircle(start, end, segmentLength, radius, circle, out hit);
 480252        if (collider is LSCapsuleCollider2D capsule)
 268253            return TrySweepCircleCapsule(start, end, segmentLength, radius, capsule, out hit);
 212254        if (collider is not LSAABBoxCollider2D
 212255            && collider is not LSPolygonCollider2D)
 256        {
 1257            hit = default;
 1258            return false;
 259        }
 260
 211261        Vector2d direction = segment.Normalized;
 211262        return TrySweepCircleConvex(start, direction, segmentLength, radius, collider, out hit);
 263    }
 264
 265    internal static bool TrySweepMoverShape(
 266        LSCollider2D mover,
 267        Vector2d displacement,
 268        LSCollider2D target,
 269        out Physics2DHit hit)
 270    {
 477271        SwiftThrowHelper.ThrowIfNull(mover, nameof(mover));
 477272        SwiftThrowHelper.ThrowIfNull(target, nameof(target));
 273
 477274        if (!Vector2d.TryGetMagnitude(displacement, out Fixed64 displacementLength)
 477275            || displacementLength <= Fixed64.Epsilon)
 276        {
 2277            hit = default;
 2278            return false;
 279        }
 280
 475281        if (mover is LSCompoundCollider2D moverCompound)
 4282            return TrySweepMoverCompound(moverCompound, displacement, target, out hit);
 283
 471284        if (target is LSCompoundCollider2D targetCompound)
 3285            return TrySweepMoverAgainstCompound(mover, displacement, targetCompound, out hit);
 286
 468287        if (mover is LSCircleCollider2D circle)
 288        {
 182289            if (!Vector2d.TryAdd(
 182290                    circle.Center,
 182291                    displacement,
 182292                    out Vector2d end))
 293            {
 1294                hit = default;
 1295                return false;
 296            }
 297
 181298            return TrySweepCircle(
 181299                circle.Center,
 181300                end,
 181301                circle.ScaledRadius,
 181302                target,
 181303                out hit);
 304        }
 286305        if (mover is LSCapsuleCollider2D moverCapsule)
 229306            return TrySweepCapsuleMover(
 229307                moverCapsule,
 229308                displacement,
 229309                displacementLength,
 229310                target,
 229311                out hit);
 312
 57313        if (target is LSCircleCollider2D targetCircle)
 40314            return TrySweepConvexMoverAgainstCircle(mover, displacement, targetCircle, out hit);
 17315        if (target is LSCapsuleCollider2D targetCapsule)
 3316            return TrySweepConvexMoverAgainstCapsule(
 3317                mover,
 3318                displacement,
 3319                displacementLength,
 3320                targetCapsule,
 3321                out hit);
 322
 14323        return TrySweepConvexMoverAgainstConvex(
 14324            mover,
 14325            displacement,
 14326            displacementLength,
 14327            target,
 14328            out hit);
 329    }
 330
 331    private static bool TryRaycastCircle(
 332        Vector2d start,
 333        Vector2d end,
 334        Fixed64 segmentLength,
 335        LSCircleCollider2D circle,
 336        out Physics2DHit hit)
 337    {
 13595338        var query = new FixedSegment2d(start, end);
 13595339        if (!query.TryGetCircleIntersectionDistanceInterval(
 13595340                new FixedBoundCircle(circle.Center, circle.ScaledRadius),
 13595341                segmentLength,
 13595342                out Fixed64 distance,
 13595343                out _))
 344        {
 5345            hit = default;
 5346            return false;
 347        }
 348
 13590349        Vector2d point = query.GetPointAtDistance(distance, segmentLength);
 13590350        Vector2d normal = Vector2d.GetDirection(circle.Center, point);
 13590351        hit = new Physics2DHit(
 13590352            circle,
 13590353            new ContactAnchor2D(
 13590354                circle.Center,
 13590355                normal * circle.ScaledRadius),
 13590356            normal,
 13590357            distance);
 13590358        return true;
 359    }
 360
 361    private static bool TrySweepCircleCircle(
 362        Vector2d start,
 363        Vector2d end,
 364        Fixed64 segmentLength,
 365        Fixed64 radius,
 366        LSCircleCollider2D circle,
 367        out Physics2DHit hit)
 368    {
 7094369        var query = new FixedSegment2d(start, end);
 7094370        if (!query.TryGetCircleIntersectionDistanceInterval(
 7094371                new FixedBoundCircle(circle.Center, circle.ScaledRadius),
 7094372                radius,
 7094373                segmentLength,
 7094374                out Fixed64 distance,
 7094375                out _,
 7094376                out _,
 7094377                out _))
 378        {
 13379            hit = default;
 13380            return false;
 381        }
 382
 7081383        Vector2d sweptCenter = query.GetPointAtDistance(distance, segmentLength);
 7081384        Vector2d normal = Vector2d.GetDirection(circle.Center, sweptCenter);
 7081385        hit = new Physics2DHit(
 7081386            circle,
 7081387            new ContactAnchor2D(
 7081388                circle.Center,
 7081389                normal * circle.ScaledRadius),
 7081390            normal,
 7081391            distance);
 7081392        return true;
 393    }
 394
 395    private static bool TryRaycastCapsule(
 396        Vector2d start,
 397        Vector2d end,
 398        Fixed64 segmentLength,
 399        LSCapsuleCollider2D capsule,
 400        out Physics2DHit hit)
 401    {
 271402        var query = new FixedSegment2d(start, end);
 271403        if (!query.TryGetCapsuleIntersectionDistanceInterval(
 271404                capsule.Center,
 271405                capsule.Rotation,
 271406                capsule.AxisLength,
 271407                capsule.ScaledRadius,
 271408                Fixed64.Zero,
 271409                segmentLength,
 271410                out Fixed64 distance,
 271411                out _,
 271412                out _,
 271413                out _))
 414        {
 3415            hit = default;
 3416            return false;
 417        }
 418
 268419        Vector2d pointOnRay = query.GetPointAtDistance(distance, segmentLength);
 268420        Vector2d normal = capsule.GetNormalFromCenteredAxis(pointOnRay);
 268421        hit = new Physics2DHit(
 268422            capsule,
 268423            ContactAnchor2D.FromWorldPoint(pointOnRay),
 268424            normal,
 268425            distance);
 268426        return true;
 427    }
 428
 429    private static bool TrySweepCircleCapsule(
 430        Vector2d start,
 431        Vector2d end,
 432        Fixed64 segmentLength,
 433        Fixed64 radius,
 434        LSCapsuleCollider2D capsule,
 435        out Physics2DHit hit)
 436    {
 268437        var query = new FixedSegment2d(start, end);
 268438        if (!query.TryGetCapsuleIntersectionDistanceInterval(
 268439                capsule.Center,
 268440                capsule.Rotation,
 268441                capsule.AxisLength,
 268442                capsule.ScaledRadius,
 268443                radius,
 268444                segmentLength,
 268445                out Fixed64 distance,
 268446                out _,
 268447                out _,
 268448                out _))
 449        {
 2450            hit = default;
 2451            return false;
 452        }
 453
 266454        Vector2d sweptCenter = query.GetPointAtDistance(distance, segmentLength);
 266455        Vector2d normal = capsule.GetNormalFromCenteredAxis(sweptCenter);
 266456        bool hasPoint = TryOffsetPoint(
 266457            sweptCenter,
 266458            -normal,
 266459            radius,
 266460            out Vector2d point);
 461
 266462        hit = new Physics2DHit(
 266463            capsule,
 266464            hasPoint
 266465                ? ContactAnchor2D.FromWorldPoint(point)
 266466                : new ContactAnchor2D(
 266467                    sweptCenter,
 266468                    -normal * radius),
 266469            normal,
 266470            distance);
 266471        return true;
 472    }
 473
 474    private static bool TryOverlapCircleCompound(
 475        Vector2d center,
 476        Fixed64 radius,
 477        LSCompoundCollider2D compound,
 478        out Physics2DHit hit)
 479    {
 4480        bool found = false;
 4481        Physics2DHit best = default;
 482
 24483        for (int i = 0; i < compound.PartCount; i++)
 484        {
 8485            LSCollider2D part = compound.GetPartCollider(i);
 8486            if (!TryOverlapCircle(center, radius, part, out Physics2DHit candidate))
 487                continue;
 488
 6489            TryKeepEarlierHit(candidate, ref found, ref best);
 490        }
 491
 4492        if (!found)
 493        {
 1494            hit = default;
 1495            return false;
 496        }
 497
 3498        hit = new Physics2DHit(compound, best.Anchor, best.Normal, best.Distance);
 3499        return true;
 500    }
 501
 502    private static bool TryOverlapConvexArea(
 503        Vector2d center,
 504        ReadOnlySpan<Vector2d> vertices,
 505        LSCollider2D collider,
 506        out Physics2DHit hit)
 507    {
 7805508        if (collider is LSCompoundCollider2D compound)
 2509            return TryOverlapConvexAreaCompound(center, vertices, compound, out hit);
 510
 7803511        return collider switch
 7803512        {
 7803513            LSCircleCollider2D circle =>
 7506514                TryOverlapConvexAreaCircle(center, vertices, circle, out hit),
 7803515            LSCapsuleCollider2D capsule =>
 136516                TryOverlapConvexAreaCapsule(center, vertices, capsule, out hit),
 161517            _ => TryOverlapConvexAreaConvex(center, vertices, collider, out hit)
 7803518        };
 519    }
 520
 521    private static bool TryOverlapConvexAreaCompound(
 522        Vector2d center,
 523        ReadOnlySpan<Vector2d> vertices,
 524        LSCompoundCollider2D compound,
 525        out Physics2DHit hit)
 526    {
 2527        bool found = false;
 2528        Physics2DHit best = default;
 12529        for (int i = 0; i < compound.PartCount; i++)
 530        {
 4531            LSCollider2D part = compound.GetPartCollider(i);
 4532            if (!TryOverlapConvexArea(center, vertices, part, out Physics2DHit candidate))
 533                continue;
 534
 2535            TryKeepEarlierHit(candidate, ref found, ref best);
 536        }
 537
 2538        if (!found)
 539        {
 1540            hit = default;
 1541            return false;
 542        }
 543
 1544        hit = new Physics2DHit(compound, best.Anchor, best.Normal, best.Distance);
 1545        return true;
 546    }
 547
 548    private static bool TryOverlapConvexAreaCircle(
 549        Vector2d center,
 550        ReadOnlySpan<Vector2d> vertices,
 551        LSCircleCollider2D circle,
 552        out Physics2DHit hit)
 553    {
 7506554        if (!FixedConvex2dRelations.TryGetCircleContact(
 7506555                circle.Center,
 7506556                circle.Rotation,
 7506557                circle.ScaledRadius,
 7506558                Vector2d.Zero,
 7506559                Fixed64.Zero,
 7506560                vertices,
 7506561                out _,
 7506562                out _,
 7506563                out _,
 7506564                out _,
 7506565                out _))
 566        {
 8567            hit = default;
 8568            return false;
 569        }
 570
 7498571        return TryBuildCenteredCapsuleAreaHit(
 7498572            center,
 7498573            circle.Center,
 7498574            circle.Rotation,
 7498575            Fixed64.Zero,
 7498576            circle.ScaledRadius,
 7498577            circle,
 7498578            out hit);
 579    }
 580
 581    private static bool TryOverlapConvexAreaCapsule(
 582        Vector2d center,
 583        ReadOnlySpan<Vector2d> vertices,
 584        LSCapsuleCollider2D capsule,
 585        out Physics2DHit hit)
 586    {
 136587        if (!FixedSegment2d.TryGetCenteredCapsuleConvexMinimumTranslation(
 136588                capsule.Center,
 136589                capsule.Rotation,
 136590                capsule.AxisLength,
 136591                capsule.ScaledRadius,
 136592                Vector2d.Zero,
 136593                vertices,
 136594                out _,
 136595                out _))
 596        {
 3597            hit = default;
 3598            return false;
 599        }
 600
 133601        return TryBuildCenteredCapsuleAreaHit(
 133602            center,
 133603            capsule.Center,
 133604            capsule.Rotation,
 133605            capsule.AxisLength,
 133606            capsule.ScaledRadius,
 133607            capsule,
 133608            out hit);
 609    }
 610
 611    private static bool TryOverlapConvexAreaConvex(
 612        Vector2d center,
 613        ReadOnlySpan<Vector2d> vertices,
 614        LSCollider2D collider,
 615        out Physics2DHit hit)
 616    {
 161617        Span<Vector2d> targetScratch = stackalloc Vector2d[4];
 161618        ReadOnlySpan<Vector2d> targetOffsets =
 161619            GetConvexVertexOffsets(collider, targetScratch);
 161620        Span<FixedPointAnchor2d> queryContacts =
 161621            stackalloc FixedPointAnchor2d[2];
 161622        Span<FixedPointAnchor2d> targetContacts =
 161623            stackalloc FixedPointAnchor2d[2];
 161624        if (!FixedConvex2dRelations.TryGetConvexContacts(
 161625                Vector2d.Zero,
 161626                Fixed64.Zero,
 161627                vertices,
 161628                collider.Center,
 161629                collider.ConvexRotation,
 161630                targetOffsets,
 161631                queryContacts,
 161632                targetContacts,
 161633                out _,
 161634                out _,
 161635                out _,
 161636                out _))
 637        {
 9638            hit = default;
 9639            return false;
 640        }
 641
 152642        return TryBuildConvexAreaHit(
 152643            center,
 152644            collider,
 152645            targetOffsets,
 152646            out hit);
 647    }
 648
 649    private static bool TryBuildCenteredCapsuleAreaHit(
 650        Vector2d queryCenter,
 651        Vector2d targetCenter,
 652        Fixed64 targetRotation,
 653        Fixed64 targetAxisLength,
 654        Fixed64 targetRadius,
 655        LSCollider2D target,
 656        out Physics2DHit hit)
 657    {
 7631658        bool containsCenter = FixedSegment2d.ContainsPointInCenteredCapsule(
 7631659            queryCenter,
 7631660            targetCenter,
 7631661            targetRotation,
 7631662            targetAxisLength,
 7631663            targetRadius,
 7631664            Fixed64.Zero);
 7631665        if (containsCenter)
 666        {
 843667            hit = new Physics2DHit(
 843668                target,
 843669                ContactAnchor2D.FromWorldPoint(queryCenter),
 843670                ResolveQueryFallbackNormal(queryCenter, targetCenter),
 843671                Fixed64.Zero);
 843672            return true;
 673        }
 674
 6788675        Vector2d normal = FixedSegment2d.GetDirectionFromCenteredAxis(
 6788676            queryCenter,
 6788677            targetCenter,
 6788678            targetRotation,
 6788679            targetAxisLength);
 680
 6788681        hit = new Physics2DHit(
 6788682            target,
 6788683            new ContactAnchor2D(
 6788684                GetCenteredCapsuleSurfaceAnchor(
 6788685                    queryCenter,
 6788686                    targetCenter,
 6788687                    targetRotation,
 6788688                    targetAxisLength,
 6788689                    targetRadius,
 6788690                    normal)),
 6788691            normal,
 6788692            FixedSegment2d.GetDistanceToCenteredCapsule(
 6788693                queryCenter,
 6788694                targetCenter,
 6788695                targetRotation,
 6788696                targetAxisLength,
 6788697                targetRadius));
 6788698        return true;
 699    }
 700
 701    private static FixedPointAnchor2d GetCenteredCapsuleSurfaceAnchor(
 702        Vector2d point,
 703        Vector2d center,
 704        Fixed64 rotation,
 705        Fixed64 axisLength,
 706        Fixed64 radius,
 707        Vector2d worldNormal)
 708    {
 709        // A unit rotation preserves the admitted normalized direction.
 6788710        _ = Vector2d.TryRotate(
 6788711            worldNormal,
 6788712            -rotation,
 6788713            out Vector2d localNormal);
 6788714        return FixedSegment2d.GetSurfaceAnchorOnCenteredCapsule(
 6788715            point,
 6788716            center,
 6788717            rotation,
 6788718            Vector2d.Forward,
 6788719            axisLength,
 6788720            radius,
 6788721            localNormal.Normalized);
 722    }
 723
 724    private static bool TryBuildConvexAreaHit(
 725        Vector2d queryCenter,
 726        LSCollider2D target,
 727        ReadOnlySpan<Vector2d> targetVertexOffsets,
 728        out Physics2DHit hit)
 729    {
 152730        if (FixedConvex2dRelations.ContainsPoint(
 152731                queryCenter,
 152732                target.Center,
 152733                target.ConvexRotation,
 152734                targetVertexOffsets))
 735        {
 16736            hit = new Physics2DHit(
 16737                target,
 16738                ContactAnchor2D.FromWorldPoint(queryCenter),
 16739                ResolveQueryFallbackNormal(queryCenter, target.Center),
 16740                Fixed64.Zero);
 16741            return true;
 742        }
 743
 136744        FixedPointAnchor2d targetAnchor =
 136745            FixedConvex2dRelations.GetClosestPointAnchor(
 136746                queryCenter,
 136747                target.Center,
 136748                target.ConvexRotation,
 136749                targetVertexOffsets);
 750
 136751        var anchor = new ContactAnchor2D(targetAnchor);
 136752        if (!anchor.TryGetOffsetFrom(queryCenter, out Vector2d centerToTarget)
 136753            || !Vector2d.TryGetMagnitude(centerToTarget, out Fixed64 distance))
 754        {
 2755            hit = default;
 2756            return false;
 757        }
 758
 134759        Vector2d normal = -centerToTarget / distance;
 134760        hit = new Physics2DHit(target, anchor, normal, distance);
 134761        return true;
 762    }
 763
 764    private static bool TryRaycastConvex(
 765        Vector2d start,
 766        Vector2d direction,
 767        Fixed64 segmentLength,
 768        LSCollider2D collider,
 769        out Physics2DHit hit)
 770    {
 286771        Span<Vector2d> scratch = stackalloc Vector2d[4];
 286772        ReadOnlySpan<Vector2d> vertexOffsets =
 286773            GetConvexVertexOffsets(collider, scratch);
 286774        if (!FixedConvex2dRelations.TryGetSegmentFirstIntersectionDistance(
 286775                start,
 286776                direction,
 286777                segmentLength,
 286778                collider.Center,
 286779                collider.ConvexRotation,
 286780                vertexOffsets,
 286781                out Fixed64 distance,
 286782                out Vector2d normal,
 286783                out FixedPointAnchor2d contactAnchor))
 784        {
 1785            hit = default;
 1786            return false;
 787        }
 788
 285789        hit = new Physics2DHit(
 285790            collider,
 285791            new ContactAnchor2D(contactAnchor),
 285792            normal,
 285793            distance);
 285794        return true;
 795    }
 796
 797    private static bool TrySweepCircleConvex(
 798        Vector2d start,
 799        Vector2d direction,
 800        Fixed64 segmentLength,
 801        Fixed64 radius,
 802        LSCollider2D collider,
 803        out Physics2DHit hit)
 804    {
 211805        Span<Vector2d> scratch = stackalloc Vector2d[4];
 211806        ReadOnlySpan<Vector2d> vertexOffsets =
 211807            GetConvexVertexOffsets(collider, scratch);
 211808        if (!FixedConvex2dRelations.TryGetSweptCircleFirstDistance(
 211809                start,
 211810                radius,
 211811                direction,
 211812                segmentLength,
 211813                collider.Center,
 211814                collider.ConvexRotation,
 211815                vertexOffsets,
 211816                out Fixed64 distance,
 211817                out Vector2d normal,
 211818                out FixedPointAnchor2d contactAnchor))
 819        {
 2820            hit = default;
 2821            return false;
 822        }
 823
 209824        hit = new Physics2DHit(
 209825            collider,
 209826            new ContactAnchor2D(contactAnchor),
 209827            normal,
 209828            distance);
 209829        return true;
 830    }
 831
 832    private static bool TrySweepConvexMoverAgainstCircle(
 833        LSCollider2D mover,
 834        Vector2d displacement,
 835        LSCircleCollider2D target,
 836        out Physics2DHit hit)
 837    {
 40838        if (CollisionDetection2D.TryCollide(mover, target, out Contact2D overlap))
 839        {
 2840            Vector2d normal = -overlap.Normal;
 2841            hit = new Physics2DHit(
 2842                target,
 2843                overlap.AnchorB,
 2844                normal,
 2845                Fixed64.Zero);
 2846            return true;
 847        }
 848
 38849        if (!TrySweepCircle(
 38850                target.Center,
 38851                target.Center - displacement,
 38852                target.ScaledRadius,
 38853                mover,
 38854                out Physics2DHit reverseHit))
 855        {
 35856            hit = default;
 35857            return false;
 858        }
 859
 3860        Vector2d hitNormal = -reverseHit.Normal;
 3861        hit = new Physics2DHit(
 3862            target,
 3863            new ContactAnchor2D(
 3864                target.Center,
 3865                hitNormal * target.ScaledRadius),
 3866            hitNormal,
 3867            reverseHit.Distance);
 3868        return true;
 869    }
 870
 871}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/2D/QueryDetection2D.Support.cs

#LineLine coverage
 1//=======================================================================
 2// QueryDetection2D.Support.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using FixedMathSharp.Geometry;
 10using Gravitas.Colliders;
 11using System;
 12using System.Runtime.CompilerServices;
 13
 14namespace Gravitas.Queries;
 15
 16internal static partial class QueryDetection2D
 17{
 18    private static bool TryOffsetPoint(
 19        Vector2d point,
 20        Vector2d direction,
 21        Fixed64 distance,
 22        out Vector2d result)
 23    {
 27424        bool representable = Fixed64.TryMultiplyAdd(direction.X, distance, point.X, out Fixed64 x)
 27425            & Fixed64.TryMultiplyAdd(direction.Y, distance, point.Y, out Fixed64 y);
 27426        result = representable ? new Vector2d(x, y) : default;
 27427        return representable;
 28    }
 29
 30    private static bool ContainsPointExact(
 31        LSCollider2D collider,
 32        Vector2d point)
 33    {
 1417134        if (collider is LSCircleCollider2D circle)
 35        {
 1360836            return FixedSegment2d.ContainsPointInCenteredCapsule(
 1360837                point,
 1360838                circle.Center,
 1360839                Vector2d.Right,
 1360840                Fixed64.Zero,
 1360841                circle.ScaledRadius,
 1360842                Fixed64.Zero);
 43        }
 44
 56345        if (collider is LSCapsuleCollider2D capsule)
 27246            return capsule.ContainsPoint(point);
 29147        if (collider is not LSAABBoxCollider2D
 29148            && collider is not LSPolygonCollider2D)
 49        {
 450            return collider.ContainsPoint(point);
 51        }
 52
 28753        Span<Vector2d> scratch = stackalloc Vector2d[4];
 28754        ReadOnlySpan<Vector2d> vertexOffsets =
 28755            GetConvexVertexOffsets(collider, scratch);
 28756        return FixedConvex2dRelations.ContainsPoint(
 28757            point,
 28758            collider.Center,
 28759            collider.ConvexRotation,
 28760            vertexOffsets);
 61    }
 62
 63    private static ReadOnlySpan<Vector2d> GetConvexVertexOffsets(
 64        LSCollider2D collider,
 65        Span<Vector2d> scratch)
 66    {
 158067        if (collider is LSPolygonCollider2D polygon)
 71768            return polygon.ScaledLocalVertices;
 69
 86370        int vertexCount = collider.VertexCount;
 863071        for (int i = 0; i < vertexCount; i++)
 345272            scratch[i] = collider.GetScaledLocalVertexUnchecked(i);
 86373        return scratch.Slice(0, vertexCount);
 74    }
 75
 76    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 77    private static void TryKeepEarlierHit(Physics2DHit candidate, ref bool found, ref Physics2DHit best)
 78    {
 2579        if (!PhysicsHitSelectionPolicy.ShouldReplace(candidate, found, best))
 680            return;
 81
 1982        found = true;
 1983        best = candidate;
 1984    }
 85
 86    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 87    private static void TryKeepCloserHit(Physics2DHit candidate, ref bool found, ref Physics2DHit best)
 88    {
 489        if (!PhysicsHitSelectionPolicy.ShouldReplaceDistance(candidate.Distance, found, best.Distance))
 190            return;
 91
 392        found = true;
 393        best = candidate;
 394    }
 95
 96    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 97    private static bool SegmentBoundsOverlap(Vector2d start, Vector2d end, LSCollider2D collider)
 98    {
 1420599        Fixed64 minX = FixedMath.Min(start.X, end.X);
 14205100        Fixed64 maxX = FixedMath.Max(start.X, end.X);
 14205101        Fixed64 minY = FixedMath.Min(start.Y, end.Y);
 14205102        Fixed64 maxY = FixedMath.Max(start.Y, end.Y);
 14205103        return maxX >= collider.MinX
 14205104            && minX <= collider.MaxX
 14205105            && maxY >= collider.MinY
 14205106            && minY <= collider.MaxY;
 107    }
 108
 109    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 110    private static bool SweepBoundsOverlap(Vector2d start, Vector2d end, Fixed64 radius, LSCollider2D collider)
 111    {
 8272112        Fixed64 minX = FixedMath.Min(start.X, end.X) - radius;
 8272113        Fixed64 maxX = FixedMath.Max(start.X, end.X) + radius;
 8272114        Fixed64 minY = FixedMath.Min(start.Y, end.Y) - radius;
 8272115        Fixed64 maxY = FixedMath.Max(start.Y, end.Y) + radius;
 8272116        return maxX >= collider.MinX
 8272117            && minX <= collider.MaxX
 8272118            && maxY >= collider.MinY
 8272119            && minY <= collider.MaxY;
 120    }
 121
 122    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 123    private static Vector2d ResolveQueryFallbackNormal(Vector2d center, Vector2d colliderCenter)
 124    {
 23848125        Vector2d direction = center - colliderCenter;
 23848126        return direction.MagnitudeSquared > Fixed64.Epsilon
 23848127            ? direction.Normalized
 23848128            : Vector2d.Right;
 129    }
 130}

Methods/Properties

TryRaycastCompound(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepCircleCompound(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepMoverCompound(Gravitas.Colliders.LSCompoundCollider2D,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepMoverAgainstCompound(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepCapsuleMover(Gravitas.Colliders.LSCapsuleCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepConvexMoverAgainstCapsule(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepConvexMoverAgainstConvex(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TryBuildCapsuleTargetSweepHit(Gravitas.Colliders.LSCapsuleCollider2D,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,Gravitas.Queries.Physics2DHit&)
TryOverlapCircle(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TryOverlapCircleCenteredCapsule(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TryOverlapPolygon(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
ValidateAabbSize(FixedMathSharp.Vector2d)
ValidateConvexQueryPolygon(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
CalculateAverageCenter(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
TryRaycast(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepCircle(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepMoverShape(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TryRaycastCircle(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCircleCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepCircleCircle(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCircleCollider2D,Gravitas.Queries.Physics2DHit&)
TryRaycastCapsule(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepCircleCapsule(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Queries.Physics2DHit&)
TryOverlapCircleCompound(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Queries.Physics2DHit&)
TryOverlapConvexArea(FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TryOverlapConvexAreaCompound(FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Queries.Physics2DHit&)
TryOverlapConvexAreaCircle(FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,Gravitas.Colliders.LSCircleCollider2D,Gravitas.Queries.Physics2DHit&)
TryOverlapConvexAreaCapsule(FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Queries.Physics2DHit&)
TryOverlapConvexAreaConvex(FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TryBuildCenteredCapsuleAreaHit(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
GetCenteredCapsuleSurfaceAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d)
TryBuildConvexAreaHit(FixedMathSharp.Vector2d,Gravitas.Colliders.LSCollider2D,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,Gravitas.Queries.Physics2DHit&)
TryRaycastConvex(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepCircleConvex(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D,Gravitas.Queries.Physics2DHit&)
TrySweepConvexMoverAgainstCircle(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCircleCollider2D,Gravitas.Queries.Physics2DHit&)
TryOffsetPoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d&)
ContainsPointExact(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d)
GetConvexVertexOffsets(Gravitas.Colliders.LSCollider2D,System.Span`1<FixedMathSharp.Vector2d>)
TryKeepEarlierHit(Gravitas.Queries.Physics2DHit,System.Boolean&,Gravitas.Queries.Physics2DHit&)
TryKeepCloserHit(Gravitas.Queries.Physics2DHit,System.Boolean&,Gravitas.Queries.Physics2DHit&)
SegmentBoundsOverlap(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,Gravitas.Colliders.LSCollider2D)
SweepBoundsOverlap(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider2D)
ResolveQueryFallbackNormal(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)