< Summary

Line coverage
100%
Covered lines: 1544
Uncovered lines: 0
Coverable lines: 1544
Total lines: 3317
Line coverage: 100%
Branch coverage
100%
Covered branches: 426
Total branches: 426
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: .ctor(...)100%11100%
File 1: RaycastBatch(...)100%44100%
File 1: RaycastAllBatch(...)100%44100%
File 1: SweepSphereBatch(...)100%22100%
File 1: SweepSphereAllBatch(...)100%22100%
File 1: SweepCapsuleBatch(...)100%22100%
File 1: SweepCapsuleAllBatch(...)100%22100%
File 1: SweepCuboidBatch(...)100%22100%
File 1: SweepCuboidAllBatch(...)100%22100%
File 1: SweepCylinderBatch(...)100%22100%
File 1: SweepCylinderAllBatch(...)100%22100%
File 1: SweepConeBatch(...)100%22100%
File 1: SweepConeAllBatch(...)100%22100%
File 1: SweepConvexMeshBatch(...)100%22100%
File 1: SweepConvexMeshAllBatch(...)100%22100%
File 1: SweepCompoundBatch(...)100%22100%
File 1: SweepCompoundAllBatch(...)100%22100%
File 1: OverlapCircleBatch(...)100%22100%
File 1: OverlapCircleAllBatch(...)100%22100%
File 1: OverlapConeBatch(...)100%22100%
File 1: OverlapConeAllBatch(...)100%22100%
File 1: OverlapCircleInDirectionBatch(...)100%22100%
File 1: TryRaycastBatchRequest(...)100%66100%
File 1: RaycastAllBatchRequest(...)100%66100%
File 1: SweepSphereAllBatchRequest(...)100%88100%
File 1: TrySweepSourceBatchRequest(...)100%44100%
File 1: SweepSourceAllBatchRequest(...)100%44100%
File 1: PrepareBatchConvexSweepSource(...)100%44100%
File 1: TryOverlapCircleBatchRequest(...)100%11100%
File 1: OverlapCircleAllBatchRequest(...)100%11100%
File 1: TryOverlapCircleInDirectionBatchRequest(...)100%22100%
File 1: TryOverlapConeBatchRequest(...)100%11100%
File 1: ValidateOverlapCircleRequests(...)100%22100%
File 1: ValidateOverlapCircleRequests(...)100%22100%
File 1: OverlapConeAllBatchRequest(...)100%11100%
File 1: WriteClosestHit(...)100%22100%
File 1: AppendRange(...)100%22100%
File 1: ResetBatchCounters(...)100%11100%
File 1: AccumulateBatchCounters(...)100%11100%
File 1: ValidateClosestBatchOutput(...)100%11100%
File 1: ValidateRangeBatchOutput(...)100%11100%
File 2: OverlapCircle(...)100%11100%
File 2: OverlapCircleInDirection(...)100%11100%
File 2: OverlapCircleAll(...)100%22100%
File 2: OverlapSphereAgainstStaticAll(...)100%66100%
File 2: ProcessPartitionForAllSphereHits(...)100%11100%
File 2: ProcessColliderListForAllSphereHits(...)100%66100%
File 2: TryBuildOverlapSphereHit(...)100%2222100%
File 2: TraceCircleForClosestHit(...)100%66100%
File 2: TraceCircleForDirectionalHit(...)100%1414100%
File 2: TraceCircleForAllHits(...)100%44100%
File 2: GetPlanarCircleCandidates(...)100%11100%
File 2: TryBuildOverlapHit(...)100%22100%
File 2: TryBuildPlanarOverlapHit(...)100%22100%
File 2: TryBuildSurfaceOverlapHit(...)100%1010100%
File 2: GetClosestSurfacePoint(...)100%44100%
File 3: OverlapCone(...)100%11100%
File 3: OverlapConeAll(...)100%22100%
File 3: TraceConeForClosestHit(...)100%44100%
File 3: TraceConeForAllHits(...)100%44100%
File 3: ProcessConePartitionForClosestHit(...)100%11100%
File 3: ProcessConePartitionForAllHits(...)100%11100%
File 3: ProcessConeColliderListForClosestHit(...)100%88100%
File 3: ProcessConeColliderListForAllHits(...)100%66100%
File 3: TryBuildOverlapConeHit(...)100%88100%
File 3: TryBuildConeHitForCollider(...)100%1818100%
File 3: TryBuildConeHitForConcaveMesh(...)100%1414100%
File 3: TryBuildConeHitForCompound(...)100%88100%
File 3: IsPointInsideConeVolume(...)100%22100%
File 3: GetClosestPointOnConeAxis(...)100%11100%
File 3: GetConeQueryBounds(...)100%11100%
File 3: ValidateConeQuery(...)100%11100%
File 4: .ctor(...)100%11100%
File 4: get_Context()100%11100%
File 4: Reset()100%11100%
File 4: Raycast(...)100%66100%
File 4: RaycastAll(...)100%88100%
File 4: SweepSphere(...)100%66100%
File 4: SweepSphereAll(...)100%11100%
File 4: SweepSphereAgainstStaticAll(...)100%11100%
File 4: SweepExactSourceAgainstStaticAll(...)100%11100%
File 4: SweepCapsule(...)100%11100%
File 4: SweepCapsuleAll(...)100%11100%
File 4: SweepCuboid(...)100%11100%
File 4: SweepCuboidAll(...)100%11100%
File 4: SweepCylinder(...)100%11100%
File 4: SweepCylinderAll(...)100%11100%
File 4: SweepCone(...)100%11100%
File 4: SweepConeAll(...)100%11100%
File 4: SweepConvexMesh(...)100%11100%
File 4: SweepConvexMeshAll(...)100%11100%
File 4: SweepCompound(...)100%11100%
File 4: SweepCompoundAll(...)100%11100%
File 4: SweepPrimitiveSource(...)100%11100%
File 4: SweepPrimitiveSourceAll(...)100%11100%
File 4: SweepConvexMeshSource(...)100%11100%
File 4: SweepConvexMeshSourceAll(...)100%11100%
File 4: SweepCompoundSource(...)100%11100%
File 4: SweepCompoundSourceAll(...)100%11100%
File 4: SweepSphereAllCore(...)100%1010100%
File 4: SweepPreparedConvexSource(...)100%44100%
File 4: SweepPreparedConvexSourceAll(...)100%66100%
File 4: BeginConvexSweepTrace(...)100%11100%
File 4: BeginRaycastTrace(...)100%11100%
File 4: BeginSweepTrace(...)100%11100%
File 4: SweepSphere(...)100%88100%
File 4: TryFindClosestSweepHit(...)100%11100%
File 4: TryFindClosestHit(...)100%11100%
File 4: AddAllHits(...)100%11100%
File 4: AddAllSweepHits(...)100%11100%
File 4: TryFindClosestConvexSweepHit(...)100%11100%
File 4: AddAllConvexSweepHits(...)100%11100%
File 4: TryBuildHitForCollider(...)100%44100%
File 4: TryBuildSweepHitForCollider(...)100%44100%
File 4: TryBuildConvexSweepHitForCollider(...)100%44100%
File 4: TryBuildHit(...)100%66100%
File 4: TryBuildSweepHit(...)100%44100%
File 4: ResetLastQueryCounters()100%11100%
File 4: NextRaycastVersion()100%22100%
File 4: NextCircleVersion()100%22100%
File 4: ResetColliderRaycastVersions()100%22100%
File 4: ResetColliderCircleVersions()100%22100%
File 4: DoesCurrentColliderIntersectRay(...)100%66100%
File 4: IsSweepCandidate(...)100%2020100%
File 4: IsExcludedByCurrentSweepSource(...)100%66100%
File 4: EnsureSourceBelongsToContext(...)100%11100%
File 4: PrepareConvexSweepSource(...)100%44100%
File 4: IsStaticStyleSweepTarget(...)100%22100%
File 5: TraceLineForClosestHit(...)100%22100%
File 5: TraceLineForAllHits(...)100%22100%
File 5: TraceSweepForClosestHit(...)100%22100%
File 5: TraceSweepForAllHits(...)100%22100%
File 5: TraceConvexSweepForClosestHit(...)100%22100%
File 5: TraceConvexSweepForAllHits(...)100%22100%
File 5: PrepareSweepBounds(...)100%11100%
File 5: PrepareConvexSweepBounds(...)100%11100%
File 5: ProcessTraceVoxelForClosestHit(...)100%22100%
File 5: ProcessTraceVoxelForAllHits(...)100%22100%
File 5: ProcessSweepVoxelForClosestHit(...)100%22100%
File 5: ProcessSweepVoxelForAllHits(...)100%22100%
File 5: ProcessConvexSweepVoxelForClosestHit(...)100%22100%
File 5: ProcessConvexSweepVoxelForAllHits(...)100%22100%
File 5: ProcessPartitionForClosestHit(...)100%11100%
File 5: ProcessColliderListForClosestHit(...)100%88100%
File 5: ProcessPartitionForAllHits(...)100%11100%
File 5: ProcessColliderListForAllHits(...)100%66100%
File 5: ProcessPartitionForClosestSweepHit(...)100%11100%
File 5: ProcessColliderListForClosestSweepHit(...)100%88100%
File 5: ProcessPartitionForAllSweepHits(...)100%22100%
File 5: ProcessPartitionForClosestConvexSweepHit(...)100%11100%
File 5: ProcessPartitionForAllConvexSweepHits(...)100%22100%
File 5: ProcessColliderListForAllSweepHits(...)100%66100%
File 5: ProcessColliderListForClosestConvexSweepHit(...)100%88100%
File 5: ProcessColliderListForAllConvexSweepHits(...)100%66100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/3D/GravitasQuery3DService.Batch.cs

