< Summary

Information
Class: Gravitas.Queries.ColliderPlanarProjection
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/3D/ColliderPlanarProjection.cs
Line coverage
100%
Covered lines: 145
Uncovered lines: 0
Coverable lines: 145
Total lines: 236
Line coverage: 100%
Branch coverage
100%
Covered branches: 42
Total branches: 42
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
TryGetRelation(...)100%1616100%
TryGetCompoundRelation(...)100%88100%
TryGetMeshRelation(...)100%1010100%
ShouldKeepCurrent(...)100%44100%
ShouldKeepCurrent(...)100%44100%
GetCanonicalQueryPoint(...)100%11100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/3D/ColliderPlanarProjection.cs

#LineLine coverage
 1//=======================================================================
 2// ColliderPlanarProjection.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;
 11
 12namespace Gravitas.Queries;
 13
 14/// <summary>
 15/// Dispatches exact X/Z projected-circle relations for built-in 3D colliders.
 16/// </summary>
 17internal static class ColliderPlanarProjection
 18{
 19    internal static bool TryGetRelation(
 20        LSCollider collider,
 21        Vector2d circleCenter,
 22        Fixed64 circleRadius,
 23        out ProjectedSurfaceRelation relation)
 24    {
 174125        if (collider is LSCompoundCollider compound)
 26        {
 21327            return TryGetCompoundRelation(
 21328                compound,
 21329                circleCenter,
 21330                circleRadius,
 21331                out relation);
 32        }
 152833        if (collider is LSMeshCollider mesh)
 34        {
 21735            return TryGetMeshRelation(
 21736                mesh,
 21737                circleCenter,
 21738                circleRadius,
 21739                out relation);
 40        }
 41
 42        bool found;
 43        PlanarProjectionRelation planar;
 44        switch (collider)
 45        {
 46            case LSSphereCollider sphere:
 46247                found = WidePlanarProjection.TryGetSphereRelation(
 46248                    circleCenter,
 46249                    circleRadius,
 46250                    sphere.Center,
 46251                    sphere.ScaledRadius,
 46252                    out planar);
 46253                break;
 54            case LSCapsuleCollider capsule:
 21055                found = WidePlanarProjection
 21056                    .TryGetCenteredCapsuleRelation(
 21057                        circleCenter,
 21058                        circleRadius,
 21059                        capsule.Center,
 21060                        capsule.Rotation,
 21061                        Vector3d.Up,
 21062                        capsule.AxisLength,
 21063                        capsule.ScaledRadius,
 21064                        out planar);
 21065                break;
 66            case LSCylinderCollider cylinder:
 21467                found = WidePlanarProjection
 21468                    .TryGetCenteredCylinderRelation(
 21469                        circleCenter,
 21470                        circleRadius,
 21471                        cylinder.Center,
 21472                        cylinder.Rotation,
 21473                        cylinder.Height,
 21474                        cylinder.ScaledRadius,
 21475                        out planar);
 21476                break;
 77            case LSConeCollider cone:
 21178                found = WidePlanarProjection
 21179                    .TryGetCenteredConeRelation(
 21180                        circleCenter,
 21181                        circleRadius,
 21182                        cone.Center,
 21183                        cone.Rotation,
 21184                        cone.Height,
 21185                        cone.ScaledRadius,
 21186                        out planar);
 21187                break;
 88            case LSCuboidCollider cuboid:
 21389                found = WidePlanarProjection
 21390                    .TryGetOrientedBoxRelation(
 21391                        circleCenter,
 21392                        circleRadius,
 21393                        cuboid.OrientedBox,
 21394                        out planar);
 21395                break;
 96            default:
 197                relation = default;
 198                return false;
 99        }
 100
 1310101        if (!found)
 102        {
 6103            relation = default;
 6104            return false;
 105        }
 106
 1304107        Vector3d queryPoint = GetCanonicalQueryPoint(
 1304108            collider,
 1304109            circleCenter);
 1304110        FixedPointAnchor anchor =
 1304111            collider.GetClosestSurfaceAnchor(
 1304112                queryPoint,
 1304113                out Vector3d normal);
 1304114        relation = new ProjectedSurfaceRelation(
 1304115            planar.Distance,
 1304116            planar.Offset,
 1304117            planar.Direction,
 1304118            anchor,
 1304119            normal,
 1304120            planar.IsContained);
 1304121        return true;
 122    }
 123
 124    private static bool TryGetCompoundRelation(
 125        LSCompoundCollider compound,
 126        Vector2d circleCenter,
 127        Fixed64 circleRadius,
 128        out ProjectedSurfaceRelation relation)
 129    {
 213130        bool found = false;
 213131        relation = default;
 862132        for (int index = 0; index < compound.PartCount; index++)
 133        {
 218134            if (!TryGetRelation(
 218135                    compound.GetPartCollider(index),
 218136                    circleCenter,
 218137                    circleRadius,
 218138                    out ProjectedSurfaceRelation candidate)
 218139                || (found
 218140                    && ShouldKeepCurrent(candidate, relation)))
 141            {
 142                continue;
 143            }
 144
 215145            found = true;
 215146            relation = candidate;
 147        }
 148
 213149        return found;
 150    }
 151
 152    private static bool TryGetMeshRelation(
 153        LSMeshCollider collider,
 154        Vector2d circleCenter,
 155        Fixed64 circleRadius,
 156        out ProjectedSurfaceRelation relation)
 157    {
 217158        PhysicsMesh mesh = collider.Mesh;
 217159        bool found = false;
 217160        PlanarProjectionRelation best = default;
 217161        int bestTriangle = -1;
 217162        FixedTriangle bestGeometry = default;
 884163        for (int index = 0; index < mesh.TriangleCount; index++)
 164        {
 225165            mesh.GetLocalTriangleVertices(
 225166                index,
 225167                out Vector3d first,
 225168                out Vector3d second,
 225169                out Vector3d third);
 225170            var triangle = new FixedTriangle(first, second, third);
 225171            if (!WidePlanarProjection.TryGetTriangleRelation(
 225172                    circleCenter,
 225173                    circleRadius,
 225174                    triangle,
 225175                    mesh.Origin,
 225176                    mesh.Rotation,
 225177                    out PlanarProjectionRelation candidate)
 225178                || (found && ShouldKeepCurrent(candidate, best)))
 179            {
 180                continue;
 181            }
 182
 218183            found = true;
 218184            best = candidate;
 218185            bestTriangle = index;
 218186            bestGeometry = triangle;
 187        }
 188
 217189        if (!found)
 190        {
 1191            relation = default;
 1192            return false;
 193        }
 194
 216195        var queryAnchor = new FixedPointAnchor(
 216196            GetCanonicalQueryPoint(
 216197                collider,
 216198                circleCenter),
 216199            FixedQuaternion.Identity,
 216200            Vector3d.Zero);
 216201        FixedPointAnchor contact = bestGeometry.GetClosestPointAnchor(
 216202            mesh.Origin,
 216203            mesh.Rotation,
 216204            queryAnchor);
 216205        relation = new ProjectedSurfaceRelation(
 216206            best.Distance,
 216207            best.Offset,
 216208            best.Direction,
 216209            contact,
 216210            mesh.GetFaceNormalWorld(bestTriangle),
 216211            best.IsContained);
 216212        return true;
 213    }
 214
 215    private static bool ShouldKeepCurrent(
 216        ProjectedSurfaceRelation candidate,
 217        ProjectedSurfaceRelation current) =>
 4218        candidate.Distance > current.Distance
 4219        || (candidate.Distance == current.Distance
 4220            && candidate.IsContained.CompareTo(current.IsContained) <= 0);
 221
 222    private static bool ShouldKeepCurrent(
 223        PlanarProjectionRelation candidate,
 224        PlanarProjectionRelation current) =>
 7225        candidate.Distance > current.Distance
 7226        || (candidate.Distance == current.Distance
 7227            && candidate.IsContained.CompareTo(current.IsContained) <= 0);
 228
 229    private static Vector3d GetCanonicalQueryPoint(
 230        LSCollider collider,
 231        Vector2d circleCenter) =>
 1520232        new(
 1520233            circleCenter.X,
 1520234            collider.Center.Y,
 1520235            circleCenter.Y);
 236}