< Summary

Information
Class: Gravitas.Queries.PhysicsMixedHit
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/Mixed/PhysicsMixedHit.cs
Line coverage
100%
Covered lines: 36
Uncovered lines: 0
Coverable lines: 36
Total lines: 186
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
.ctor(...)100%88100%
get_Point3D()100%11100%
get_Point2D()100%11100%
TryGetPoint3D(...)100%11100%
TryGetPoint2D(...)100%11100%
get_NormalFor3DSource()100%11100%
get_NormalFor2DSource()100%22100%
GetRequiredWorldPoint(...)100%22100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Queries/Mixed/PhysicsMixedHit.cs

#LineLine coverage
 1//=======================================================================
 2// PhysicsMixedHit.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 System;
 12using System.Runtime.CompilerServices;
 13
 14namespace Gravitas.Queries;
 15
 16/// <summary>
 17/// Result from an explicit mixed 3D/2D query.
 18/// </summary>
 19public readonly struct PhysicsMixedHit
 20{
 21    /// <summary>
 22    /// Creates a mixed query hit from world-space surface witnesses.
 23    /// </summary>
 24    public PhysicsMixedHit(
 25        LSCollider? collider3D,
 26        LSCollider2D? collider2D,
 27        Vector3d point3D,
 28        Vector3d point2D,
 29        Vector3d normal3DTo2D,
 30        PhysicsQueryReducerKind reducerKind,
 31        Fixed64 distance,
 32        Vector3d direction3D)
 2733        : this(
 2734            collider3D,
 2735            collider2D,
 2736            ContactAnchor.FromWorldPoint(point3D),
 2737            ContactAnchor.FromWorldPoint(point2D),
 2738            normal3DTo2D,
 2739            reducerKind,
 2740            distance,
 2741            direction3D)
 42    {
 2743    }
 44
 45    /// <summary>
 46    /// Creates a mixed query hit with rigid-frame surface witnesses.
 47    /// </summary>
 48    /// <exception cref="ArgumentException">
 49    /// Either rigid-frame anchor is invalid.
 50    /// </exception>
 51    public PhysicsMixedHit(
 52        LSCollider? collider3D,
 53        LSCollider2D? collider2D,
 54        ContactAnchor anchor3D,
 55        ContactAnchor anchor2D,
 56        Vector3d normal3DTo2D,
 57        PhysicsQueryReducerKind reducerKind,
 58        Fixed64 distance,
 59        Vector3d direction3D)
 60    {
 160961        if (!anchor3D.IsValid)
 162            throw new ArgumentException("The 3D hit anchor must be valid.", nameof(anchor3D));
 160863        if (!anchor2D.IsValid)
 164            throw new ArgumentException("The 2D hit anchor must be valid.", nameof(anchor2D));
 65
 160766        Collider3D = collider3D;
 160767        Collider2D = collider2D;
 160768        Body3D = collider3D?.Body;
 160769        Body2D = collider2D?.Body;
 160770        Anchor3D = anchor3D;
 160771        Anchor2D = anchor2D;
 160772        Normal3DTo2D = normal3DTo2D;
 160773        ReducerKind = reducerKind;
 160774        Distance = distance;
 160775        Direction3D = direction3D;
 160776    }
 77
 78    /// <summary>
 79    /// Gets the 3D collider participating in the hit, if registered.
 80    /// </summary>
 81    public LSCollider? Collider3D { get; }
 82
 83    /// <summary>
 84    /// Gets the 2D collider participating in the hit, if registered.
 85    /// </summary>
 86    public LSCollider2D? Collider2D { get; }
 87
 88    /// <summary>
 89    /// Gets the 3D collider's body, if any.
 90    /// </summary>
 91    public SolidBody? Body3D { get; }
 92
 93    /// <summary>
 94    /// Gets the 2D collider's body, if any.
 95    /// </summary>
 96    public SolidBody2D? Body2D { get; }
 97
 98    /// <summary>
 99    /// Gets the rigid-frame witness on the 3D shape.
 100    /// </summary>
 101    public ContactAnchor Anchor3D { get; }
 102
 103    /// <summary>
 104    /// Gets the rigid-frame witness on the embedded 2D volume.
 105    /// </summary>
 106    public ContactAnchor Anchor2D { get; }
 107
 108    /// <summary>
 109    /// Gets the materialized 3D witness.
 110    /// </summary>
 111    /// <exception cref="InvalidOperationException">
 112    /// The conceptual witness lies outside the representable coordinate range.
 113    /// </exception>
 22114    public Vector3d Point3D => GetRequiredWorldPoint(Anchor3D, nameof(Point3D));
 115
 116    /// <summary>
 117    /// Gets the materialized embedded-2D witness.
 118    /// </summary>
 119    /// <exception cref="InvalidOperationException">
 120    /// The conceptual witness lies outside the representable coordinate range.
 121    /// </exception>
 9122    public Vector3d Point2D => GetRequiredWorldPoint(Anchor2D, nameof(Point2D));
 123
 124    /// <summary>
 125    /// Attempts to materialize the 3D witness without saturation.
 126    /// </summary>
 127    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 5128    public bool TryGetPoint3D(out Vector3d point) => Anchor3D.TryGetWorldPoint(out point);
 129
 130    /// <summary>
 131    /// Attempts to materialize the embedded-2D witness without saturation.
 132    /// </summary>
 133    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 5134    public bool TryGetPoint2D(out Vector3d point) => Anchor2D.TryGetWorldPoint(out point);
 135
 136    /// <summary>
 137    /// Normal pointing from the 3D collider or swept 3D source toward the embedded 2D volume.
 138    /// </summary>
 139    public Vector3d Normal3DTo2D { get; }
 140
 141    /// <summary>
 142    /// Gets whether this mixed query hit was produced by an exact shape reducer or a conservative fallback.
 143    /// </summary>
 144    public PhysicsQueryReducerKind ReducerKind { get; }
 145
 146    /// <summary>
 147    /// Distance travelled by the swept source center before impact.
 148    /// </summary>
 149    public Fixed64 Distance { get; }
 150
 151    /// <summary>
 152    /// Gets the world-space sweep direction associated with the hit.
 153    /// </summary>
 154    public Vector3d Direction3D { get; }
 155
 156    /// <summary>
 157    /// Surface normal suitable for clamping a 3D source moving into an embedded 2D target.
 158    /// </summary>
 159    public Vector3d NormalFor3DSource
 160    {
 161        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 25162        get => -Normal3DTo2D;
 163    }
 164
 165    /// <summary>
 166    /// Planar normal suitable for clamping a 2D source moving into a 3D target.
 167    /// </summary>
 168    public Vector2d NormalFor2DSource
 169    {
 170        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 171        get
 172        {
 49173            Vector2d normal = new(Normal3DTo2D.X, Normal3DTo2D.Z);
 49174            return normal.MagnitudeSquared > Fixed64.Epsilon ? normal.Normalized : Vector2d.Zero;
 175        }
 176    }
 177
 178    private static Vector3d GetRequiredWorldPoint(ContactAnchor anchor, string propertyName)
 179    {
 31180        if (anchor.TryGetWorldPoint(out Vector3d point))
 29181            return point;
 182
 2183        throw new InvalidOperationException(
 2184            $"{propertyName} is outside the representable coordinate range. Use the corresponding TryGet method.");
 185    }
 186}