#LineLine coverage
 1//=======================================================================
 2// GravitasQuery3DService.Batch.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;
 10using Gravitas.Support;
 11using SwiftCollections;
 12using System;
 13
 14namespace Gravitas.Queries;
 15
 16/// <summary>
 17/// Owns batched 3D query behavior for one <see cref="GravitasWorldContext"/>.
 18/// </summary>
 19public sealed partial class GravitasQuery3DService
 20{
 508321    private readonly SwiftList<Physics3DHit> _batch3DHits = new();
 22
 23    /// <summary>
 24    /// Gets the number of requests processed by the last 3D batch query call.
 25    /// </summary>
 26    public int LastBatchRequestCount { get; private set; }
 27
 28    /// <summary>
 29    /// Gets the number of hits accepted by the last 3D batch query call.
 30    /// </summary>
 31    public int LastBatchHitCount { get; private set; }
 32
 33    /// <summary>
 34    /// Gets the summed candidate count reported by the last 3D batch query call.
 35    /// </summary>
 36    public int LastBatchCandidateCount { get; private set; }
 37
 38    /// <summary>
 39    /// Executes multiple 3D segment raycasts and writes one closest-hit slot per request.
 40    /// </summary>
 41    /// <returns>The number of requests that produced a hit.</returns>
 42    public int RaycastBatch(ReadOnlySpan<PhysicsRaycast3DRequest> requests, Span<Physics3DHit> closestHits)
 43    {
 21144        ValidateClosestBatchOutput(requests.Length, closestHits);
 21045        ResetBatchCounters(requests.Length);
 46
 21047        int hitCount = 0;
 126248        for (int i = 0; i < requests.Length; i++)
 49        {
 42150            PhysicsRaycast3DRequest request = requests[i];
 42151            bool found = TryRaycastBatchRequest(request, out Physics3DHit hit);
 42152            if (found)
 53            {
 21054                closestHits[i] = hit;
 21055                hitCount++;
 56            }
 57            else
 58            {
 21159                closestHits[i] = default;
 60            }
 61
 42162            AccumulateBatchCounters(found ? 1 : 0);
 63        }
 64
 21065        LastBatchHitCount = hitCount;
 21066        return hitCount;
 67    }
 68
 69    /// <summary>
 70    /// Executes multiple 3D segment raycasts and appends all hits into one caller-owned hit buffer.
 71    /// </summary>
 72    /// <returns>The number of hits written to <paramref name="hits"/>.</returns>
 73    public int RaycastAllBatch(
 74        ReadOnlySpan<PhysicsRaycast3DRequest> requests,
 75        SwiftList<Physics3DHit> hits,
 76        Span<PhysicsQueryHitRange> ranges)
 77    {
 21278        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 21279        ValidateRangeBatchOutput(requests.Length, ranges);
 21280        ResetBatchCounters(requests.Length);
 21281        hits.FastClear();
 82
 127283        for (int i = 0; i < requests.Length; i++)
 84        {
 42485            int start = hits.Count;
 42486            PhysicsRaycast3DRequest request = requests[i];
 42487            int count = RaycastAllBatchRequest(request, _batch3DHits);
 42488            if (count > 0)
 21289                hits.AddRange(_batch3DHits.AsReadOnlySpan());
 90
 42491            ranges[i] = new PhysicsQueryHitRange(start, count);
 42492            AccumulateBatchCounters(count);
 93        }
 94
 21295        LastBatchHitCount = hits.Count;
 21296        return hits.Count;
 97    }
 98
 99    /// <summary>
 100    /// Executes multiple 3D swept-sphere queries and writes one closest-hit slot per request.
 101    /// </summary>
 102    public int SweepSphereBatch(ReadOnlySpan<PhysicsSweepSphere3DRequest> requests, Span<Physics3DHit> closestHits)
 103    {
 3104        ValidateClosestBatchOutput(requests.Length, closestHits);
 3105        ResetBatchCounters(requests.Length);
 106
 3107        int hitCount = 0;
 20108        for (int i = 0; i < requests.Length; i++)
 109        {
 7110            PhysicsSweepSphere3DRequest request = requests[i];
 7111            bool found = SweepSphere(
 7112                request.Start,
 7113                request.End,
 7114                request.Radius,
 7115                request.LayerMask,
 7116                request.ExcludedCollider,
 7117                out Physics3DHit hit);
 7118            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 119        }
 120
 3121        LastBatchHitCount = hitCount;
 3122        return hitCount;
 123    }
 124
 125    /// <summary>
 126    /// Executes multiple 3D swept-sphere queries and appends all hits into one caller-owned hit buffer.
 127    /// </summary>
 128    public int SweepSphereAllBatch(
 129        ReadOnlySpan<PhysicsSweepSphere3DRequest> requests,
 130        SwiftList<Physics3DHit> hits,
 131        Span<PhysicsQueryHitRange> ranges)
 132    {
 3133        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 3134        ValidateRangeBatchOutput(requests.Length, ranges);
 3135        ResetBatchCounters(requests.Length);
 3136        hits.FastClear();
 137
 20138        for (int i = 0; i < requests.Length; i++)
 139        {
 7140            PhysicsSweepSphere3DRequest request = requests[i];
 7141            int count = SweepSphereAllBatchRequest(request, _batch3DHits);
 7142            AppendRange(hits, ranges, i, count);
 143        }
 144
 3145        LastBatchHitCount = hits.Count;
 3146        return hits.Count;
 147    }
 148
 149    /// <summary>
 150    /// Executes multiple registered capsule-source sweeps and writes one closest-hit slot per request.
 151    /// </summary>
 152    public int SweepCapsuleBatch(ReadOnlySpan<PhysicsSweepCapsule3DRequest> requests, Span<Physics3DHit> closestHits)
 153    {
 1154        ValidateClosestBatchOutput(requests.Length, closestHits);
 1155        ResetBatchCounters(requests.Length);
 156
 1157        int hitCount = 0;
 1158        LSCollider? preparedSource = null;
 1159        Vector3d preparedDisplacement = default;
 6160        for (int i = 0; i < requests.Length; i++)
 161        {
 2162            PhysicsSweepCapsule3DRequest request = requests[i];
 2163            bool found = TrySweepSourceBatchRequest(
 2164                request.Source,
 2165                request.Displacement,
 2166                request.LayerMask,
 2167                request.ExcludedCollider,
 2168                request.IncludeTriggers,
 2169                ref preparedSource,
 2170                ref preparedDisplacement,
 2171                out Physics3DHit hit);
 2172            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 173        }
 174
 1175        LastBatchHitCount = hitCount;
 1176        return hitCount;
 177    }
 178
 179    /// <summary>
 180    /// Executes multiple registered capsule-source sweeps and appends all hits into one caller-owned hit buffer.
 181    /// </summary>
 182    public int SweepCapsuleAllBatch(
 183        ReadOnlySpan<PhysicsSweepCapsule3DRequest> requests,
 184        SwiftList<Physics3DHit> hits,
 185        Span<PhysicsQueryHitRange> ranges)
 186    {
 1187        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 1188        ValidateRangeBatchOutput(requests.Length, ranges);
 1189        ResetBatchCounters(requests.Length);
 1190        hits.FastClear();
 191
 1192        LSCollider? preparedSource = null;
 1193        Vector3d preparedDisplacement = default;
 6194        for (int i = 0; i < requests.Length; i++)
 195        {
 2196            PhysicsSweepCapsule3DRequest request = requests[i];
 2197            int count = SweepSourceAllBatchRequest(
 2198                request.Source,
 2199                request.Displacement,
 2200                request.LayerMask,
 2201                request.ExcludedCollider,
 2202                request.IncludeTriggers,
 2203                ref preparedSource,
 2204                ref preparedDisplacement,
 2205                _batch3DHits);
 2206            AppendRange(hits, ranges, i, count);
 207        }
 208
 1209        LastBatchHitCount = hits.Count;
 1210        return hits.Count;
 211    }
 212
 213    /// <summary>
 214    /// Executes multiple registered cuboid-source sweeps and writes one closest-hit slot per request.
 215    /// </summary>
 216    public int SweepCuboidBatch(ReadOnlySpan<PhysicsSweepCuboid3DRequest> requests, Span<Physics3DHit> closestHits)
 217    {
 2218        ValidateClosestBatchOutput(requests.Length, closestHits);
 2219        ResetBatchCounters(requests.Length);
 220
 2221        int hitCount = 0;
 2222        LSCollider? preparedSource = null;
 2223        Vector3d preparedDisplacement = default;
 12224        for (int i = 0; i < requests.Length; i++)
 225        {
 4226            PhysicsSweepCuboid3DRequest request = requests[i];
 4227            bool found = TrySweepSourceBatchRequest(
 4228                request.Source,
 4229                request.Displacement,
 4230                request.LayerMask,
 4231                request.ExcludedCollider,
 4232                request.IncludeTriggers,
 4233                ref preparedSource,
 4234                ref preparedDisplacement,
 4235                out Physics3DHit hit);
 4236            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 237        }
 238
 2239        LastBatchHitCount = hitCount;
 2240        return hitCount;
 241    }
 242
 243    /// <summary>
 244    /// Executes multiple registered cuboid-source sweeps and appends all hits into one caller-owned hit buffer.
 245    /// </summary>
 246    public int SweepCuboidAllBatch(
 247        ReadOnlySpan<PhysicsSweepCuboid3DRequest> requests,
 248        SwiftList<Physics3DHit> hits,
 249        Span<PhysicsQueryHitRange> ranges)
 250    {
 2251        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 2252        ValidateRangeBatchOutput(requests.Length, ranges);
 2253        ResetBatchCounters(requests.Length);
 2254        hits.FastClear();
 255
 2256        LSCollider? preparedSource = null;
 2257        Vector3d preparedDisplacement = default;
 12258        for (int i = 0; i < requests.Length; i++)
 259        {
 4260            PhysicsSweepCuboid3DRequest request = requests[i];
 4261            int count = SweepSourceAllBatchRequest(
 4262                request.Source,
 4263                request.Displacement,
 4264                request.LayerMask,
 4265                request.ExcludedCollider,
 4266                request.IncludeTriggers,
 4267                ref preparedSource,
 4268                ref preparedDisplacement,
 4269                _batch3DHits);
 4270            AppendRange(hits, ranges, i, count);
 271        }
 272
 2273        LastBatchHitCount = hits.Count;
 2274        return hits.Count;
 275    }
 276
 277    /// <summary>
 278    /// Executes multiple registered cylinder-source sweeps and writes one closest-hit slot per request.
 279    /// </summary>
 280    public int SweepCylinderBatch(ReadOnlySpan<PhysicsSweepCylinder3DRequest> requests, Span<Physics3DHit> closestHits)
 281    {
 1282        ValidateClosestBatchOutput(requests.Length, closestHits);
 1283        ResetBatchCounters(requests.Length);
 284
 1285        int hitCount = 0;
 1286        LSCollider? preparedSource = null;
 1287        Vector3d preparedDisplacement = default;
 6288        for (int i = 0; i < requests.Length; i++)
 289        {
 2290            PhysicsSweepCylinder3DRequest request = requests[i];
 2291            bool found = TrySweepSourceBatchRequest(
 2292                request.Source,
 2293                request.Displacement,
 2294                request.LayerMask,
 2295                request.ExcludedCollider,
 2296                request.IncludeTriggers,
 2297                ref preparedSource,
 2298                ref preparedDisplacement,
 2299                out Physics3DHit hit);
 2300            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 301        }
 302
 1303        LastBatchHitCount = hitCount;
 1304        return hitCount;
 305    }
 306
 307    /// <summary>
 308    /// Executes multiple registered cylinder-source sweeps and appends all hits into one caller-owned hit buffer.
 309    /// </summary>
 310    public int SweepCylinderAllBatch(
 311        ReadOnlySpan<PhysicsSweepCylinder3DRequest> requests,
 312        SwiftList<Physics3DHit> hits,
 313        Span<PhysicsQueryHitRange> ranges)
 314    {
 1315        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 1316        ValidateRangeBatchOutput(requests.Length, ranges);
 1317        ResetBatchCounters(requests.Length);
 1318        hits.FastClear();
 319
 1320        LSCollider? preparedSource = null;
 1321        Vector3d preparedDisplacement = default;
 6322        for (int i = 0; i < requests.Length; i++)
 323        {
 2324            PhysicsSweepCylinder3DRequest request = requests[i];
 2325            int count = SweepSourceAllBatchRequest(
 2326                request.Source,
 2327                request.Displacement,
 2328                request.LayerMask,
 2329                request.ExcludedCollider,
 2330                request.IncludeTriggers,
 2331                ref preparedSource,
 2332                ref preparedDisplacement,
 2333                _batch3DHits);
 2334            AppendRange(hits, ranges, i, count);
 335        }
 336
 1337        LastBatchHitCount = hits.Count;
 1338        return hits.Count;
 339    }
 340
 341    /// <summary>
 342    /// Executes multiple registered cone-source sweeps and writes one closest-hit slot per request.
 343    /// </summary>
 344    public int SweepConeBatch(ReadOnlySpan<PhysicsSweepCone3DRequest> requests, Span<Physics3DHit> closestHits)
 345    {
 1346        ValidateClosestBatchOutput(requests.Length, closestHits);
 1347        ResetBatchCounters(requests.Length);
 348
 1349        int hitCount = 0;
 1350        LSCollider? preparedSource = null;
 1351        Vector3d preparedDisplacement = default;
 6352        for (int i = 0; i < requests.Length; i++)
 353        {
 2354            PhysicsSweepCone3DRequest request = requests[i];
 2355            bool found = TrySweepSourceBatchRequest(
 2356                request.Source,
 2357                request.Displacement,
 2358                request.LayerMask,
 2359                request.ExcludedCollider,
 2360                request.IncludeTriggers,
 2361                ref preparedSource,
 2362                ref preparedDisplacement,
 2363                out Physics3DHit hit);
 2364            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 365        }
 366
 1367        LastBatchHitCount = hitCount;
 1368        return hitCount;
 369    }
 370
 371    /// <summary>
 372    /// Executes multiple registered cone-source sweeps and appends all hits into one caller-owned hit buffer.
 373    /// </summary>
 374    public int SweepConeAllBatch(
 375        ReadOnlySpan<PhysicsSweepCone3DRequest> requests,
 376        SwiftList<Physics3DHit> hits,
 377        Span<PhysicsQueryHitRange> ranges)
 378    {
 1379        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 1380        ValidateRangeBatchOutput(requests.Length, ranges);
 1381        ResetBatchCounters(requests.Length);
 1382        hits.FastClear();
 383
 1384        LSCollider? preparedSource = null;
 1385        Vector3d preparedDisplacement = default;
 6386        for (int i = 0; i < requests.Length; i++)
 387        {
 2388            PhysicsSweepCone3DRequest request = requests[i];
 2389            int count = SweepSourceAllBatchRequest(
 2390                request.Source,
 2391                request.Displacement,
 2392                request.LayerMask,
 2393                request.ExcludedCollider,
 2394                request.IncludeTriggers,
 2395                ref preparedSource,
 2396                ref preparedDisplacement,
 2397                _batch3DHits);
 2398            AppendRange(hits, ranges, i, count);
 399        }
 400
 1401        LastBatchHitCount = hits.Count;
 1402        return hits.Count;
 403    }
 404
 405    /// <summary>
 406    /// Executes multiple registered convex mesh-source sweeps and writes one closest-hit slot per request.
 407    /// </summary>
 408    public int SweepConvexMeshBatch(ReadOnlySpan<PhysicsSweepConvexMesh3DRequest> requests, Span<Physics3DHit> closestHi
 409    {
 1410        ValidateClosestBatchOutput(requests.Length, closestHits);
 1411        ResetBatchCounters(requests.Length);
 412
 1413        int hitCount = 0;
 1414        LSCollider? preparedSource = null;
 1415        Vector3d preparedDisplacement = default;
 6416        for (int i = 0; i < requests.Length; i++)
 417        {
 2418            PhysicsSweepConvexMesh3DRequest request = requests[i];
 2419            bool found = TrySweepSourceBatchRequest(
 2420                request.Source,
 2421                request.Displacement,
 2422                request.LayerMask,
 2423                request.ExcludedCollider,
 2424                request.IncludeTriggers,
 2425                ref preparedSource,
 2426                ref preparedDisplacement,
 2427                out Physics3DHit hit);
 2428            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 429        }
 430
 1431        LastBatchHitCount = hitCount;
 1432        return hitCount;
 433    }
 434
 435    /// <summary>
 436    /// Executes multiple registered convex mesh-source sweeps and appends all hits into one caller-owned hit buffer.
 437    /// </summary>
 438    public int SweepConvexMeshAllBatch(
 439        ReadOnlySpan<PhysicsSweepConvexMesh3DRequest> requests,
 440        SwiftList<Physics3DHit> hits,
 441        Span<PhysicsQueryHitRange> ranges)
 442    {
 1443        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 1444        ValidateRangeBatchOutput(requests.Length, ranges);
 1445        ResetBatchCounters(requests.Length);
 1446        hits.FastClear();
 447
 1448        LSCollider? preparedSource = null;
 1449        Vector3d preparedDisplacement = default;
 6450        for (int i = 0; i < requests.Length; i++)
 451        {
 2452            PhysicsSweepConvexMesh3DRequest request = requests[i];
 2453            int count = SweepSourceAllBatchRequest(
 2454                request.Source,
 2455                request.Displacement,
 2456                request.LayerMask,
 2457                request.ExcludedCollider,
 2458                request.IncludeTriggers,
 2459                ref preparedSource,
 2460                ref preparedDisplacement,
 2461                _batch3DHits);
 2462            AppendRange(hits, ranges, i, count);
 463        }
 464
 1465        LastBatchHitCount = hits.Count;
 1466        return hits.Count;
 467    }
 468
 469    /// <summary>
 470    /// Executes multiple registered compound-source sweeps and writes one closest-hit slot per request.
 471    /// </summary>
 472    public int SweepCompoundBatch(ReadOnlySpan<PhysicsSweepCompound3DRequest> requests, Span<Physics3DHit> closestHits)
 473    {
 1474        ValidateClosestBatchOutput(requests.Length, closestHits);
 1475        ResetBatchCounters(requests.Length);
 476
 1477        int hitCount = 0;
 1478        LSCollider? preparedSource = null;
 1479        Vector3d preparedDisplacement = default;
 6480        for (int i = 0; i < requests.Length; i++)
 481        {
 2482            PhysicsSweepCompound3DRequest request = requests[i];
 2483            bool found = TrySweepSourceBatchRequest(
 2484                request.Source,
 2485                request.Displacement,
 2486                request.LayerMask,
 2487                request.ExcludedCollider,
 2488                request.IncludeTriggers,
 2489                ref preparedSource,
 2490                ref preparedDisplacement,
 2491                out Physics3DHit hit);
 2492            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 493        }
 494
 1495        LastBatchHitCount = hitCount;
 1496        return hitCount;
 497    }
 498
 499    /// <summary>
 500    /// Executes multiple registered compound-source sweeps and appends all hits into one caller-owned hit buffer.
 501    /// </summary>
 502    public int SweepCompoundAllBatch(
 503        ReadOnlySpan<PhysicsSweepCompound3DRequest> requests,
 504        SwiftList<Physics3DHit> hits,
 505        Span<PhysicsQueryHitRange> ranges)
 506    {
 1507        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 1508        ValidateRangeBatchOutput(requests.Length, ranges);
 1509        ResetBatchCounters(requests.Length);
 1510        hits.FastClear();
 511
 1512        LSCollider? preparedSource = null;
 1513        Vector3d preparedDisplacement = default;
 6514        for (int i = 0; i < requests.Length; i++)
 515        {
 2516            PhysicsSweepCompound3DRequest request = requests[i];
 2517            int count = SweepSourceAllBatchRequest(
 2518                request.Source,
 2519                request.Displacement,
 2520                request.LayerMask,
 2521                request.ExcludedCollider,
 2522                request.IncludeTriggers,
 2523                ref preparedSource,
 2524                ref preparedDisplacement,
 2525                _batch3DHits);
 2526            AppendRange(hits, ranges, i, count);
 527        }
 528
 1529        LastBatchHitCount = hits.Count;
 1530        return hits.Count;
 531    }
 532
 533    /// <summary>
 534    /// Executes multiple 3D X/Z circle overlaps and writes one closest-hit slot per request.
 535    /// </summary>
 536    public int OverlapCircleBatch(ReadOnlySpan<PhysicsOverlapCircle3DRequest> requests, Span<Physics3DHit> closestHits)
 537    {
 2538        ValidateClosestBatchOutput(requests.Length, closestHits);
 2539        ValidateOverlapCircleRequests(requests);
 1540        ResetBatchCounters(requests.Length);
 541
 1542        int hitCount = 0;
 8543        for (int i = 0; i < requests.Length; i++)
 544        {
 3545            PhysicsOverlapCircle3DRequest request = requests[i];
 3546            bool found = TryOverlapCircleBatchRequest(request, out Physics3DHit hit);
 3547            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 548        }
 549
 1550        LastBatchHitCount = hitCount;
 1551        return hitCount;
 552    }
 553
 554    /// <summary>
 555    /// Executes multiple 3D X/Z circle overlaps and appends all hits into one caller-owned hit buffer.
 556    /// </summary>
 557    public int OverlapCircleAllBatch(
 558        ReadOnlySpan<PhysicsOverlapCircle3DRequest> requests,
 559        SwiftList<Physics3DHit> hits,
 560        Span<PhysicsQueryHitRange> ranges)
 561    {
 2562        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 2563        ValidateRangeBatchOutput(requests.Length, ranges);
 2564        ValidateOverlapCircleRequests(requests);
 1565        ResetBatchCounters(requests.Length);
 1566        hits.FastClear();
 567
 8568        for (int i = 0; i < requests.Length; i++)
 569        {
 3570            PhysicsOverlapCircle3DRequest request = requests[i];
 3571            int count = OverlapCircleAllBatchRequest(request, _batch3DHits);
 3572            AppendRange(hits, ranges, i, count);
 573        }
 574
 1575        LastBatchHitCount = hits.Count;
 1576        return hits.Count;
 577    }
 578
 579    /// <summary>
 580    /// Executes multiple directional cone-volume overlaps and writes one closest-hit slot per request.
 581    /// </summary>
 582    public int OverlapConeBatch(ReadOnlySpan<PhysicsOverlapCone3DRequest> requests, Span<Physics3DHit> closestHits)
 583    {
 1584        ValidateClosestBatchOutput(requests.Length, closestHits);
 1585        ResetBatchCounters(requests.Length);
 586
 1587        int hitCount = 0;
 6588        for (int i = 0; i < requests.Length; i++)
 589        {
 2590            PhysicsOverlapCone3DRequest request = requests[i];
 2591            bool found = TryOverlapConeBatchRequest(request, out Physics3DHit hit);
 2592            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 593        }
 594
 1595        LastBatchHitCount = hitCount;
 1596        return hitCount;
 597    }
 598
 599    /// <summary>
 600    /// Executes multiple directional cone-volume overlaps and appends all hits into one caller-owned hit buffer.
 601    /// </summary>
 602    public int OverlapConeAllBatch(
 603        ReadOnlySpan<PhysicsOverlapCone3DRequest> requests,
 604        SwiftList<Physics3DHit> hits,
 605        Span<PhysicsQueryHitRange> ranges)
 606    {
 1607        SwiftThrowHelper.ThrowIfNull(hits, nameof(hits));
 1608        ValidateRangeBatchOutput(requests.Length, ranges);
 1609        ResetBatchCounters(requests.Length);
 1610        hits.FastClear();
 611
 6612        for (int i = 0; i < requests.Length; i++)
 613        {
 2614            PhysicsOverlapCone3DRequest request = requests[i];
 2615            int count = OverlapConeAllBatchRequest(request, _batch3DHits);
 2616            AppendRange(hits, ranges, i, count);
 617        }
 618
 1619        LastBatchHitCount = hits.Count;
 1620        return hits.Count;
 621    }
 622
 623    /// <summary>
 624    /// Executes multiple directional 3D X/Z projected-circle overlaps and writes one closest-hit slot per request.
 625    /// </summary>
 626    public int OverlapCircleInDirectionBatch(
 627        ReadOnlySpan<PhysicsOverlapCircleInDirection3DRequest> requests,
 628        Span<Physics3DHit> closestHits)
 629    {
 2630        ValidateClosestBatchOutput(requests.Length, closestHits);
 2631        ValidateOverlapCircleRequests(requests);
 1632        ResetBatchCounters(requests.Length);
 633
 1634        int hitCount = 0;
 10635        for (int i = 0; i < requests.Length; i++)
 636        {
 4637            PhysicsOverlapCircleInDirection3DRequest request = requests[i];
 4638            bool found = TryOverlapCircleInDirectionBatchRequest(request, out Physics3DHit hit);
 4639            WriteClosestHit(closestHits, i, hit, found, ref hitCount);
 640        }
 641
 1642        LastBatchHitCount = hitCount;
 1643        return hitCount;
 644    }
 645
 646    private bool TryRaycastBatchRequest(PhysicsRaycast3DRequest request, out Physics3DHit hit)
 647    {
 421648        _currentLayerMask = request.LayerMask;
 421649        if (!Vector3d.TrySubtract(request.End, request.Start, out Vector3d segment)
 421650            || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength)
 421651            || segmentLength == Fixed64.Zero)
 652        {
 3653            ResetLastQueryCounters();
 3654            hit = default;
 3655            return false;
 656        }
 657
 418658        Vector3d direction = segment.Normalized;
 418659        BeginRaycastTrace(request.Start, request.End);
 418660        return TryFindClosestHit(request.Start, request.End, direction, out hit);
 661    }
 662
 663    private int RaycastAllBatchRequest(PhysicsRaycast3DRequest request, SwiftList<Physics3DHit> results)
 664    {
 424665        _currentLayerMask = request.LayerMask;
 424666        results.FastClear();
 424667        if (!Vector3d.TrySubtract(request.End, request.Start, out Vector3d segment)
 424668            || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength)
 424669            || segmentLength == Fixed64.Zero)
 670        {
 3671            ResetLastQueryCounters();
 3672            return 0;
 673        }
 674
 421675        BeginRaycastTrace(request.Start, request.End);
 421676        AddAllHits(request.Start, request.End, segment.Normalized, results);
 421677        Physics3DHitSorter.SortByDistance(results);
 421678        return results.Count;
 679    }
 680
 681    private int SweepSphereAllBatchRequest(PhysicsSweepSphere3DRequest request, SwiftList<Physics3DHit> results)
 682    {
 7683        results.FastClear();
 7684        if (!Vector3d.TrySubtract(request.End, request.Start, out Vector3d segment)
 7685            || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength)
 7686            || segmentLength <= Fixed64.Epsilon
 7687            || request.Radius <= Fixed64.Zero)
 688        {
 5689            ResetLastQueryCounters();
 5690            return 0;
 691        }
 692
 2693        BeginSweepTrace(
 2694            request.Start,
 2695            request.End,
 2696            request.Radius,
 2697            request.LayerMask,
 2698            request.ExcludedCollider);
 2699        AddAllSweepHits(request.Start, request.End, segment.Normalized, request.Radius, results);
 2700        Physics3DHitSorter.SortByDistance(results);
 2701        return results.Count;
 702    }
 703
 704    private bool TrySweepSourceBatchRequest(
 705        LSCollider? source,
 706        Vector3d displacement,
 707        PhysicsLayerMask layerMask,
 708        LSCollider? excludedCollider,
 709        bool includeTriggers,
 710        ref LSCollider? preparedSource,
 711        ref Vector3d preparedDisplacement,
 712        out Physics3DHit hit)
 713    {
 14714        PrepareBatchConvexSweepSource(source, displacement, ref preparedSource, ref preparedDisplacement);
 14715        LSCollider prepared = preparedSource!;
 14716        if (!Vector3d.TryGetMagnitude(displacement, out Fixed64 displacementLength)
 14717            || displacementLength <= Fixed64.Epsilon)
 718        {
 6719            ResetLastQueryCounters();
 6720            hit = default;
 6721            return false;
 722        }
 723
 8724        BeginConvexSweepTrace(prepared, layerMask, excludedCollider, includeTriggers);
 8725        return TryFindClosestConvexSweepHit(prepared, displacement, out hit);
 726    }
 727
 728    private int SweepSourceAllBatchRequest(
 729        LSCollider? source,
 730        Vector3d displacement,
 731        PhysicsLayerMask layerMask,
 732        LSCollider? excludedCollider,
 733        bool includeTriggers,
 734        ref LSCollider? preparedSource,
 735        ref Vector3d preparedDisplacement,
 736        SwiftList<Physics3DHit> results)
 737    {
 14738        results.FastClear();
 14739        PrepareBatchConvexSweepSource(source, displacement, ref preparedSource, ref preparedDisplacement);
 14740        LSCollider prepared = preparedSource!;
 14741        if (!Vector3d.TryGetMagnitude(displacement, out Fixed64 displacementLength)
 14742            || displacementLength <= Fixed64.Epsilon)
 743        {
 6744            ResetLastQueryCounters();
 6745            return 0;
 746        }
 747
 8748        BeginConvexSweepTrace(prepared, layerMask, excludedCollider, includeTriggers);
 8749        AddAllConvexSweepHits(prepared, displacement, results);
 8750        Physics3DHitSorter.SortByDistance(results);
 8751        return results.Count;
 752    }
 753
 754    private void PrepareBatchConvexSweepSource(
 755        LSCollider? source,
 756        Vector3d displacement,
 757        ref LSCollider? preparedSource,
 758        ref Vector3d preparedDisplacement)
 759    {
 28760        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 28761        EnsureSourceBelongsToContext(source!);
 762
 28763        if (ReferenceEquals(source, preparedSource) && displacement.Equals(preparedDisplacement))
 2764            return;
 765
 26766        PrepareConvexSweepSource(source!, displacement);
 26767        preparedSource = source;
 26768        preparedDisplacement = displacement;
 26769    }
 770
 771    private bool TryOverlapCircleBatchRequest(PhysicsOverlapCircle3DRequest request, out Physics3DHit hit)
 772    {
 3773        _currentLayerMask = request.LayerMask;
 3774        ResetLastQueryCounters();
 775
 3776        bool found = false;
 3777        Physics3DHit closest = default;
 3778        TraceCircleForClosestHit(
 3779            request.Position,
 3780            request.Radius,
 3781            ref found,
 3782            ref closest);
 783
 3784        hit = closest;
 3785        return found;
 786    }
 787
 788    private int OverlapCircleAllBatchRequest(PhysicsOverlapCircle3DRequest request, SwiftList<Physics3DHit> results)
 789    {
 3790        _currentLayerMask = request.LayerMask;
 3791        ResetLastQueryCounters();
 3792        results.FastClear();
 793
 3794        TraceCircleForAllHits(request.Position, request.Radius, results);
 3795        Physics3DHitSorter.SortByDistance(results);
 3796        return results.Count;
 797    }
 798
 799    private bool TryOverlapCircleInDirectionBatchRequest(
 800        PhysicsOverlapCircleInDirection3DRequest request,
 801        out Physics3DHit hit)
 802    {
 4803        _currentLayerMask = request.LayerMask;
 4804        ResetLastQueryCounters();
 805
 4806        var direction = new Vector2d(
 4807            request.Direction.X,
 4808            request.Direction.Z);
 4809        bool found = false;
 4810        Physics3DHit closest = default;
 4811        TraceCircleForDirectionalHit(
 4812            request.Position,
 4813            request.Radius,
 4814            direction,
 4815            request.MaxDistance,
 4816            ref found,
 4817            ref closest);
 818
 4819        hit = found ? closest : default;
 4820        return found;
 821    }
 822
 823    private bool TryOverlapConeBatchRequest(PhysicsOverlapCone3DRequest request, out Physics3DHit hit) =>
 2824        OverlapCone(
 2825            request.Origin,
 2826            request.Direction,
 2827            request.Length,
 2828            request.EndRadius,
 2829            out hit,
 2830            request.LayerMask);
 831
 832    private static void ValidateOverlapCircleRequests(ReadOnlySpan<PhysicsOverlapCircle3DRequest> requests)
 833    {
 24834        for (int i = 0; i < requests.Length; i++)
 835        {
 10836            SwiftThrowHelper.ThrowIfArgument(
 10837                requests[i].Radius < Fixed64.Zero,
 10838                nameof(requests),
 10839                "3D query radius cannot be negative.");
 840        }
 2841    }
 842
 843    private static void ValidateOverlapCircleRequests(
 844        ReadOnlySpan<PhysicsOverlapCircleInDirection3DRequest> requests)
 845    {
 14846        for (int i = 0; i < requests.Length; i++)
 847        {
 6848            SwiftThrowHelper.ThrowIfArgument(
 6849                requests[i].Radius < Fixed64.Zero,
 6850                nameof(requests),
 6851                "3D query radius cannot be negative.");
 852        }
 1853    }
 854
 855    private int OverlapConeAllBatchRequest(PhysicsOverlapCone3DRequest request, SwiftList<Physics3DHit> results) =>
 2856        OverlapConeAll(
 2857            request.Origin,
 2858            request.Direction,
 2859            request.Length,
 2860            request.EndRadius,
 2861            request.LayerMask,
 2862            results);
 863
 864    private void WriteClosestHit(Span<Physics3DHit> closestHits, int index, Physics3DHit hit, bool found, ref int hitCou
 865    {
 30866        if (found)
 867        {
 14868            closestHits[index] = hit;
 14869            hitCount++;
 14870            AccumulateBatchCounters(1);
 871        }
 872        else
 873        {
 16874            closestHits[index] = default;
 16875            AccumulateBatchCounters(0);
 876        }
 16877    }
 878
 879    private void AppendRange(
 880        SwiftList<Physics3DHit> hits,
 881        Span<PhysicsQueryHitRange> ranges,
 882        int index,
 883        int count)
 884    {
 26885        int start = hits.Count;
 26886        if (count > 0)
 12887            hits.AddRange(_batch3DHits.AsReadOnlySpan());
 888
 26889        ranges[index] = new PhysicsQueryHitRange(start, count);
 26890        AccumulateBatchCounters(count);
 26891    }
 892
 893    private void ResetBatchCounters(int requestCount)
 894    {
 479895        LastBatchRequestCount = requestCount;
 479896        LastBatchHitCount = 0;
 479897        LastBatchCandidateCount = 0;
 479898    }
 899
 900    private void AccumulateBatchCounters(int hitCount)
 901    {
 901902        LastBatchHitCount += hitCount;
 901903        LastBatchCandidateCount += LastQueryCandidateCount;
 901904    }
 905
 906    private static void ValidateClosestBatchOutput(int requestCount, Span<Physics3DHit> closestHits)
 907    {
 226908        SwiftThrowHelper.ThrowIfArgument(
 226909            closestHits.Length < requestCount,
 226910            nameof(closestHits),
 226911            "Closest-hit output span must contain at least one slot per request.");
 225912    }
 913
 914    private static void ValidateRangeBatchOutput(int requestCount, Span<PhysicsQueryHitRange> ranges)
 915    {
 225916        SwiftThrowHelper.ThrowIfArgument(
 225917            ranges.Length < requestCount,
 225918            nameof(ranges),
 225919            "Range output span must contain at least one slot per request.");
 225920    }
 921}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/3D/GravitasQuery3DService.Circle.cs

