< Summary

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

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ContainsPoint(...)100%11100%
TryGetContact(...)100%44100%
TryGetCenteredCapsuleContact(...)100%88100%
ValidateRotation(...)100%22100%
ValidateHull(...)100%88100%
ValidateIndices(...)100%44100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// FixedConvexHullRelations.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9
 10namespace FixedMathSharp.Geometry;
 11
 12/// <summary>
 13/// Provides full-domain relations for rigidly transformed 3D convex hulls.
 14/// </summary>
 15public static class FixedConvexHullRelations
 16{
 17    /// <summary>
 18    /// Tests whether a point lies in or on a closed convex hull. The supplied
 19    /// interior point determines the accepted side of consistently wound faces.
 20    /// </summary>
 21    public static bool ContainsPoint(
 22        Vector3d hullOrigin,
 23        FixedQuaternion hullRotation,
 24        ReadOnlySpan<Vector3d> hullLocalPoints,
 25        ReadOnlySpan<int> triangleVertexIndices,
 26        Vector3d hullInteriorLocalPoint,
 27        FixedPointAnchor point)
 28    {
 1029        ValidateRotation(hullRotation, nameof(hullRotation));
 930        ValidateHull(
 931            hullLocalPoints,
 932            triangleVertexIndices,
 933            ReadOnlySpan<int>.Empty);
 534        return WideOrientedBox.ContainsConvexHullPoint(
 535            hullOrigin,
 536            hullRotation,
 537            hullLocalPoints,
 538            triangleVertexIndices,
 539            hullInteriorLocalPoint,
 540            point);
 41    }
 42
 43    /// <summary>
 44    /// Attempts to obtain the minimum-translation contact between two rigidly
 45    /// transformed convex hulls.
 46    /// </summary>
 47    public static bool TryGetContact(
 48        Vector3d firstOrigin,
 49        FixedQuaternion firstRotation,
 50        ReadOnlySpan<Vector3d> firstLocalPoints,
 51        ReadOnlySpan<int> firstTriangleVertexIndices,
 52        ReadOnlySpan<int> firstEdgeVertexPairs,
 53        Vector3d secondOrigin,
 54        FixedQuaternion secondRotation,
 55        ReadOnlySpan<Vector3d> secondLocalPoints,
 56        ReadOnlySpan<int> secondTriangleVertexIndices,
 57        ReadOnlySpan<int> secondEdgeVertexPairs,
 58        out FixedContactAnchors contact)
 59    {
 1160        ValidateRotation(firstRotation, nameof(firstRotation));
 1161        ValidateRotation(secondRotation, nameof(secondRotation));
 1062        ValidateHull(
 1063            firstLocalPoints,
 1064            firstTriangleVertexIndices,
 1065            firstEdgeVertexPairs);
 966        ValidateHull(
 967            secondLocalPoints,
 968            secondTriangleVertexIndices,
 969            secondEdgeVertexPairs);
 970        if (firstEdgeVertexPairs.Length == 0)
 71        {
 172            throw new ArgumentException(
 173                "A convex-hull contact requires first-hull edge topology.",
 174                nameof(firstEdgeVertexPairs));
 75        }
 876        if (secondEdgeVertexPairs.Length == 0)
 77        {
 178            throw new ArgumentException(
 179                "A convex-hull contact requires second-hull edge topology.",
 180                nameof(secondEdgeVertexPairs));
 81        }
 782        return WideOrientedBox.TryGetConvexHullContact(
 783            firstOrigin,
 784            firstRotation,
 785            firstLocalPoints,
 786            firstTriangleVertexIndices,
 787            firstEdgeVertexPairs,
 788            secondOrigin,
 789            secondRotation,
 790            secondLocalPoints,
 791            secondTriangleVertexIndices,
 792            secondEdgeVertexPairs,
 793            out contact);
 94    }
 95
 96    /// <summary>
 97    /// Attempts to obtain the minimum-translation contact between a rigidly
 98    /// transformed convex hull and a centered capsule.
 99    /// </summary>
 100    /// <remarks>
 101    /// The returned normal points from the hull toward the capsule. Hull
 102    /// points remain in their canonical local frame throughout the exact SAT.
 103    /// </remarks>
 104    public static bool TryGetCenteredCapsuleContact(
 105        Vector3d hullOrigin,
 106        FixedQuaternion hullRotation,
 107        ReadOnlySpan<Vector3d> hullLocalPoints,
 108        ReadOnlySpan<int> triangleVertexIndices,
 109        ReadOnlySpan<int> edgeVertexPairs,
 110        Vector3d capsuleCenter,
 111        FixedQuaternion capsuleRotation,
 112        Vector3d capsuleLocalAxisDirection,
 113        Fixed64 capsuleAxisLength,
 114        Fixed64 capsuleRadius,
 115        out FixedContactAnchors contact)
 116    {
 39117        ValidateRotation(hullRotation, nameof(hullRotation));
 39118        ValidateRotation(capsuleRotation, nameof(capsuleRotation));
 38119        ValidateHull(
 38120            hullLocalPoints,
 38121            triangleVertexIndices,
 38122            edgeVertexPairs);
 38123        if (edgeVertexPairs.Length == 0)
 124        {
 1125            throw new ArgumentException(
 1126                "A convex-hull capsule contact requires hull edge topology.",
 1127                nameof(edgeVertexPairs));
 128        }
 37129        if (!capsuleLocalAxisDirection.IsNormalized())
 130        {
 1131            throw new ArgumentException(
 1132                "The capsule local axis direction must be normalized.",
 1133                nameof(capsuleLocalAxisDirection));
 134        }
 36135        if (capsuleAxisLength < Fixed64.Zero)
 1136            throw new ArgumentOutOfRangeException(nameof(capsuleAxisLength));
 35137        if (capsuleRadius < Fixed64.Zero)
 1138            throw new ArgumentOutOfRangeException(nameof(capsuleRadius));
 139
 34140        return WideOrientedBox.TryGetConvexHullCenteredCapsuleContact(
 34141            hullOrigin,
 34142            hullRotation,
 34143            hullLocalPoints,
 34144            triangleVertexIndices,
 34145            edgeVertexPairs,
 34146            capsuleCenter,
 34147            capsuleRotation,
 34148            capsuleLocalAxisDirection,
 34149            capsuleAxisLength,
 34150            capsuleRadius,
 34151            out contact);
 152    }
 153
 154    private static void ValidateRotation(
 155        FixedQuaternion rotation,
 156        string parameterName)
 157    {
 110158        if (!rotation.IsNormalized())
 3159            throw new ArgumentException("The hull rotation must be normalized.", parameterName);
 107160    }
 161
 162    private static void ValidateHull(
 163        ReadOnlySpan<Vector3d> points,
 164        ReadOnlySpan<int> triangleVertexIndices,
 165        ReadOnlySpan<int> edgeVertexPairs)
 166    {
 66167        if (points.Length < 3)
 1168            throw new ArgumentException("A convex hull requires at least three points.", nameof(points));
 65169        if (triangleVertexIndices.Length == 0
 65170            || triangleVertexIndices.Length % 3 != 0)
 171        {
 2172            throw new ArgumentException(
 2173                "Triangle indices must be a nonempty multiple of three.",
 2174                nameof(triangleVertexIndices));
 175        }
 63176        if (edgeVertexPairs.Length % 2 != 0)
 177        {
 1178            throw new ArgumentException(
 1179                "Edge indices must contain complete vertex pairs.",
 1180                nameof(edgeVertexPairs));
 181        }
 182
 62183        ValidateIndices(points.Length, triangleVertexIndices, nameof(triangleVertexIndices));
 61184        ValidateIndices(points.Length, edgeVertexPairs, nameof(edgeVertexPairs));
 61185    }
 186
 187    private static void ValidateIndices(
 188        int pointCount,
 189        ReadOnlySpan<int> indices,
 190        string parameterName)
 191    {
 6720192        for (int index = 0; index < indices.Length; index++)
 193        {
 3238194            if ((uint)indices[index] >= (uint)pointCount)
 1195                throw new ArgumentOutOfRangeException(parameterName);
 196        }
 122197    }
 198}