#LineLine coverage
 1//=======================================================================
 2// GravitasQuery3DService.Circle.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 Gravitas.Support;
 13using GridForge.Grids;
 14using GridForge.Utility;
 15using SwiftCollections;
 16
 17namespace Gravitas.Queries;
 18
 19/// <summary>
 20/// Owns 3D X/Z circle overlap query behavior for one <see cref="GravitasWorldContext"/>.
 21/// </summary>
 22public sealed partial class GravitasQuery3DService
 23{
 24    /// <summary>
 25    /// Finds the closest collider whose complete X/Z projection overlaps the supplied circle.
 26    /// The query position's Y component does not affect classification.
 27    /// </summary>
 28    public bool OverlapCircle(
 29        Vector3d position,
 30        Fixed64 radius,
 31        out Physics3DHit raycastHit,
 32        PhysicsLayerMask layerMask)
 33    {
 934        SwiftThrowHelper.ThrowIfArgument(
 935            radius < Fixed64.Zero,
 936            nameof(radius),
 937            "3D query radius cannot be negative.");
 38
 839        _currentLayerMask = layerMask;
 840        ResetLastQueryCounters();
 41
 842        Physics3DHit closestHit = default;
 843        bool found = false;
 44
 845        TraceCircleForClosestHit(position, radius, ref found, ref closestHit);
 46
 847        raycastHit = closestHit;
 848        _context.Diagnostics.EmitCircleQuery(
 849            position,
 850            radius,
 851            Vector3d.Zero,
 852            Fixed64.Zero,
 853            layerMask.Bits,
 854            found,
 855            found ? 1 : 0,
 856            closestHit);
 57
 858        return found;
 59    }
 60
 61    /// <summary>
 62    /// Finds the closest projected-circle overlap whose exact separation lies in the supplied X/Z
 63    /// direction and whose rounded distance is within the supplied limit. Containment is admitted in
 64    /// every direction, and the query position's Y component is ignored.
 65    /// </summary>
 66    public bool OverlapCircleInDirection(
 67        Vector3d position,
 68        Fixed64 radius,
 69        Vector3d direction,
 70        out Physics3DHit raycastHit,
 71        Fixed64 maxDistance,
 72        PhysicsLayerMask layerMask)
 73    {
 1274        SwiftThrowHelper.ThrowIfArgument(
 1275            radius < Fixed64.Zero,
 1276            nameof(radius),
 1277            "3D query radius cannot be negative.");
 78
 1179        _currentLayerMask = layerMask;
 1180        ResetLastQueryCounters();
 81
 1182        var planarDirection = new Vector2d(direction.X, direction.Z);
 1183        Vector2d normalizedPlanarDirection = Vector2d.GetNormalized(planarDirection);
 1184        var normalizedDirection = new Vector3d(
 1185            normalizedPlanarDirection.X,
 1186            Fixed64.Zero,
 1187            normalizedPlanarDirection.Y);
 1188        Physics3DHit closestHit = default;
 1189        bool found = false;
 90
 1191        TraceCircleForDirectionalHit(
 1192            position,
 1193            radius,
 1194            planarDirection,
 1195            maxDistance,
 1196            ref found,
 1197            ref closestHit);
 98
 1199        raycastHit = closestHit;
 11100        _context.Diagnostics.EmitCircleQuery(
 11101            position,
 11102            radius,
 11103            normalizedDirection,
 11104            maxDistance,
 11105            layerMask.Bits,
 11106            found,
 11107            found ? 1 : 0,
 11108            closestHit);
 109
 11110        return found;
 111    }
 112
 113    /// <summary>
 114    /// Finds all colliders whose complete X/Z projections overlap the supplied circle. The query
 115    /// position's Y component does not affect classification.
 116    /// </summary>
 117    public int OverlapCircleAll(
 118        Vector3d position,
 119        Fixed64 radius,
 120        PhysicsLayerMask layerMask,
 121        SwiftList<Physics3DHit> results)
 122    {
 15123        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 15124        SwiftThrowHelper.ThrowIfArgument(
 15125            radius < Fixed64.Zero,
 15126            nameof(radius),
 15127            "3D query radius cannot be negative.");
 128
 14129        _currentLayerMask = layerMask;
 14130        ResetLastQueryCounters();
 131
 14132        results.FastClear();
 133
 14134        TraceCircleForAllHits(position, radius, results);
 135
 14136        Physics3DHitSorter.SortByDistance(results);
 14137        Physics3DHit firstHit = results.Count > 0 ? results[0] : default;
 14138        _context.Diagnostics.EmitCircleQuery(
 14139            position,
 14140            radius,
 14141            Vector3d.Zero,
 14142            Fixed64.Zero,
 14143            layerMask.Bits,
 14144            results.Count > 0,
 14145            results.Count,
 14146            firstHit);
 147
 14148        return results.Count;
 149    }
 150
 151    internal int OverlapSphereAgainstStaticAll(
 152        Vector3d position,
 153        Fixed64 radius,
 154        PhysicsLayerMask layerMask,
 155        SwiftList<Physics3DHit> results,
 156        LSCollider? excludedCollider = null,
 157        bool includeTriggers = true)
 158    {
 343159        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 160
 343161        results.FastClear();
 343162        if (radius <= Fixed64.Zero)
 163        {
 1164            ResetLastQueryCounters();
 1165            return 0;
 166        }
 167
 342168        _currentLayerMask = layerMask;
 342169        _currentExcludedCollider = excludedCollider;
 342170        _currentIncludeTriggers = includeTriggers;
 342171        _currentStaticSweepTargetsOnly = true;
 342172        NextCircleVersion();
 342173        ResetLastQueryCounters();
 342174        _redundantColliderCheck.Clear();
 342175        _redundantVoxelCheck.Clear();
 176
 342177        Vector3d min = new(position.X - radius, position.Y - radius, position.Z - radius);
 342178        Vector3d max = new(position.X + radius, position.Y + radius, position.Z + radius);
 342179        GridTracer.GetCoveredVoxelsInto(_context.World, min, max, _coveredVoxels, _traceScratch);
 488376180        for (int i = 0; i < _coveredVoxels.Count; i++)
 181        {
 243846182            Voxel voxel = _coveredVoxels[i];
 243846183            if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 184                continue;
 185
 30325186            ProcessPartitionForAllSphereHits(partition!, position, radius, results);
 187        }
 188
 342189        Physics3DHitSorter.SortByDistance(results);
 342190        return results.Count;
 191    }
 192
 193    private void ProcessPartitionForAllSphereHits(
 194        PhysicsPartition partition,
 195        Vector3d position,
 196        Fixed64 radius,
 197        SwiftList<Physics3DHit> results)
 198    {
 30325199        ProcessColliderListForAllSphereHits(partition.ContainedKinematicObjects, position, radius, results);
 30325200        ProcessColliderListForAllSphereHits(partition.ContainedStaticObjects, position, radius, results);
 30325201    }
 202
 203    private void ProcessColliderListForAllSphereHits(
 204        SwiftSparseSet? colliderIds,
 205        Vector3d position,
 206        Fixed64 radius,
 207        SwiftList<Physics3DHit> results)
 208    {
 60650209        if (colliderIds == null)
 35464210            return;
 211
 100924212        for (int i = colliderIds.Count - 1; i >= 0; i--)
 25276213            if (TryBuildOverlapSphereHit(colliderIds.DenseKeys[i], position, radius, out Physics3DHit hitInfo))
 63214                results.Add(hitInfo);
 25186215    }
 216
 217    private bool TryBuildOverlapSphereHit(int colliderId, Vector3d position, Fixed64 radius, out Physics3DHit hit)
 218    {
 25276219        hit = default;
 25276220        if (!_context.Physics.TryGetColliderById(colliderId, out LSCollider? current))
 27221            return false;
 222
 25249223        LSCollider collider = current!;
 25249224        if (ReferenceEquals(collider, _currentExcludedCollider)
 25249225            || (_currentExcludedCollider != null
 25249226                && _context.Constraints3D.ShouldExcludeLinkedCollision(_currentExcludedCollider, collider))
 25249227            || !_currentLayerMask.Includes(collider.Layer)
 25249228            || collider.CircleQueryVersion == CircleVersion
 25249229            || (!_currentIncludeTriggers && collider.IsTrigger)
 25249230            || (_currentStaticSweepTargetsOnly && !IsStaticStyleSweepTarget(collider)))
 231        {
 25183232            return false;
 233        }
 234
 66235        collider.CircleQueryVersion = CircleVersion;
 66236        LastQueryCandidateCount++;
 237
 66238        Fixed64 broadDistance = collider.ScaledRadius + radius;
 66239        if ((collider.Center - position).MagnitudeSquared > broadDistance * broadDistance)
 1240            return false;
 241
 65242        return TryBuildSurfaceOverlapHit(
 65243            collider,
 65244            position,
 65245            radius,
 65246            out hit);
 247    }
 248
 249    private void TraceCircleForClosestHit(
 250        Vector3d position,
 251        Fixed64 radius,
 252        ref bool found,
 253        ref Physics3DHit closestHit)
 254    {
 11255        GetPlanarCircleCandidates(position, radius);
 44256        for (int i = 0; i < _planarCircleCandidates.Count; i++)
 257        {
 11258            if (!TryBuildOverlapHit(
 11259                    _planarCircleCandidates[i],
 11260                    position,
 11261                    radius,
 11262                    out Physics3DHit hitInfo,
 11263                    out _)
 11264                || !PhysicsHitSelectionPolicy.ShouldReplace(hitInfo, found, closestHit))
 265                continue;
 266
 8267            found = true;
 8268            closestHit = hitInfo;
 269        }
 11270    }
 271
 272    private void TraceCircleForDirectionalHit(
 273        Vector3d position,
 274        Fixed64 radius,
 275        Vector2d direction,
 276        Fixed64 maxDistance,
 277        ref bool found,
 278        ref Physics3DHit closestHit)
 279    {
 15280        if (direction == Vector2d.Zero)
 3281            return;
 282
 12283        GetPlanarCircleCandidates(position, radius);
 56284        for (int i = 0; i < _planarCircleCandidates.Count; i++)
 285        {
 16286            if (!TryBuildOverlapHit(
 16287                    _planarCircleCandidates[i],
 16288                    position,
 16289                    radius,
 16290                    out Physics3DHit hitInfo,
 16291                    out ProjectedSurfaceRelation relation)
 16292                || hitInfo.Distance > maxDistance
 16293                || (!relation.IsContained
 16294                    && WideGeometry.GetDifferenceDotProduct2D(
 16295                        relation.Direction.X,
 16296                        Fixed64.Zero,
 16297                        relation.Direction.Y,
 16298                        Fixed64.Zero,
 16299                        direction.X,
 16300                        Fixed64.Zero,
 16301                        direction.Y,
 16302                        Fixed64.Zero).Sign <= 0)
 16303                || !PhysicsHitSelectionPolicy.ShouldReplace(hitInfo, found, closestHit))
 304            {
 305                continue;
 306            }
 307
 9308            found = true;
 9309            closestHit = hitInfo;
 310        }
 12311    }
 312
 313    private void TraceCircleForAllHits(Vector3d position, Fixed64 radius, SwiftList<Physics3DHit> results)
 314    {
 17315        GetPlanarCircleCandidates(position, radius);
 82316        for (int i = 0; i < _planarCircleCandidates.Count; i++)
 24317            if (TryBuildOverlapHit(
 24318                    _planarCircleCandidates[i],
 24319                    position,
 24320                    radius,
 24321                    out Physics3DHit hitInfo,
 24322                    out _))
 21323                results.Add(hitInfo);
 17324    }
 325
 326    private void GetPlanarCircleCandidates(Vector3d position, Fixed64 radius)
 327    {
 40328        var center = new Vector2d(position.X, position.Z);
 40329        _context.Collisions.QueryPlanarColliderCandidates(
 40330            DynamicCcdCandidateIndex2D.CreateBoundsBetween(
 40331                center,
 40332                center,
 40333                radius),
 40334            _planarCircleCandidates);
 40335    }
 336
 337    private bool TryBuildOverlapHit(
 338        int colliderId,
 339        Vector3d position,
 340        Fixed64 radius,
 341        out Physics3DHit raycastHit,
 342        out ProjectedSurfaceRelation relation)
 343    {
 51344        raycastHit = default;
 51345        relation = default;
 51346        SwiftThrowHelper.ThrowIfTrue(
 51347            !_context.Physics.TryGetColliderById(colliderId, out LSCollider? current),
 51348            nameof(GravitasQuery3DService),
 51349            "Planar query index contained an unregistered collider.");
 51350        LSCollider collider = current!;
 51351        if (!_currentLayerMask.Includes(collider.Layer))
 2352            return false;
 353
 49354        LastQueryCandidateCount++;
 355
 49356        return TryBuildPlanarOverlapHit(
 49357            collider,
 49358            position,
 49359            radius,
 49360            out raycastHit,
 49361            out relation);
 362    }
 363
 364    private static bool TryBuildPlanarOverlapHit(
 365        LSCollider collider,
 366        Vector3d position,
 367        Fixed64 radius,
 368        out Physics3DHit hit,
 369        out ProjectedSurfaceRelation relation)
 370    {
 49371        if (!ColliderPlanarProjection.TryGetRelation(
 49372                collider,
 49373                new Vector2d(position.X, position.Z),
 49374                radius,
 49375                out relation))
 376        {
 4377            hit = default;
 4378            return false;
 379        }
 380
 45381        hit = new Physics3DHit(
 45382            collider,
 45383            new ContactAnchor(relation.ContactAnchor),
 45384            relation.OutwardNormal,
 45385            relation.Distance,
 45386            new Vector3d(
 45387                relation.Offset.X,
 45388                Fixed64.Zero,
 45389                relation.Offset.Y));
 45390        return true;
 391    }
 392
 393    internal static bool TryBuildSurfaceOverlapHit(
 394        LSCollider collider,
 395        Vector3d position,
 396        Fixed64 radius,
 397        out Physics3DHit hit)
 398    {
 399        ContactAnchor anchor;
 400        Vector3d toPoint;
 401        Vector3d normal;
 68402        if (collider is LSCuboidCollider cuboid)
 403        {
 4404            anchor = new ContactAnchor(
 4405                cuboid.OrientedBox.GetClosestPointAnchor(position));
 4406            if (!anchor.TryGetOffsetFrom(position, out toPoint))
 407            {
 1408                hit = default;
 1409                return false;
 410            }
 3411            normal = cuboid.OrientedBox.GetNearestFaceNormal(position);
 412        }
 413        else
 414        {
 64415            Vector3d point = GetClosestSurfacePoint(collider, position);
 64416            if (!Vector3d.TrySubtract(point, position, out toPoint))
 417            {
 1418                hit = default;
 1419                return false;
 420            }
 63421            anchor = ContactAnchor.FromWorldPoint(point);
 63422            normal = collider.GetNormalAtPoint(point);
 423        }
 424
 66425        if (!Vector3d.TryGetMagnitude(toPoint, out Fixed64 distance)
 66426            || distance > radius)
 427        {
 3428            hit = default;
 3429            return false;
 430        }
 431
 63432        hit = new Physics3DHit(
 63433            collider,
 63434            anchor,
 63435            normal,
 63436            distance,
 63437            toPoint);
 63438        return true;
 439    }
 440
 441    private static Vector3d GetClosestSurfacePoint(LSCollider collider, Vector3d position)
 442    {
 522443        if (position == collider.Center && collider is not LSMeshCollider)
 226444            return collider.Center + Vector3d.Right * collider.ScaledRadius;
 445
 296446        return collider.ClosestPointOnSurface(position);
 447    }
 448}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/3D/GravitasQuery3DService.Cone.cs

#LineLine coverage
 1//=======================================================================
 2// GravitasQuery3DService.Cone.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 Gravitas.Support;
 13using GridForge.Grids;
 14using GridForge.Utility;
 15using SwiftCollections;
 16using SwiftCollections.Query;
 17
 18namespace Gravitas.Queries;
 19
 20/// <content>
 21/// Owns apex-origin 3D cone-volume overlap query behavior.
 22/// </content>
 23public sealed partial class GravitasQuery3DService
 24{
 25    /// <summary>
 26    /// Finds the closest collider whose surface intersects an apex-origin
 27    /// directional cone volume.
 28    /// </summary>
 29    public bool OverlapCone(
 30        Vector3d origin,
 31        Vector3d direction,
 32        Fixed64 length,
 33        Fixed64 endRadius,
 34        out Physics3DHit hit,
 35        PhysicsLayerMask layerMask)
 36    {
 2837        Vector3d normalizedDirection = ValidateConeQuery(origin, direction, length, endRadius, out Vector3d end);
 2438        _currentLayerMask = layerMask;
 2439        NextCircleVersion();
 2440        ResetLastQueryCounters();
 2441        _redundantColliderCheck.Clear();
 2442        _redundantVoxelCheck.Clear();
 43
 2444        bool found = false;
 2445        Physics3DHit closestHit = default;
 2446        Fixed64 closestDistance = Fixed64.MaxValue;
 2447        TraceConeForClosestHit(
 2448            origin,
 2449            end,
 2450            normalizedDirection,
 2451            length,
 2452            endRadius,
 2453            ref found,
 2454            ref closestHit,
 2455            ref closestDistance);
 56
 2457        hit = closestHit;
 2458        _context.Diagnostics.EmitRayQuery(
 2459            origin,
 2460            end,
 2461            endRadius,
 2462            layerMask.Bits,
 2463            found,
 2464            found ? 1 : 0,
 2465            closestHit);
 2466        return found;
 67    }
 68
 69    /// <summary>
 70    /// Writes all colliders whose surfaces intersect an apex-origin
 71    /// directional cone volume into caller-owned storage.
 72    /// </summary>
 73    public int OverlapConeAll(
 74        Vector3d origin,
 75        Vector3d direction,
 76        Fixed64 length,
 77        Fixed64 endRadius,
 78        PhysicsLayerMask layerMask,
 79        SwiftList<Physics3DHit> results)
 80    {
 21781        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 21782        Vector3d normalizedDirection = ValidateConeQuery(origin, direction, length, endRadius, out Vector3d end);
 21783        _currentLayerMask = layerMask;
 21784        NextCircleVersion();
 21785        ResetLastQueryCounters();
 21786        results.FastClear();
 21787        _redundantColliderCheck.Clear();
 21788        _redundantVoxelCheck.Clear();
 89
 21790        TraceConeForAllHits(origin, end, normalizedDirection, length, endRadius, results);
 21791        Physics3DHitSorter.SortByDistance(results);
 92
 21793        _context.Diagnostics.EmitRayQuery(
 21794            origin,
 21795            end,
 21796            endRadius,
 21797            layerMask.Bits,
 21798            results.Count > 0,
 21799            results.Count,
 217100            results.Count > 0 ? results[0] : default);
 217101        return results.Count;
 102    }
 103
 104    private void TraceConeForClosestHit(
 105        Vector3d origin,
 106        Vector3d baseCenter,
 107        Vector3d direction,
 108        Fixed64 length,
 109        Fixed64 endRadius,
 110        ref bool found,
 111        ref Physics3DHit closestHit,
 112        ref Fixed64 closestDistance)
 113    {
 24114        GetConeQueryBounds(origin, baseCenter, direction, endRadius, out Vector3d min, out Vector3d max);
 24115        GridTracer.GetCoveredVoxelsInto(_context.World, min, max, _coveredVoxels, _traceScratch);
 7762116        for (int i = 0; i < _coveredVoxels.Count; i++)
 117        {
 3857118            Voxel voxel = _coveredVoxels[i];
 3857119            if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 120                continue;
 121
 1175122            ProcessConePartitionForClosestHit(
 1175123                partition!,
 1175124                origin,
 1175125                baseCenter,
 1175126                direction,
 1175127                length,
 1175128                endRadius,
 1175129                ref found,
 1175130                ref closestHit,
 1175131                ref closestDistance);
 132        }
 24133    }
 134
 135    private void TraceConeForAllHits(
 136        Vector3d origin,
 137        Vector3d baseCenter,
 138        Vector3d direction,
 139        Fixed64 length,
 140        Fixed64 endRadius,
 141        SwiftList<Physics3DHit> results)
 142    {
 217143        GetConeQueryBounds(origin, baseCenter, direction, endRadius, out Vector3d min, out Vector3d max);
 217144        GridTracer.GetCoveredVoxelsInto(_context.World, min, max, _coveredVoxels, _traceScratch);
 75652145        for (int i = 0; i < _coveredVoxels.Count; i++)
 146        {
 37609147            Voxel voxel = _coveredVoxels[i];
 37609148            if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 149                continue;
 150
 11658151            ProcessConePartitionForAllHits(partition!, origin, baseCenter, direction, length, endRadius, results);
 152        }
 217153    }
 154
 155    private void ProcessConePartitionForClosestHit(
 156        PhysicsPartition partition,
 157        Vector3d origin,
 158        Vector3d baseCenter,
 159        Vector3d direction,
 160        Fixed64 length,
 161        Fixed64 endRadius,
 162        ref bool found,
 163        ref Physics3DHit closestHit,
 164        ref Fixed64 closestDistance)
 165    {
 1175166        ProcessConeColliderListForClosestHit(partition.ContainedDynamicObjects, origin, baseCenter, direction, length, e
 1175167        ProcessConeColliderListForClosestHit(partition.ContainedKinematicObjects, origin, baseCenter, direction, length,
 1175168        ProcessConeColliderListForClosestHit(partition.ContainedStaticObjects, origin, baseCenter, direction, length, en
 1175169    }
 170
 171    private void ProcessConePartitionForAllHits(
 172        PhysicsPartition partition,
 173        Vector3d origin,
 174        Vector3d baseCenter,
 175        Vector3d direction,
 176        Fixed64 length,
 177        Fixed64 endRadius,
 178        SwiftList<Physics3DHit> results)
 179    {
 11658180        ProcessConeColliderListForAllHits(partition.ContainedDynamicObjects, origin, baseCenter, direction, length, endR
 11658181        ProcessConeColliderListForAllHits(partition.ContainedKinematicObjects, origin, baseCenter, direction, length, en
 11658182        ProcessConeColliderListForAllHits(partition.ContainedStaticObjects, origin, baseCenter, direction, length, endRa
 11658183    }
 184
 185    private void ProcessConeColliderListForClosestHit(
 186        SwiftSparseSet? colliderIds,
 187        Vector3d origin,
 188        Vector3d baseCenter,
 189        Vector3d direction,
 190        Fixed64 length,
 191        Fixed64 endRadius,
 192        ref bool found,
 193        ref Physics3DHit closestHit,
 194        ref Fixed64 closestDistance)
 195    {
 3525196        if (colliderIds == null)
 2350197            return;
 198
 4850199        for (int i = colliderIds.Count - 1; i >= 0; i--)
 200        {
 1250201            if (!TryBuildOverlapConeHit(colliderIds.DenseKeys[i], origin, baseCenter, direction, length, endRadius, out 
 1250202                || !PhysicsHitSelectionPolicy.ShouldReplace(hit, found, closestHit))
 203            {
 204                continue;
 205            }
 206
 17207            found = true;
 17208            closestHit = hit;
 17209            closestDistance = hit.Distance;
 210        }
 1175211    }
 212
 213    private void ProcessConeColliderListForAllHits(
 214        SwiftSparseSet? colliderIds,
 215        Vector3d origin,
 216        Vector3d baseCenter,
 217        Vector3d direction,
 218        Fixed64 length,
 219        Fixed64 endRadius,
 220        SwiftList<Physics3DHit> results)
 221    {
 34974222        if (colliderIds == null)
 23292223            return;
 224
 61956225        for (int i = colliderIds.Count - 1; i >= 0; i--)
 226        {
 19296227            if (TryBuildOverlapConeHit(colliderIds.DenseKeys[i], origin, baseCenter, direction, length, endRadius, out P
 639228                results.Add(hit);
 229        }
 11682230    }
 231
 232    private bool TryBuildOverlapConeHit(
 233        int colliderId,
 234        Vector3d origin,
 235        Vector3d baseCenter,
 236        Vector3d direction,
 237        Fixed64 length,
 238        Fixed64 endRadius,
 239        out Physics3DHit hit)
 240    {
 20546241        hit = default;
 20546242        if (!_context.Physics.TryGetColliderById(colliderId, out LSCollider? current))
 54243            return false;
 244
 20492245        LSCollider collider = current!;
 20492246        if (!_currentLayerMask.Includes(collider.Layer)
 20492247            || collider.CircleQueryVersion == CircleVersion
 20492248            || !_redundantColliderCheck.Add(collider.Id))
 249        {
 19822250            return false;
 251        }
 252
 670253        collider.CircleQueryVersion = CircleVersion;
 670254        LastQueryCandidateCount++;
 670255        return TryBuildConeHitForCollider(collider, origin, baseCenter, direction, length, endRadius, out hit);
 256    }
 257
 258    private bool TryBuildConeHitForCollider(
 259        LSCollider collider,
 260        Vector3d origin,
 261        Vector3d baseCenter,
 262        Vector3d direction,
 263        Fixed64 length,
 264        Fixed64 endRadius,
 265        out Physics3DHit hit)
 266    {
 676267        if (collider is LSCompoundCollider compound)
 3268            return TryBuildConeHitForCompound(compound, origin, baseCenter, direction, length, endRadius, out hit);
 269
 673270        if (collider is LSMeshCollider { Mode: MeshColliderMode.Concave } concaveMesh)
 219271            return TryBuildConeHitForConcaveMesh(concaveMesh, origin, baseCenter, direction, length, endRadius, out hit)
 272
 454273        bool supportedConvexTarget = ConvexColliderSupport.IsSupported(collider);
 454274        if (supportedConvexTarget
 454275            && !ConvexColliderSupport.IntersectsConeVolume(collider, origin, baseCenter, direction, endRadius))
 276        {
 8277            hit = default;
 8278            return false;
 279        }
 280
 446281        Vector3d axisPoint = GetClosestPointOnConeAxis(origin, direction, length, collider.Center);
 446282        Vector3d point = GetClosestSurfacePoint(collider, axisPoint);
 446283        if (!IsPointInsideConeVolume(origin, direction, length, endRadius, point, out Fixed64 axialDistance))
 284        {
 8285            Vector3d supportTowardAxis = collider.Center == axisPoint
 8286                ? GetClosestSurfacePoint(collider, origin)
 8287                : GetClosestSurfacePoint(collider, axisPoint);
 8288            if (!IsPointInsideConeVolume(origin, direction, length, endRadius, supportTowardAxis, out axialDistance))
 289            {
 5290                if (!supportedConvexTarget)
 291                {
 1292                    hit = default;
 1293                    return false;
 294                }
 295
 4296                point = GetClosestSurfacePoint(collider, origin);
 4297                axialDistance = FixedMath.Min(
 4298                    Vector3d.ProjectNonNegativeDifferenceParameter(point, origin, direction),
 4299                    length);
 300            }
 301            else
 302            {
 3303                point = supportTowardAxis;
 304            }
 305        }
 306
 445307        Vector3d toPoint = point - origin;
 445308        Vector3d normal = collider.GetNormalAtPoint(point);
 445309        hit = new Physics3DHit(collider, point, normal, axialDistance, toPoint);
 445310        return true;
 311    }
 312
 313    private bool TryBuildConeHitForConcaveMesh(
 314        LSMeshCollider mesh,
 315        Vector3d origin,
 316        Vector3d baseCenter,
 317        Vector3d direction,
 318        Fixed64 length,
 319        Fixed64 endRadius,
 320        out Physics3DHit hit)
 321    {
 219322        GetConeQueryBounds(origin, baseCenter, direction, endRadius, out Vector3d min, out Vector3d max);
 219323        mesh.GetTrianglesInBounds(new FixedBoundVolume(min, max), _meshTriangleCandidates);
 219324        LastMeshTriangleCandidateCount += _meshTriangleCandidates.Count;
 325
 219326        bool found = false;
 219327        Fixed64 bestDistance = Fixed64.MaxValue;
 219328        int bestTriangleIndex = int.MaxValue;
 219329        Physics3DHit best = default;
 219330        var queryOriginAnchor = new FixedPointAnchor(
 219331            origin,
 219332            FixedQuaternion.Identity,
 219333            Vector3d.Zero);
 219334        if (!queryOriginAnchor.TryGetLocalPointIn(
 219335                mesh.Mesh.Origin,
 219336                mesh.Mesh.Rotation,
 219337                out Vector3d localOrigin))
 338        {
 1339            hit = default;
 1340            return false;
 341        }
 218342        Vector3d localDirection =
 218343            mesh.Mesh.Rotation.Inverse().Rotate(direction);
 344
 880345        for (int i = 0; i < _meshTriangleCandidates.Count; i++)
 346        {
 222347            int triangleIndex = _meshTriangleCandidates[i];
 222348            mesh.Mesh.GetLocalTriangleVertices(
 222349                triangleIndex,
 222350                out Vector3d first,
 222351                out Vector3d second,
 222352                out Vector3d third);
 222353            Vector3d normal = mesh.Mesh.GetFaceNormalWorld(triangleIndex);
 222354            if (!new FixedTriangle(first, second, third).TryGetFiniteConeIntersectionMinimumAxialPoint(
 222355                    localOrigin,
 222356                    localDirection,
 222357                    length,
 222358                    endRadius,
 222359                    out Vector3d localPoint))
 360            {
 361                continue;
 362            }
 363
 220364            FixedPointAnchor pointAnchor =
 220365                mesh.Mesh.CreatePointAnchor(localPoint);
 220366            Fixed64 axialDistance = FixedMath.Min(
 220367                pointAnchor.ProjectNonNegativeOffsetFrom(
 220368                    queryOriginAnchor,
 220369                    direction),
 220370                length);
 371
 220372            if (found
 220373                && (axialDistance > bestDistance
 220374                    || (axialDistance == bestDistance && triangleIndex >= bestTriangleIndex)))
 375            {
 376                continue;
 377            }
 378
 218379            _ = pointAnchor.TryGetOffsetFrom(
 218380                queryOriginAnchor,
 218381                out Vector3d toPoint);
 218382            best = new Physics3DHit(
 218383                mesh,
 218384                new ContactAnchor(pointAnchor),
 218385                normal,
 218386                axialDistance,
 218387                toPoint);
 218388            bestDistance = axialDistance;
 218389            bestTriangleIndex = triangleIndex;
 218390            found = true;
 391        }
 392
 218393        hit = best;
 218394        return found;
 395    }
 396
 397    private bool TryBuildConeHitForCompound(
 398        LSCompoundCollider compound,
 399        Vector3d origin,
 400        Vector3d baseCenter,
 401        Vector3d direction,
 402        Fixed64 length,
 403        Fixed64 endRadius,
 404        out Physics3DHit hit)
 405    {
 3406        bool found = false;
 3407        Physics3DHit best = default;
 18408        for (int i = 0; i < compound.PartCount; i++)
 409        {
 6410            if (!TryBuildConeHitForCollider(compound.GetPartCollider(i), origin, baseCenter, direction, length, endRadiu
 6411                || !PhysicsHitSelectionPolicy.ShouldReplace(partHit, found, best))
 412            {
 413                continue;
 414            }
 415
 2416            best = new Physics3DHit(compound, partHit.Anchor, partHit.Normal, partHit.Distance, partHit.Direction);
 2417            found = true;
 418        }
 419
 3420        hit = found ? best : default;
 3421        return found;
 422    }
 423
 424    private static bool IsPointInsideConeVolume(
 425        Vector3d origin,
 426        Vector3d direction,
 427        Fixed64 length,
 428        Fixed64 endRadius,
 429        Vector3d point,
 430        out Fixed64 axialDistance)
 431    {
 454432        if (!FixedSegment.ContainsPointInFiniteCone(
 454433                point,
 454434                origin,
 454435                direction,
 454436                length,
 454437                endRadius))
 438        {
 13439            axialDistance = default;
 13440            return false;
 441        }
 442
 441443        axialDistance = Vector3d.ProjectNonNegativeDifferenceParameter(point, origin, direction);
 441444        return true;
 445    }
 446
 447    private static Vector3d GetClosestPointOnConeAxis(
 448        Vector3d origin,
 449        Vector3d direction,
 450        Fixed64 length,
 451        Vector3d point)
 452    {
 446453        Fixed64 axial = FixedMath.Min(
 446454            Vector3d.ProjectNonNegativeDifferenceParameter(point, origin, direction),
 446455            length);
 446456        return new FixedRay(origin, direction).GetPoint(axial);
 457    }
 458
 459    private static void GetConeQueryBounds(
 460        Vector3d origin,
 461        Vector3d baseCenter,
 462        Vector3d direction,
 463        Fixed64 endRadius,
 464        out Vector3d min,
 465        out Vector3d max)
 466    {
 460467        ConeGeometry.CreateFiniteConeBounds(origin, baseCenter, direction, endRadius, out min, out max);
 460468    }
 469
 470    private static Vector3d ValidateConeQuery(
 471        Vector3d origin,
 472        Vector3d direction,
 473        Fixed64 length,
 474        Fixed64 endRadius,
 475        out Vector3d end)
 476    {
 245477        SwiftThrowHelper.ThrowIfArgument(
 245478            direction == Vector3d.Zero,
 245479            nameof(direction),
 245480            "Cone query direction must be non-zero.");
 244481        SwiftThrowHelper.ThrowIfArgument(
 244482            length <= Fixed64.Zero,
 244483            nameof(length),
 244484            "Cone query length must be greater than zero.");
 243485        SwiftThrowHelper.ThrowIfArgument(
 243486            endRadius <= Fixed64.Zero,
 243487            nameof(endRadius),
 243488            "Cone query end radius must be greater than zero.");
 489
 243490        Vector3d normalizedDirection = direction.Normalized;
 243491        SwiftThrowHelper.ThrowIfArgument(
 243492            !new FixedRay(origin, normalizedDirection).TryGetPoint(length, out end),
 243493            nameof(length),
 243494            "Cone query endpoint must be representable without fixed-point saturation.");
 241495        return normalizedDirection;
 496    }
 497}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/3D/GravitasQuery3DService.Raycast.cs

#LineLine coverage
 1//=======================================================================
 2// GravitasQuery3DService.Raycast.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;
 10using Gravitas.CollisionHandling;
 11using Gravitas.Support;
 12using GridForge.Grids;
 13using GridForge.Spatial;
 14using GridForge.Utility;
 15using SwiftCollections;
 16using System.Runtime.CompilerServices;
 17
 18namespace Gravitas.Queries;
 19
 20/// <summary>
 21/// Owns 3D raycast, swept-sphere, and X/Z circle query buffers for one <see cref="GravitasWorldContext"/>.
 22/// </summary>
 23public sealed partial class GravitasQuery3DService
 24{
 25    private readonly GravitasWorldContext _context;
 508326    private readonly RaycastSegmentWorker _worker = new();
 508327    private readonly SweptSphereQueryWorker _sweepWorker = new();
 508328    private readonly ConvexSweepQueryWorker _convexSweepWorker = new();
 508329    private SwiftList<Vector3d> _bufferIntersectionPoints = new();
 508330    private readonly SwiftList<int> _meshTriangleCandidates = new(16);
 508331    private readonly SwiftList<int> _planarCircleCandidates = new();
 508332    private readonly SwiftHashSet<int> _redundantColliderCheck = new();
 508333    private readonly SwiftHashSet<WorldVoxelIndex> _redundantVoxelCheck = new();
 508334    private readonly SwiftList<Voxel> _coveredVoxels = new();
 508335    private readonly GridTraceScratch _traceScratch = new();
 36
 37    private PhysicsLayerMask _currentLayerMask;
 38    private LSCollider? _currentExcludedCollider;
 39    private LSCollider? _currentSweepSourceCollider;
 40    private bool _currentStaticSweepTargetsOnly;
 41    private bool _currentIncludeTriggers;
 42
 43    /// <summary>
 44    /// Initializes a new raycast service for the supplied context.
 45    /// </summary>
 46    /// <param name="context">The owning world context.</param>
 508347    public GravitasQuery3DService(GravitasWorldContext context)
 48    {
 508349        SwiftThrowHelper.ThrowIfNull(context, nameof(context));
 508350        _context = context;
 508351    }
 52
 53    /// <summary>
 54    /// Gets the owning world context.
 55    /// </summary>
 156    public GravitasWorldContext Context => _context;
 57
 58    /// <summary>
 59    /// Gets the context-local raycast/sweep query version.
 60    /// </summary>
 61    public uint RaycastVersion { get; internal set; }
 62
 63    /// <summary>
 64    /// Gets the context-local partition-traversed sphere/cone deduplication version.
 65    /// </summary>
 66    public uint CircleVersion { get; internal set; }
 67
 68    internal int LastQueryCandidateCount { get; private set; }
 69
 70    internal int LastMeshTriangleCandidateCount { get; private set; }
 71
 72    /// <summary>
 73    /// Resets context-local raycast query buffers.
 74    /// </summary>
 75    public void Reset()
 76    {
 3277        ResetColliderRaycastVersions();
 3278        ResetColliderCircleVersions();
 3279        RaycastVersion = 0;
 3280        CircleVersion = 0;
 3281        ResetLastQueryCounters();
 3282        ResetBatchCounters(0);
 3283        _bufferIntersectionPoints.FastClear();
 3284        _meshTriangleCandidates.FastClear();
 3285        _planarCircleCandidates.FastClear();
 3286        _batch3DHits.FastClear();
 3287        _redundantColliderCheck.Clear();
 3288        _redundantVoxelCheck.Clear();
 3289        _coveredVoxels.FastClear();
 3290        _traceScratch.Clear();
 3291    }
 92
 93    /// <summary>
 94    /// Performs a raycast from an origin in a direction up to a maximum distance.
 95    /// </summary>
 96    public bool Raycast(
 97        Vector3d origin,
 98        Vector3d direction,
 99        Fixed64 maxDistance,
 100        out Physics3DHit raycastHit,
 101        PhysicsLayerMask layerMask)
 102    {
 25103        _currentLayerMask = layerMask;
 25104        if (direction == Vector3d.Zero || maxDistance <= Fixed64.Zero)
 105        {
 3106            ResetLastQueryCounters();
 3107            raycastHit = default;
 3108            return false;
 109        }
 110
 22111        Vector3d rayDirection = direction.Normalized;
 22112        Vector3d requestedDisplacement = rayDirection * maxDistance;
 22113        if (!Vector3d.TryAdd(origin, requestedDisplacement, out Vector3d end))
 114        {
 1115            ResetLastQueryCounters();
 1116            raycastHit = default;
 1117            return false;
 118        }
 119
 21120        BeginRaycastTrace(origin, end);
 21121        bool hit = TryFindClosestHit(origin, end, rayDirection, out raycastHit);
 21122        _context.Diagnostics.EmitRayQuery(
 21123            origin,
 21124            end,
 21125            Fixed64.Zero,
 21126            layerMask.Bits,
 21127            hit,
 21128            hit ? 1 : 0,
 21129            raycastHit);
 21130        return hit;
 131    }
 132
 133    /// <summary>
 134    /// Executes a raycast between two points and writes hits from closest to farthest into caller-owned storage.
 135    /// </summary>
 136    public int RaycastAll(
 137        Vector3d start3d,
 138        Vector3d end3d,
 139        PhysicsLayerMask layerMask,
 140        SwiftList<Physics3DHit> results)
 141    {
 1084142        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 143
 1084144        _currentLayerMask = layerMask;
 1084145        results.FastClear();
 146
 1084147        if (!Vector3d.TrySubtract(end3d, start3d, out Vector3d segment)
 1084148            || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength)
 1084149            || segmentLength == Fixed64.Zero)
 150        {
 75151            ResetLastQueryCounters();
 75152            return 0;
 153        }
 154
 1009155        BeginRaycastTrace(start3d, end3d);
 1009156        AddAllHits(start3d, end3d, segment.Normalized, results);
 1009157        Physics3DHitSorter.SortByDistance(results);
 1009158        _context.Diagnostics.EmitRayQuery(
 1009159            start3d,
 1009160            end3d,
 1009161            Fixed64.Zero,
 1009162            layerMask.Bits,
 1009163            results.Count > 0,
 1009164            results.Count,
 1009165            results.Count > 0 ? results[0] : default);
 1009166        return results.Count;
 167    }
 168
 169    /// <summary>
 170    /// Sweeps a sphere from an origin in a direction up to a maximum distance and returns the closest hit.
 171    /// </summary>
 172    public bool SweepSphere(
 173        Vector3d origin,
 174        Fixed64 radius,
 175        Vector3d direction,
 176        Fixed64 maxDistance,
 177        out Physics3DHit sweepHit,
 178        PhysicsLayerMask layerMask,
 179        LSCollider? excludedCollider = null)
 180    {
 22181        if (direction == Vector3d.Zero || maxDistance <= Fixed64.Zero)
 182        {
 3183            ResetLastQueryCounters();
 3184            sweepHit = default;
 3185            return false;
 186        }
 187
 19188        Vector3d sweepDirection = direction.Normalized;
 19189        Vector3d requestedDisplacement = sweepDirection * maxDistance;
 19190        if (!Vector3d.TryAdd(origin, requestedDisplacement, out Vector3d end))
 191        {
 1192            ResetLastQueryCounters();
 1193            sweepHit = default;
 1194            return false;
 195        }
 18196        bool hit = SweepSphere(origin, end, radius, layerMask, excludedCollider, out sweepHit);
 18197        _context.Diagnostics.EmitRayQuery(
 18198            origin,
 18199            end,
 18200            radius,
 18201            layerMask.Bits,
 18202            hit,
 18203            hit ? 1 : 0,
 18204            sweepHit);
 18205        return hit;
 206    }
 207
 208    /// <summary>
 209    /// Sweeps a sphere between two points and writes hits from closest to farthest into caller-owned storage.
 210    /// </summary>
 211    public int SweepSphereAll(
 212        Vector3d start3d,
 213        Vector3d end3d,
 214        Fixed64 radius,
 215        PhysicsLayerMask layerMask,
 216        SwiftList<Physics3DHit> results,
 217        LSCollider? excludedCollider = null)
 218    {
 7909219        return SweepSphereAllCore(
 7909220            start3d,
 7909221            end3d,
 7909222            radius,
 7909223            layerMask,
 7909224            results,
 7909225            excludedCollider,
 7909226            includeTriggers: true,
 7909227            staticTargetsOnly: false);
 228    }
 229
 230    internal int SweepSphereAgainstStaticAll(
 231        Vector3d start3d,
 232        Vector3d end3d,
 233        Fixed64 radius,
 234        PhysicsLayerMask layerMask,
 235        SwiftList<Physics3DHit> results,
 236        LSCollider? excludedCollider = null,
 237        bool includeTriggers = true)
 238    {
 6565239        return SweepSphereAllCore(
 6565240            start3d,
 6565241            end3d,
 6565242            radius,
 6565243            layerMask,
 6565244            results,
 6565245            excludedCollider,
 6565246            includeTriggers,
 6565247            staticTargetsOnly: true);
 248    }
 249
 250    internal int SweepExactSourceAgainstStaticAll(
 251        LSCollider source,
 252        Vector3d displacement,
 253        PhysicsLayerMask layerMask,
 254        SwiftList<Physics3DHit> results,
 255        LSCollider? excludedCollider = null,
 256        bool includeTriggers = true)
 257    {
 106258        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 106259        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 106260        EnsureSourceBelongsToContext(source);
 106261        PrepareConvexSweepSource(source, displacement);
 106262        return SweepPreparedConvexSourceAll(
 106263            source,
 106264            displacement,
 106265            layerMask,
 106266            results,
 106267            excludedCollider,
 106268            includeTriggers,
 106269            staticTargetsOnly: true);
 270    }
 271
 272    /// <summary>
 273    /// Sweeps a capsule source by <paramref name="displacement"/> and returns the closest 3D target hit.
 274    /// </summary>
 275    public bool SweepCapsule(
 276        LSCapsuleCollider source,
 277        Vector3d displacement,
 278        PhysicsLayerMask layerMask,
 279        out Physics3DHit sweepHit,
 280        LSCollider? excludedCollider = null,
 281        bool includeTriggers = true)
 282    {
 1283        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 1284        return SweepPrimitiveSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers);
 285    }
 286
 287    /// <summary>
 288    /// Writes all 3D targets hit by sweeping a capsule source into caller-owned storage.
 289    /// </summary>
 290    public int SweepCapsuleAll(
 291        LSCapsuleCollider source,
 292        Vector3d displacement,
 293        PhysicsLayerMask layerMask,
 294        SwiftList<Physics3DHit> results,
 295        LSCollider? excludedCollider = null,
 296        bool includeTriggers = true)
 297    {
 1298        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 1299        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 1300        return SweepPrimitiveSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers);
 301    }
 302
 303    /// <summary>
 304    /// Sweeps a cuboid source by <paramref name="displacement"/> and returns the closest 3D target hit.
 305    /// </summary>
 306    public bool SweepCuboid(
 307        LSCuboidCollider source,
 308        Vector3d displacement,
 309        PhysicsLayerMask layerMask,
 310        out Physics3DHit sweepHit,
 311        LSCollider? excludedCollider = null,
 312        bool includeTriggers = true)
 313    {
 6314        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 6315        return SweepPrimitiveSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers);
 316    }
 317
 318    /// <summary>
 319    /// Writes all 3D targets hit by sweeping a cuboid source into caller-owned storage.
 320    /// </summary>
 321    public int SweepCuboidAll(
 322        LSCuboidCollider source,
 323        Vector3d displacement,
 324        PhysicsLayerMask layerMask,
 325        SwiftList<Physics3DHit> results,
 326        LSCollider? excludedCollider = null,
 327        bool includeTriggers = true)
 328    {
 4329        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 4330        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 4331        return SweepPrimitiveSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers);
 332    }
 333
 334    /// <summary>
 335    /// Sweeps a finite-cylinder source by <paramref name="displacement"/> and returns the closest 3D target hit.
 336    /// </summary>
 337    public bool SweepCylinder(
 338        LSCylinderCollider source,
 339        Vector3d displacement,
 340        PhysicsLayerMask layerMask,
 341        out Physics3DHit sweepHit,
 342        LSCollider? excludedCollider = null,
 343        bool includeTriggers = true)
 344    {
 1345        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 1346        return SweepPrimitiveSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers);
 347    }
 348
 349    /// <summary>
 350    /// Writes all 3D targets hit by sweeping a finite-cylinder source into caller-owned storage.
 351    /// </summary>
 352    public int SweepCylinderAll(
 353        LSCylinderCollider source,
 354        Vector3d displacement,
 355        PhysicsLayerMask layerMask,
 356        SwiftList<Physics3DHit> results,
 357        LSCollider? excludedCollider = null,
 358        bool includeTriggers = true)
 359    {
 1360        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 1361        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 1362        return SweepPrimitiveSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers);
 363    }
 364
 365    /// <summary>
 366    /// Sweeps a finite-cone source by <paramref name="displacement"/> and returns the closest 3D target hit.
 367    /// </summary>
 368    public bool SweepCone(
 369        LSConeCollider source,
 370        Vector3d displacement,
 371        PhysicsLayerMask layerMask,
 372        out Physics3DHit sweepHit,
 373        LSCollider? excludedCollider = null,
 374        bool includeTriggers = true)
 375    {
 1376        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 1377        return SweepPrimitiveSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers);
 378    }
 379
 380    /// <summary>
 381    /// Writes all 3D targets hit by sweeping a finite-cone source into caller-owned storage.
 382    /// </summary>
 383    public int SweepConeAll(
 384        LSConeCollider source,
 385        Vector3d displacement,
 386        PhysicsLayerMask layerMask,
 387        SwiftList<Physics3DHit> results,
 388        LSCollider? excludedCollider = null,
 389        bool includeTriggers = true)
 390    {
 1391        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 1392        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 1393        return SweepPrimitiveSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers);
 394    }
 395
 396    /// <summary>
 397    /// Sweeps a convex mesh source by <paramref name="displacement"/> and returns the closest 3D target hit.
 398    /// </summary>
 399    public bool SweepConvexMesh(
 400        LSMeshCollider source,
 401        Vector3d displacement,
 402        PhysicsLayerMask layerMask,
 403        out Physics3DHit sweepHit,
 404        LSCollider? excludedCollider = null,
 405        bool includeTriggers = true)
 406    {
 11407        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 11408        return SweepConvexMeshSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers);
 409    }
 410
 411    /// <summary>
 412    /// Writes all 3D targets hit by sweeping a convex mesh source into caller-owned storage.
 413    /// </summary>
 414    public int SweepConvexMeshAll(
 415        LSMeshCollider source,
 416        Vector3d displacement,
 417        PhysicsLayerMask layerMask,
 418        SwiftList<Physics3DHit> results,
 419        LSCollider? excludedCollider = null,
 420        bool includeTriggers = true)
 421    {
 2422        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 2423        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 2424        return SweepConvexMeshSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers);
 425    }
 426
 427    /// <summary>
 428    /// Sweeps an authored compound source by <paramref name="displacement"/> and returns the closest 3D target hit.
 429    /// </summary>
 430    public bool SweepCompound(
 431        LSCompoundCollider source,
 432        Vector3d displacement,
 433        PhysicsLayerMask layerMask,
 434        out Physics3DHit sweepHit,
 435        LSCollider? excludedCollider = null,
 436        bool includeTriggers = true)
 437    {
 1438        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 1439        return SweepCompoundSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers);
 440    }
 441
 442    /// <summary>
 443    /// Writes all 3D targets hit by sweeping an authored compound source into caller-owned storage.
 444    /// </summary>
 445    public int SweepCompoundAll(
 446        LSCompoundCollider source,
 447        Vector3d displacement,
 448        PhysicsLayerMask layerMask,
 449        SwiftList<Physics3DHit> results,
 450        LSCollider? excludedCollider = null,
 451        bool includeTriggers = true)
 452    {
 1453        SwiftThrowHelper.ThrowIfNull(source, nameof(source));
 1454        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 1455        return SweepCompoundSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers);
 456    }
 457
 458    private bool SweepPrimitiveSource(
 459        LSCollider source,
 460        Vector3d displacement,
 461        PhysicsLayerMask layerMask,
 462        out Physics3DHit sweepHit,
 463        LSCollider? excludedCollider,
 464        bool includeTriggers)
 465    {
 9466        EnsureSourceBelongsToContext(source);
 9467        _convexSweepWorker.PreparePrimitiveSource(source, displacement);
 9468        return SweepPreparedConvexSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTrigger
 469    }
 470
 471    private int SweepPrimitiveSourceAll(
 472        LSCollider source,
 473        Vector3d displacement,
 474        PhysicsLayerMask layerMask,
 475        SwiftList<Physics3DHit> results,
 476        LSCollider? excludedCollider,
 477        bool includeTriggers)
 478    {
 7479        EnsureSourceBelongsToContext(source);
 7480        _convexSweepWorker.PreparePrimitiveSource(source, displacement);
 7481        return SweepPreparedConvexSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers)
 482    }
 483
 484    private bool SweepConvexMeshSource(
 485        LSMeshCollider source,
 486        Vector3d displacement,
 487        PhysicsLayerMask layerMask,
 488        out Physics3DHit sweepHit,
 489        LSCollider? excludedCollider,
 490        bool includeTriggers)
 491    {
 11492        EnsureSourceBelongsToContext(source);
 11493        _convexSweepWorker.PrepareConvexMeshSource(source, displacement);
 10494        return SweepPreparedConvexSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTrigger
 495    }
 496
 497    private int SweepConvexMeshSourceAll(
 498        LSMeshCollider source,
 499        Vector3d displacement,
 500        PhysicsLayerMask layerMask,
 501        SwiftList<Physics3DHit> results,
 502        LSCollider? excludedCollider,
 503        bool includeTriggers)
 504    {
 2505        EnsureSourceBelongsToContext(source);
 2506        _convexSweepWorker.PrepareConvexMeshSource(source, displacement);
 2507        return SweepPreparedConvexSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers)
 508    }
 509
 510    private bool SweepCompoundSource(
 511        LSCompoundCollider source,
 512        Vector3d displacement,
 513        PhysicsLayerMask layerMask,
 514        out Physics3DHit sweepHit,
 515        LSCollider? excludedCollider,
 516        bool includeTriggers)
 517    {
 1518        EnsureSourceBelongsToContext(source);
 1519        _convexSweepWorker.PrepareCompoundSource(source, displacement);
 1520        return SweepPreparedConvexSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTrigger
 521    }
 522
 523    private int SweepCompoundSourceAll(
 524        LSCompoundCollider source,
 525        Vector3d displacement,
 526        PhysicsLayerMask layerMask,
 527        SwiftList<Physics3DHit> results,
 528        LSCollider? excludedCollider,
 529        bool includeTriggers)
 530    {
 1531        EnsureSourceBelongsToContext(source);
 1532        _convexSweepWorker.PrepareCompoundSource(source, displacement);
 1533        return SweepPreparedConvexSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers)
 534    }
 535
 536    private int SweepSphereAllCore(
 537        Vector3d start3d,
 538        Vector3d end3d,
 539        Fixed64 radius,
 540        PhysicsLayerMask layerMask,
 541        SwiftList<Physics3DHit> results,
 542        LSCollider? excludedCollider,
 543        bool includeTriggers,
 544        bool staticTargetsOnly)
 545    {
 14474546        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 547
 14474548        results.FastClear();
 14474549        if (!Vector3d.TrySubtract(end3d, start3d, out Vector3d segment)
 14474550            || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength)
 14474551            || segmentLength <= Fixed64.Epsilon
 14474552            || radius <= Fixed64.Zero)
 553        {
 116554            ResetLastQueryCounters();
 116555            return 0;
 556        }
 557
 14358558        BeginSweepTrace(start3d, end3d, radius, layerMask, excludedCollider, includeTriggers, staticTargetsOnly);
 14358559        AddAllSweepHits(start3d, end3d, segment.Normalized, radius, results);
 14358560        Physics3DHitSorter.SortByDistance(results);
 14358561        _context.Diagnostics.EmitRayQuery(
 14358562            start3d,
 14358563            end3d,
 14358564            radius,
 14358565            layerMask.Bits,
 14358566            results.Count > 0,
 14358567            results.Count,
 14358568            results.Count > 0 ? results[0] : default);
 14358569        return results.Count;
 570    }
 571
 572    private bool SweepPreparedConvexSource(
 573        LSCollider source,
 574        Vector3d displacement,
 575        PhysicsLayerMask layerMask,
 576        out Physics3DHit sweepHit,
 577        LSCollider? excludedCollider,
 578        bool includeTriggers)
 579    {
 20580        sweepHit = default;
 20581        if (!Vector3d.TryGetMagnitude(displacement, out Fixed64 displacementLength)
 20582            || displacementLength <= Fixed64.Epsilon)
 583        {
 2584            ResetLastQueryCounters();
 2585            return false;
 586        }
 587
 18588        BeginConvexSweepTrace(source, layerMask, excludedCollider, includeTriggers);
 18589        bool hit = TryFindClosestConvexSweepHit(source, displacement, out sweepHit);
 18590        _context.Diagnostics.EmitRayQuery(
 18591            source.Center,
 18592            source.Center + displacement,
 18593            source.ScaledRadius,
 18594            layerMask.Bits,
 18595            hit,
 18596            hit ? 1 : 0,
 18597            sweepHit);
 18598        return hit;
 599    }
 600
 601    private int SweepPreparedConvexSourceAll(
 602        LSCollider source,
 603        Vector3d displacement,
 604        PhysicsLayerMask layerMask,
 605        SwiftList<Physics3DHit> results,
 606        LSCollider? excludedCollider,
 607        bool includeTriggers,
 608        bool staticTargetsOnly = false)
 609    {
 116610        results.FastClear();
 116611        if (!Vector3d.TryGetMagnitude(displacement, out Fixed64 displacementLength)
 116612            || displacementLength <= Fixed64.Epsilon)
 613        {
 2614            ResetLastQueryCounters();
 2615            return 0;
 616        }
 617
 114618        BeginConvexSweepTrace(source, layerMask, excludedCollider, includeTriggers, staticTargetsOnly);
 114619        AddAllConvexSweepHits(source, displacement, results);
 114620        Physics3DHitSorter.SortByDistance(results);
 114621        _context.Diagnostics.EmitRayQuery(
 114622            source.Center,
 114623            source.Center + displacement,
 114624            source.ScaledRadius,
 114625            layerMask.Bits,
 114626            results.Count > 0,
 114627            results.Count,
 114628            results.Count > 0 ? results[0] : default);
 114629        return results.Count;
 630    }
 631
 632    private void BeginConvexSweepTrace(
 633        LSCollider source,
 634        PhysicsLayerMask layerMask,
 635        LSCollider? excludedCollider,
 636        bool includeTriggers,
 637        bool staticTargetsOnly = false)
 638    {
 148639        _currentLayerMask = layerMask;
 148640        _currentExcludedCollider = excludedCollider;
 148641        _currentSweepSourceCollider = source;
 148642        _currentIncludeTriggers = includeTriggers;
 148643        _currentStaticSweepTargetsOnly = staticTargetsOnly;
 148644        _redundantColliderCheck.Clear();
 148645        _redundantVoxelCheck.Clear();
 148646        ResetLastQueryCounters();
 148647        NextRaycastVersion();
 148648    }
 649
 650    private void BeginRaycastTrace(Vector3d start, Vector3d end)
 651    {
 1869652        _redundantColliderCheck.Clear();
 1869653        _redundantVoxelCheck.Clear();
 1869654        _bufferIntersectionPoints.FastClear();
 1869655        _currentExcludedCollider = null;
 1869656        _currentSweepSourceCollider = null;
 1869657        _currentStaticSweepTargetsOnly = false;
 1869658        _currentIncludeTriggers = true;
 1869659        ResetLastQueryCounters();
 1869660        NextRaycastVersion();
 1869661        _worker.PrepareSegmentCheck(start, end);
 1869662    }
 663
 664    private void BeginSweepTrace(
 665        Vector3d start,
 666        Vector3d end,
 667        Fixed64 radius,
 668        PhysicsLayerMask layerMask,
 669        LSCollider? excludedCollider,
 670        bool includeTriggers = true,
 671        bool staticTargetsOnly = false)
 672    {
 14379673        _currentLayerMask = layerMask;
 14379674        _currentExcludedCollider = excludedCollider;
 14379675        _currentSweepSourceCollider = null;
 14379676        _currentIncludeTriggers = includeTriggers;
 14379677        _currentStaticSweepTargetsOnly = staticTargetsOnly;
 14379678        _redundantColliderCheck.Clear();
 14379679        _redundantVoxelCheck.Clear();
 14379680        ResetLastQueryCounters();
 14379681        NextRaycastVersion();
 14379682        _sweepWorker.Prepare(start, end, radius);
 14379683    }
 684
 685    private bool SweepSphere(
 686        Vector3d start,
 687        Vector3d end,
 688        Fixed64 radius,
 689        PhysicsLayerMask layerMask,
 690        LSCollider? excludedCollider,
 691        out Physics3DHit sweepHit)
 692    {
 25693        sweepHit = default;
 25694        if (radius <= Fixed64.Zero)
 695        {
 2696            ResetLastQueryCounters();
 2697            return false;
 698        }
 699
 23700        if (!Vector3d.TrySubtract(end, start, out Vector3d segment)
 23701            || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength)
 23702            || segmentLength <= Fixed64.Epsilon)
 703        {
 4704            ResetLastQueryCounters();
 4705            return false;
 706        }
 707
 19708        Vector3d direction = segment.Normalized;
 19709        BeginSweepTrace(start, end, radius, layerMask, excludedCollider);
 19710        return TryFindClosestSweepHit(start, end, radius, direction, out sweepHit);
 711    }
 712
 713    private bool TryFindClosestSweepHit(
 714        Vector3d start,
 715        Vector3d end,
 716        Fixed64 radius,
 717        Vector3d direction,
 718        out Physics3DHit sweepHit)
 719    {
 19720        bool found = false;
 19721        Physics3DHit closestHit = default;
 722
 19723        TraceSweepForClosestHit(start, end, radius, direction, ref found, ref closestHit);
 724
 19725        sweepHit = closestHit;
 19726        return found;
 727    }
 728
 729    private bool TryFindClosestHit(Vector3d start, Vector3d end, Vector3d direction, out Physics3DHit raycastHit)
 730    {
 439731        bool found = false;
 439732        Physics3DHit closestHit = default;
 733
 439734        TraceLineForClosestHit(start, end, direction, ref found, ref closestHit);
 735
 439736        raycastHit = closestHit;
 439737        return found;
 738    }
 739
 740    private void AddAllHits(Vector3d start, Vector3d end, Vector3d direction, SwiftList<Physics3DHit> results)
 741    {
 1430742        TraceLineForAllHits(start, end, direction, results);
 1430743    }
 744
 745    private void AddAllSweepHits(
 746        Vector3d start,
 747        Vector3d end,
 748        Vector3d direction,
 749        Fixed64 radius,
 750        SwiftList<Physics3DHit> results)
 751    {
 14360752        TraceSweepForAllHits(start, end, radius, direction, results);
 14360753    }
 754
 755    private bool TryFindClosestConvexSweepHit(
 756        LSCollider source,
 757        Vector3d displacement,
 758        out Physics3DHit sweepHit)
 759    {
 26760        bool found = false;
 26761        Physics3DHit closestHit = default;
 762
 26763        TraceConvexSweepForClosestHit(source, displacement, ref found, ref closestHit);
 764
 26765        sweepHit = closestHit;
 26766        return found;
 767    }
 768
 769    private void AddAllConvexSweepHits(
 770        LSCollider source,
 771        Vector3d displacement,
 772        SwiftList<Physics3DHit> results)
 773    {
 122774        TraceConvexSweepForAllHits(source, displacement, results);
 122775    }
 776
 777    private bool TryBuildHitForCollider(
 778        int colliderId,
 779        Vector3d origin,
 780        Vector3d direction,
 781        out Physics3DHit hit)
 782    {
 4845783        hit = default;
 4845784        return _context.Physics.TryGetColliderById(colliderId, out LSCollider? current)
 4845785            && DoesCurrentColliderIntersectRay(current!)
 4845786            && TryBuildHit(current!, origin, direction, out hit);
 787    }
 788
 789    private bool TryBuildSweepHitForCollider(
 790        int colliderId,
 791        Vector3d origin,
 792        Vector3d direction,
 793        out Physics3DHit hit)
 794    {
 583152795        hit = default;
 583152796        return _context.Physics.TryGetColliderById(colliderId, out LSCollider? current)
 583152797            && IsSweepCandidate(current!)
 583152798            && TryBuildSweepHit(current!, origin, direction, out hit);
 799    }
 800
 801    private bool TryBuildConvexSweepHitForCollider(int colliderId, out Physics3DHit hit)
 802    {
 3399803        hit = default;
 3399804        if (!_context.Physics.TryGetColliderById(colliderId, out LSCollider? current)
 3399805            || !IsSweepCandidate(current!))
 806        {
 3304807            return false;
 808        }
 809
 95810        bool found = _convexSweepWorker.TrySweepPreparedSource(current!, out hit);
 95811        LastMeshTriangleCandidateCount += _convexSweepWorker.LastMeshTriangleCandidateCount;
 95812        return found;
 813    }
 814
 815    private bool TryBuildHit(
 816        LSCollider collider,
 817        Vector3d origin,
 818        Vector3d direction,
 819        out Physics3DHit raycastHit)
 820    {
 2025821        Fixed64 closestDistance = Fixed64.MaxValue;
 2025822        Vector3d closestIntersection = Vector3d.Zero;
 823
 10994824        for (int i = _bufferIntersectionPoints.Count - 1; i >= 0; i--)
 825        {
 3472826            Fixed64 dist = Vector3d.Distance(_bufferIntersectionPoints[i], origin);
 3472827            if (dist < closestDistance)
 828            {
 3470829                closestDistance = dist;
 3470830                closestIntersection = _bufferIntersectionPoints[i];
 831            }
 832        }
 833
 2025834        if (closestDistance == Fixed64.MaxValue)
 835        {
 2836            raycastHit = default;
 2837            return false;
 838        }
 839
 2023840        Vector3d normal = collider.GetNormalAtPoint(closestIntersection);
 2023841        raycastHit = new Physics3DHit(collider, closestIntersection, normal, closestDistance, direction);
 2023842        return true;
 843    }
 844
 845    private bool TryBuildSweepHit(
 846        LSCollider collider,
 847        Vector3d origin,
 848        Vector3d direction,
 849        out Physics3DHit sweepHit)
 850    {
 9122851        sweepHit = default;
 9122852        bool found = _sweepWorker.TrySweep(collider, out Vector3d sweepCenter, out Fixed64 distance);
 9122853        LastMeshTriangleCandidateCount += _sweepWorker.LastMeshTriangleCandidateCount;
 9122854        if (!found)
 1942855            return false;
 856
 7180857        if (!ContinuousCollisionContactPolicy.TryResolveSweptSphereContact(
 7180858                collider,
 7180859                sweepCenter,
 7180860                direction,
 7180861                out ContactAnchor anchor,
 7180862                out Vector3d normal))
 863        {
 1864            return false;
 865        }
 866
 7179867        sweepHit = new Physics3DHit(collider, anchor, normal, distance, direction);
 7179868        return true;
 869    }
 870
 871    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 872    private void ResetLastQueryCounters()
 873    {
 17287874        LastQueryCandidateCount = 0;
 17287875        LastMeshTriangleCandidateCount = 0;
 17287876    }
 877
 878    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 879    private uint NextRaycastVersion()
 880    {
 16396881        RaycastVersion++;
 16396882        if (RaycastVersion == 0)
 883        {
 1884            ResetColliderRaycastVersions();
 1885            RaycastVersion = 1;
 886        }
 887
 16396888        return RaycastVersion;
 889    }
 890
 891    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 892    private uint NextCircleVersion()
 893    {
 583894        CircleVersion++;
 583895        if (CircleVersion == 0)
 896        {
 1897            ResetColliderCircleVersions();
 1898            CircleVersion = 1;
 899        }
 900
 583901        return CircleVersion;
 902    }
 903
 904    private void ResetColliderRaycastVersions()
 905    {
 70906        for (int i = 0; i < _context.Physics.ColliderCount; i++)
 2907            _context.Physics.GetColliderByServiceIndex(i).RaycastVersion = 0;
 33908    }
 909
 910    private void ResetColliderCircleVersions()
 911    {
 70912        for (int i = 0; i < _context.Physics.ColliderCount; i++)
 2913            _context.Physics.GetColliderByServiceIndex(i).CircleQueryVersion = 0;
 33914    }
 915
 916    private bool DoesCurrentColliderIntersectRay(LSCollider current)
 917    {
 4845918        if (!_currentLayerMask.Includes(current.Layer)
 4845919            || current.RaycastVersion == RaycastVersion
 4845920            || !_redundantColliderCheck.Add(current.Id))
 921        {
 2729922            return false;
 923        }
 924
 2116925        current.RaycastVersion = RaycastVersion;
 2116926        _bufferIntersectionPoints.FastClear();
 2116927        return current.ColliderOverlapsRay(_worker, ref _bufferIntersectionPoints);
 928    }
 929
 930    private bool IsSweepCandidate(LSCollider current)
 931    {
 586524932        if (ReferenceEquals(current, _currentExcludedCollider)
 586524933            || ReferenceEquals(current, _currentSweepSourceCollider)
 586524934            || IsExcludedByCurrentSweepSource(current)
 586524935            || !_currentLayerMask.Includes(current.Layer)
 586524936            || current.RaycastVersion == RaycastVersion
 586524937            || !_redundantColliderCheck.Add(current.Id))
 938        {
 577304939            return false;
 940        }
 941
 9220942        if (!_currentIncludeTriggers && current.IsTrigger)
 2943            return false;
 944
 9218945        if (_currentStaticSweepTargetsOnly && !IsStaticStyleSweepTarget(current))
 1946            return false;
 947
 9217948        current.RaycastVersion = RaycastVersion;
 9217949        LastQueryCandidateCount++;
 9217950        return true;
 951    }
 952
 953    private bool IsExcludedByCurrentSweepSource(LSCollider current)
 954    {
 237925955        if (_currentSweepSourceCollider != null
 237925956            && _context.Constraints3D.ShouldExcludeLinkedCollision(_currentSweepSourceCollider, current))
 957        {
 27958            return true;
 959        }
 960
 237898961        return _currentExcludedCollider != null
 237898962            && _context.Constraints3D.ShouldExcludeLinkedCollision(_currentExcludedCollider, current);
 963    }
 964
 965    private void EnsureSourceBelongsToContext(LSCollider source)
 966    {
 165967        SwiftThrowHelper.ThrowIfArgument(
 165968            !ReferenceEquals(source.Context, _context),
 165969            nameof(source),
 165970            "Sweep source collider must belong to this query service context.");
 165971    }
 972
 973    private void PrepareConvexSweepSource(LSCollider source, Vector3d displacement)
 974    {
 975        switch (source)
 976        {
 977            case LSMeshCollider mesh:
 8978                _convexSweepWorker.PrepareConvexMeshSource(mesh, displacement);
 8979                return;
 980            case LSCompoundCollider compound:
 7981                _convexSweepWorker.PrepareCompoundSource(compound, displacement);
 7982                return;
 983            default:
 117984                _convexSweepWorker.PreparePrimitiveSource(source, displacement);
 117985                return;
 986        }
 987    }
 988
 989    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 990    private static bool IsStaticStyleSweepTarget(LSCollider collider)
 991    {
 6470992        SolidBody? body = collider.Body;
 6470993        return collider.IsStatic || body!.IsKinematic;
 994    }
 995
 996}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/3D/GravitasQuery3DService.Raycast.Traversal.cs

#LineLine coverage
 1//=======================================================================
 2// GravitasQuery3DService.Raycast.Traversal.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;
 10using Gravitas.CollisionHandling;
 11using Gravitas.Support;
 12using GridForge.Grids;
 13using GridForge.Spatial;
 14using GridForge.Utility;
 15using SwiftCollections;
 16
 17namespace Gravitas.Queries;
 18
 19/// <content>
 20/// Owns partition traversal for 3D raycasts, swept spheres, and registered-source sweeps.
 21/// </content>
 22public sealed partial class GravitasQuery3DService
 23{
 24    private void TraceLineForClosestHit(
 25        Vector3d start,
 26        Vector3d end,
 27        Vector3d direction,
 28        ref bool found,
 29        ref Physics3DHit closestHit)
 30    {
 43931        GridTracer.TraceLineInto(_context.World, start, end, _coveredVoxels, _traceScratch);
 695632        for (int i = 0; i < _coveredVoxels.Count; i++)
 303933            ProcessTraceVoxelForClosestHit(
 303934                _coveredVoxels[i],
 303935                start,
 303936                direction,
 303937                ref found,
 303938                ref closestHit);
 43939    }
 40
 41    private void TraceLineForAllHits(
 42        Vector3d start,
 43        Vector3d end,
 44        Vector3d direction,
 45        SwiftList<Physics3DHit> results)
 46    {
 143047        GridTracer.TraceLineInto(_context.World, start, end, _coveredVoxels, _traceScratch);
 1358848        for (int i = 0; i < _coveredVoxels.Count; i++)
 536449            ProcessTraceVoxelForAllHits(_coveredVoxels[i], start, direction, results);
 143050    }
 51
 52    private void TraceSweepForClosestHit(
 53        Vector3d start,
 54        Vector3d end,
 55        Fixed64 radius,
 56        Vector3d direction,
 57        ref bool found,
 58        ref Physics3DHit closestHit)
 59    {
 1960        PrepareSweepBounds(start, end, radius, out Vector3d coverageMin, out Vector3d coverageMax);
 1961        GridTracer.GetCoveredVoxelsInto(_context.World, coverageMin, coverageMax, _coveredVoxels, _traceScratch);
 1301662        for (int i = 0; i < _coveredVoxels.Count; i++)
 648963            ProcessSweepVoxelForClosestHit(
 648964                _coveredVoxels[i],
 648965                start,
 648966                direction,
 648967                ref found,
 648968                ref closestHit);
 1969    }
 70
 71    private void TraceSweepForAllHits(
 72        Vector3d start,
 73        Vector3d end,
 74        Fixed64 radius,
 75        Vector3d direction,
 76        SwiftList<Physics3DHit> results)
 77    {
 1436078        PrepareSweepBounds(start, end, radius, out Vector3d coverageMin, out Vector3d coverageMax);
 1436079        GridTracer.GetCoveredVoxelsInto(_context.World, coverageMin, coverageMax, _coveredVoxels, _traceScratch);
 146793480        for (int i = 0; i < _coveredVoxels.Count; i++)
 71960781            ProcessSweepVoxelForAllHits(_coveredVoxels[i], start, direction, results);
 1436082    }
 83
 84    private void TraceConvexSweepForClosestHit(
 85        LSCollider source,
 86        Vector3d displacement,
 87        ref bool found,
 88        ref Physics3DHit closestHit)
 89    {
 2690        PrepareConvexSweepBounds(source, displacement, out Vector3d coverageMin, out Vector3d coverageMax);
 2691        GridTracer.GetCoveredVoxelsInto(_context.World, coverageMin, coverageMax, _coveredVoxels, _traceScratch);
 569292        for (int i = 0; i < _coveredVoxels.Count; i++)
 282093            ProcessConvexSweepVoxelForClosestHit(
 282094                _coveredVoxels[i],
 282095                ref found,
 282096                ref closestHit);
 2697    }
 98
 99    private void TraceConvexSweepForAllHits(
 100        LSCollider source,
 101        Vector3d displacement,
 102        SwiftList<Physics3DHit> results)
 103    {
 122104        PrepareConvexSweepBounds(source, displacement, out Vector3d coverageMin, out Vector3d coverageMax);
 122105        GridTracer.GetCoveredVoxelsInto(_context.World, coverageMin, coverageMax, _coveredVoxels, _traceScratch);
 29710106        for (int i = 0; i < _coveredVoxels.Count; i++)
 14733107            ProcessConvexSweepVoxelForAllHits(_coveredVoxels[i], results);
 122108    }
 109
 110    private void PrepareSweepBounds(
 111        Vector3d start,
 112        Vector3d end,
 113        Fixed64 radius,
 114        out Vector3d coverageMin,
 115        out Vector3d coverageMax)
 116    {
 14379117        Vector3d radiusExtents = Vector3d.One * radius;
 14379118        coverageMin = Vector3d.Min(start, end) - radiusExtents;
 14379119        coverageMax = Vector3d.Max(start, end) + radiusExtents;
 14379120    }
 121
 122    private static void PrepareConvexSweepBounds(
 123        LSCollider source,
 124        Vector3d displacement,
 125        out Vector3d coverageMin,
 126        out Vector3d coverageMax)
 127    {
 148128        coverageMin = Vector3d.Min(source.BoundsMin, source.BoundsMin + displacement);
 148129        coverageMax = Vector3d.Max(source.BoundsMax, source.BoundsMax + displacement);
 148130    }
 131
 132    private void ProcessTraceVoxelForClosestHit(
 133        Voxel voxel,
 134        Vector3d origin,
 135        Vector3d direction,
 136        ref bool found,
 137        ref Physics3DHit closestHit)
 138    {
 3039139        if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 140        {
 1926141            return;
 142        }
 143
 1113144        ProcessPartitionForClosestHit(
 1113145            partition!,
 1113146            origin,
 1113147            direction,
 1113148            ref found,
 1113149            ref closestHit);
 1113150    }
 151
 152    private void ProcessTraceVoxelForAllHits(
 153        Voxel voxel,
 154        Vector3d origin,
 155        Vector3d direction,
 156        SwiftList<Physics3DHit> results)
 157    {
 5364158        if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 159        {
 2342160            return;
 161        }
 162
 3022163        ProcessPartitionForAllHits(partition!, origin, direction, results);
 3022164    }
 165
 166    private void ProcessSweepVoxelForClosestHit(
 167        Voxel voxel,
 168        Vector3d origin,
 169        Vector3d direction,
 170        ref bool found,
 171        ref Physics3DHit closestHit)
 172    {
 6489173        if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 174        {
 5817175            return;
 176        }
 177
 672178        ProcessPartitionForClosestSweepHit(
 672179            partition!,
 672180            origin,
 672181            direction,
 672182            ref found,
 672183            ref closestHit);
 672184    }
 185
 186    private void ProcessSweepVoxelForAllHits(
 187        Voxel voxel,
 188        Vector3d origin,
 189        Vector3d direction,
 190        SwiftList<Physics3DHit> results)
 191    {
 719607192        if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 193        {
 187695194            return;
 195        }
 196
 531912197        ProcessPartitionForAllSweepHits(partition!, origin, direction, results);
 531912198    }
 199
 200    private void ProcessConvexSweepVoxelForClosestHit(
 201        Voxel voxel,
 202        ref bool found,
 203        ref Physics3DHit closestHit)
 204    {
 2820205        if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 206        {
 1320207            return;
 208        }
 209
 1500210        ProcessPartitionForClosestConvexSweepHit(
 1500211            partition!,
 1500212            ref found,
 1500213            ref closestHit);
 1500214    }
 215
 216    private void ProcessConvexSweepVoxelForAllHits(
 217        Voxel voxel,
 218        SwiftList<Physics3DHit> results)
 219    {
 14733220        if (!GridTraversal.TryGetUniquePartition(voxel, _redundantVoxelCheck, out PhysicsPartition? partition))
 221        {
 6747222            return;
 223        }
 224
 7986225        ProcessPartitionForAllConvexSweepHits(partition!, results);
 7986226    }
 227
 228    private void ProcessPartitionForClosestHit(
 229        PhysicsPartition partition,
 230        Vector3d origin,
 231        Vector3d direction,
 232        ref bool found,
 233        ref Physics3DHit closestHit)
 234    {
 1113235        ProcessColliderListForClosestHit(
 1113236            partition.ContainedDynamicObjects,
 1113237            origin,
 1113238            direction,
 1113239            ref found,
 1113240            ref closestHit);
 241
 1113242        ProcessColliderListForClosestHit(
 1113243            partition.ContainedKinematicObjects,
 1113244            origin,
 1113245            direction,
 1113246            ref found,
 1113247            ref closestHit);
 248
 1113249        ProcessColliderListForClosestHit(
 1113250            partition.ContainedStaticObjects,
 1113251            origin,
 1113252            direction,
 1113253            ref found,
 1113254            ref closestHit);
 1113255    }
 256
 257    private void ProcessColliderListForClosestHit(
 258        SwiftSparseSet? colliderIds,
 259        Vector3d origin,
 260        Vector3d direction,
 261        ref bool found,
 262        ref Physics3DHit closestHit)
 263    {
 3339264        if (colliderIds == null)
 2226265            return;
 266
 4868267        for (int i = colliderIds.Count - 1; i >= 0; i--)
 268        {
 1321269            if (!TryBuildHitForCollider(colliderIds.DenseKeys[i], origin, direction, out Physics3DHit hit)
 1321270                || !PhysicsHitSelectionPolicy.ShouldReplace(hit, found, closestHit))
 271            {
 272                continue;
 273            }
 274
 230275            found = true;
 230276            closestHit = hit;
 277        }
 1113278    }
 279
 280    private void ProcessPartitionForAllHits(
 281        PhysicsPartition partition,
 282        Vector3d origin,
 283        Vector3d direction,
 284        SwiftList<Physics3DHit> results)
 285    {
 3022286        ProcessColliderListForAllHits(partition.ContainedDynamicObjects, origin, direction, results);
 3022287        ProcessColliderListForAllHits(partition.ContainedKinematicObjects, origin, direction, results);
 3022288        ProcessColliderListForAllHits(partition.ContainedStaticObjects, origin, direction, results);
 3022289    }
 290
 291    private void ProcessColliderListForAllHits(
 292        SwiftSparseSet? colliderIds,
 293        Vector3d origin,
 294        Vector3d direction,
 295        SwiftList<Physics3DHit> results)
 296    {
 9066297        if (colliderIds == null)
 6019298            return;
 299
 13142300        for (int i = colliderIds.Count - 1; i >= 0; i--)
 301        {
 3524302            if (TryBuildHitForCollider(colliderIds.DenseKeys[i], origin, direction, out Physics3DHit hit))
 1585303                results.Add(hit);
 304        }
 3047305    }
 306
 307    private void ProcessPartitionForClosestSweepHit(
 308        PhysicsPartition partition,
 309        Vector3d origin,
 310        Vector3d direction,
 311        ref bool found,
 312        ref Physics3DHit closestHit)
 313    {
 672314        ProcessColliderListForClosestSweepHit(
 672315            partition.ContainedDynamicObjects,
 672316            origin,
 672317            direction,
 672318            ref found,
 672319            ref closestHit);
 320
 672321        ProcessColliderListForClosestSweepHit(
 672322            partition.ContainedKinematicObjects,
 672323            origin,
 672324            direction,
 672325            ref found,
 672326            ref closestHit);
 327
 672328        ProcessColliderListForClosestSweepHit(
 672329            partition.ContainedStaticObjects,
 672330            origin,
 672331            direction,
 672332            ref found,
 672333            ref closestHit);
 672334    }
 335
 336    private void ProcessColliderListForClosestSweepHit(
 337        SwiftSparseSet? colliderIds,
 338        Vector3d origin,
 339        Vector3d direction,
 340        ref bool found,
 341        ref Physics3DHit closestHit)
 342    {
 2016343        if (colliderIds == null)
 1344344            return;
 345
 2832346        for (int i = colliderIds.Count - 1; i >= 0; i--)
 347        {
 744348            if (!TryBuildSweepHitForCollider(colliderIds.DenseKeys[i], origin, direction, out Physics3DHit hit)
 744349                || !PhysicsHitSelectionPolicy.ShouldReplace(hit, found, closestHit))
 350            {
 351                continue;
 352            }
 353
 19354            found = true;
 19355            closestHit = hit;
 356        }
 672357    }
 358
 359    private void ProcessPartitionForAllSweepHits(
 360        PhysicsPartition partition,
 361        Vector3d origin,
 362        Vector3d direction,
 363        SwiftList<Physics3DHit> results)
 364    {
 531912365        if (!_currentStaticSweepTargetsOnly)
 182380366            ProcessColliderListForAllSweepHits(partition.ContainedDynamicObjects, origin, direction, results);
 367
 531912368        ProcessColliderListForAllSweepHits(partition.ContainedKinematicObjects, origin, direction, results);
 531912369        ProcessColliderListForAllSweepHits(partition.ContainedStaticObjects, origin, direction, results);
 531912370    }
 371
 372    private void ProcessPartitionForClosestConvexSweepHit(
 373        PhysicsPartition partition,
 374        ref bool found,
 375        ref Physics3DHit closestHit)
 376    {
 1500377        ProcessColliderListForClosestConvexSweepHit(
 1500378            partition.ContainedDynamicObjects,
 1500379            ref found,
 1500380            ref closestHit);
 381
 1500382        ProcessColliderListForClosestConvexSweepHit(
 1500383            partition.ContainedKinematicObjects,
 1500384            ref found,
 1500385            ref closestHit);
 386
 1500387        ProcessColliderListForClosestConvexSweepHit(
 1500388            partition.ContainedStaticObjects,
 1500389            ref found,
 1500390            ref closestHit);
 1500391    }
 392
 393    private void ProcessPartitionForAllConvexSweepHits(
 394        PhysicsPartition partition,
 395        SwiftList<Physics3DHit> results)
 396    {
 7986397        if (!_currentStaticSweepTargetsOnly)
 981398            ProcessColliderListForAllConvexSweepHits(partition.ContainedDynamicObjects, results);
 399
 7986400        ProcessColliderListForAllConvexSweepHits(partition.ContainedKinematicObjects, results);
 7986401        ProcessColliderListForAllConvexSweepHits(partition.ContainedStaticObjects, results);
 7986402    }
 403
 404    private void ProcessColliderListForAllSweepHits(
 405        SwiftSparseSet? colliderIds,
 406        Vector3d origin,
 407        Vector3d direction,
 408        SwiftList<Physics3DHit> results)
 409    {
 1246204410        if (colliderIds == null)
 607369411            return;
 412
 2442486413        for (int i = colliderIds.Count - 1; i >= 0; i--)
 414        {
 582408415            if (TryBuildSweepHitForCollider(colliderIds.DenseKeys[i], origin, direction, out Physics3DHit hit))
 7159416                results.Add(hit);
 417        }
 638835418    }
 419
 420    private void ProcessColliderListForClosestConvexSweepHit(
 421        SwiftSparseSet? colliderIds,
 422        ref bool found,
 423        ref Physics3DHit closestHit)
 424    {
 4500425        if (colliderIds == null)
 3000426            return;
 427
 6090428        for (int i = colliderIds.Count - 1; i >= 0; i--)
 429        {
 1545430            if (!TryBuildConvexSweepHitForCollider(colliderIds.DenseKeys[i], out Physics3DHit hit)
 1545431                || !PhysicsHitSelectionPolicy.ShouldReplace(hit, found, closestHit))
 432            {
 433                continue;
 434            }
 435
 23436            found = true;
 23437            closestHit = hit;
 438        }
 1500439    }
 440
 441    private void ProcessColliderListForAllConvexSweepHits(
 442        SwiftSparseSet? colliderIds,
 443        SwiftList<Physics3DHit> results)
 444    {
 16953445        if (colliderIds == null)
 15198446            return;
 447
 7218448        for (int i = colliderIds.Count - 1; i >= 0; i--)
 449        {
 1854450            if (TryBuildConvexSweepHitForCollider(colliderIds.DenseKeys[i], out Physics3DHit hit))
 35451                results.Add(hit);
 452        }
 1755453    }
 454
 455}

Methods/Properties

.ctor(Gravitas.GravitasWorldContext)
RaycastBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsRaycast3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
RaycastAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsRaycast3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
SweepSphereBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepSphere3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
SweepSphereAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepSphere3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
SweepCapsuleBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCapsule3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
SweepCapsuleAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCapsule3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
SweepCuboidBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCuboid3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
SweepCuboidAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCuboid3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
SweepCylinderBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCylinder3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
SweepCylinderAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCylinder3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
SweepConeBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCone3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
SweepConeAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCone3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
SweepConvexMeshBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepConvexMesh3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
SweepConvexMeshAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepConvexMesh3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
SweepCompoundBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCompound3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
SweepCompoundAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsSweepCompound3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
OverlapCircleBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsOverlapCircle3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
OverlapCircleAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsOverlapCircle3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
OverlapConeBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsOverlapCone3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
OverlapConeAllBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsOverlapCone3DRequest>,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
OverlapCircleInDirectionBatch(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsOverlapCircleInDirection3DRequest>,System.Span`1<Gravitas.Queries.Physics3DHit>)
TryRaycastBatchRequest(Gravitas.Queries.PhysicsRaycast3DRequest,Gravitas.Queries.Physics3DHit&)
RaycastAllBatchRequest(Gravitas.Queries.PhysicsRaycast3DRequest,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
SweepSphereAllBatchRequest(Gravitas.Queries.PhysicsSweepSphere3DRequest,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TrySweepSourceBatchRequest(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Colliders.LSCollider,System.Boolean,Gravitas.Colliders.LSCollider&,FixedMathSharp.Vector3d&,Gravitas.Queries.Physics3DHit&)
SweepSourceAllBatchRequest(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Colliders.LSCollider,System.Boolean,Gravitas.Colliders.LSCollider&,FixedMathSharp.Vector3d&,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
PrepareBatchConvexSweepSource(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Colliders.LSCollider&,FixedMathSharp.Vector3d&)
TryOverlapCircleBatchRequest(Gravitas.Queries.PhysicsOverlapCircle3DRequest,Gravitas.Queries.Physics3DHit&)
OverlapCircleAllBatchRequest(Gravitas.Queries.PhysicsOverlapCircle3DRequest,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TryOverlapCircleInDirectionBatchRequest(Gravitas.Queries.PhysicsOverlapCircleInDirection3DRequest,Gravitas.Queries.Physics3DHit&)
TryOverlapConeBatchRequest(Gravitas.Queries.PhysicsOverlapCone3DRequest,Gravitas.Queries.Physics3DHit&)
ValidateOverlapCircleRequests(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsOverlapCircle3DRequest>)
ValidateOverlapCircleRequests(System.ReadOnlySpan`1<Gravitas.Queries.PhysicsOverlapCircleInDirection3DRequest>)
OverlapConeAllBatchRequest(Gravitas.Queries.PhysicsOverlapCone3DRequest,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
WriteClosestHit(System.Span`1<Gravitas.Queries.Physics3DHit>,System.Int32,Gravitas.Queries.Physics3DHit,System.Boolean,System.Int32&)
AppendRange(SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>,System.Int32,System.Int32)
ResetBatchCounters(System.Int32)
AccumulateBatchCounters(System.Int32)
ValidateClosestBatchOutput(System.Int32,System.Span`1<Gravitas.Queries.Physics3DHit>)
ValidateRangeBatchOutput(System.Int32,System.Span`1<Gravitas.Queries.PhysicsQueryHitRange>)
OverlapCircle(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&,Gravitas.Support.PhysicsLayerMask)
OverlapCircleInDirection(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,Gravitas.Queries.Physics3DHit&,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask)
OverlapCircleAll(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
OverlapSphereAgainstStaticAll(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
ProcessPartitionForAllSphereHits(Gravitas.PhysicsPartition,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessColliderListForAllSphereHits(SwiftCollections.SwiftSparseSet,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TryBuildOverlapSphereHit(System.Int32,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&)
TraceCircleForClosestHit(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Boolean&,Gravitas.Queries.Physics3DHit&)
TraceCircleForDirectionalHit(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.Boolean&,Gravitas.Queries.Physics3DHit&)
TraceCircleForAllHits(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
GetPlanarCircleCandidates(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64)
TryBuildOverlapHit(System.Int32,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&,Gravitas.Queries.ProjectedSurfaceRelation&)
TryBuildPlanarOverlapHit(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&,Gravitas.Queries.ProjectedSurfaceRelation&)
TryBuildSurfaceOverlapHit(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&)
GetClosestSurfacePoint(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d)
OverlapCone(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&,Gravitas.Support.PhysicsLayerMask)
OverlapConeAll(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TraceConeForClosestHit(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean&,Gravitas.Queries.Physics3DHit&,FixedMathSharp.Fixed64&)
TraceConeForAllHits(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessConePartitionForClosestHit(Gravitas.PhysicsPartition,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean&,Gravitas.Queries.Physics3DHit&,FixedMathSharp.Fixed64&)
ProcessConePartitionForAllHits(Gravitas.PhysicsPartition,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessConeColliderListForClosestHit(SwiftCollections.SwiftSparseSet,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean&,Gravitas.Queries.Physics3DHit&,FixedMathSharp.Fixed64&)
ProcessConeColliderListForAllHits(SwiftCollections.SwiftSparseSet,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TryBuildOverlapConeHit(System.Int32,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&)
TryBuildConeHitForCollider(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&)
TryBuildConeHitForConcaveMesh(Gravitas.Colliders.LSMeshCollider,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&)
TryBuildConeHitForCompound(Gravitas.Colliders.LSCompoundCollider,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&)
IsPointInsideConeVolume(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64&)
GetClosestPointOnConeAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d)
GetConeQueryBounds(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&)
ValidateConeQuery(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&)
.ctor(Gravitas.GravitasWorldContext)
get_Context()
Reset()
Raycast(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&,Gravitas.Support.PhysicsLayerMask)
RaycastAll(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
SweepSphere(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Queries.Physics3DHit&,Gravitas.Support.PhysicsLayerMask,Gravitas.Colliders.LSCollider)
SweepSphereAll(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider)
SweepSphereAgainstStaticAll(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepExactSourceAgainstStaticAll(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCapsule(Gravitas.Colliders.LSCapsuleCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCapsuleAll(Gravitas.Colliders.LSCapsuleCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCuboid(Gravitas.Colliders.LSCuboidCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCuboidAll(Gravitas.Colliders.LSCuboidCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCylinder(Gravitas.Colliders.LSCylinderCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCylinderAll(Gravitas.Colliders.LSCylinderCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCone(Gravitas.Colliders.LSConeCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepConeAll(Gravitas.Colliders.LSConeCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepConvexMesh(Gravitas.Colliders.LSMeshCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepConvexMeshAll(Gravitas.Colliders.LSMeshCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCompound(Gravitas.Colliders.LSCompoundCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCompoundAll(Gravitas.Colliders.LSCompoundCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepPrimitiveSource(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepPrimitiveSourceAll(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepConvexMeshSource(Gravitas.Colliders.LSMeshCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepConvexMeshSourceAll(Gravitas.Colliders.LSMeshCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCompoundSource(Gravitas.Colliders.LSCompoundCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepCompoundSourceAll(Gravitas.Colliders.LSCompoundCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean)
SweepSphereAllCore(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean,System.Boolean)
SweepPreparedConvexSource(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,Gravitas.Queries.Physics3DHit&,Gravitas.Colliders.LSCollider,System.Boolean)
SweepPreparedConvexSourceAll(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Support.PhysicsLayerMask,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>,Gravitas.Colliders.LSCollider,System.Boolean,System.Boolean)
BeginConvexSweepTrace(Gravitas.Colliders.LSCollider,Gravitas.Support.PhysicsLayerMask,Gravitas.Colliders.LSCollider,System.Boolean,System.Boolean)
BeginRaycastTrace(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
BeginSweepTrace(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask,Gravitas.Colliders.LSCollider,System.Boolean,System.Boolean)
SweepSphere(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Support.PhysicsLayerMask,Gravitas.Colliders.LSCollider,Gravitas.Queries.Physics3DHit&)
TryFindClosestSweepHit(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,Gravitas.Queries.Physics3DHit&)
TryFindClosestHit(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,Gravitas.Queries.Physics3DHit&)
AddAllHits(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
AddAllSweepHits(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TryFindClosestConvexSweepHit(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,Gravitas.Queries.Physics3DHit&)
AddAllConvexSweepHits(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TryBuildHitForCollider(System.Int32,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,Gravitas.Queries.Physics3DHit&)
TryBuildSweepHitForCollider(System.Int32,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,Gravitas.Queries.Physics3DHit&)
TryBuildConvexSweepHitForCollider(System.Int32,Gravitas.Queries.Physics3DHit&)
TryBuildHit(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,Gravitas.Queries.Physics3DHit&)
TryBuildSweepHit(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,Gravitas.Queries.Physics3DHit&)
ResetLastQueryCounters()
NextRaycastVersion()
NextCircleVersion()
ResetColliderRaycastVersions()
ResetColliderCircleVersions()
DoesCurrentColliderIntersectRay(Gravitas.Colliders.LSCollider)
IsSweepCandidate(Gravitas.Colliders.LSCollider)
IsExcludedByCurrentSweepSource(Gravitas.Colliders.LSCollider)
EnsureSourceBelongsToContext(Gravitas.Colliders.LSCollider)
PrepareConvexSweepSource(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d)
IsStaticStyleSweepTarget(Gravitas.Colliders.LSCollider)
TraceLineForClosestHit(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
TraceLineForAllHits(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TraceSweepForClosestHit(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
TraceSweepForAllHits(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
TraceConvexSweepForClosestHit(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
TraceConvexSweepForAllHits(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
PrepareSweepBounds(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&)
PrepareConvexSweepBounds(Gravitas.Colliders.LSCollider,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&)
ProcessTraceVoxelForClosestHit(GridForge.Grids.Voxel,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessTraceVoxelForAllHits(GridForge.Grids.Voxel,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessSweepVoxelForClosestHit(GridForge.Grids.Voxel,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessSweepVoxelForAllHits(GridForge.Grids.Voxel,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessConvexSweepVoxelForClosestHit(GridForge.Grids.Voxel,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessConvexSweepVoxelForAllHits(GridForge.Grids.Voxel,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessPartitionForClosestHit(Gravitas.PhysicsPartition,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessColliderListForClosestHit(SwiftCollections.SwiftSparseSet,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessPartitionForAllHits(Gravitas.PhysicsPartition,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessColliderListForAllHits(SwiftCollections.SwiftSparseSet,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessPartitionForClosestSweepHit(Gravitas.PhysicsPartition,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessColliderListForClosestSweepHit(SwiftCollections.SwiftSparseSet,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessPartitionForAllSweepHits(Gravitas.PhysicsPartition,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessPartitionForClosestConvexSweepHit(Gravitas.PhysicsPartition,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessPartitionForAllConvexSweepHits(Gravitas.PhysicsPartition,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessColliderListForAllSweepHits(SwiftCollections.SwiftSparseSet,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)
ProcessColliderListForClosestConvexSweepHit(SwiftCollections.SwiftSparseSet,System.Boolean&,Gravitas.Queries.Physics3DHit&)
ProcessColliderListForAllConvexSweepHits(SwiftCollections.SwiftSparseSet,SwiftCollections.SwiftList`1<Gravitas.Queries.Physics3DHit>)