< 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: 201
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    /// Face and edge indices must describe the convex hull's complete boundary;
 104    /// structural validation checks indices, not convexity or topology completeness.
 105    /// A zero-length capsule core is a sphere, including volume containment.
 106    /// </remarks>
 107    public static bool TryGetCenteredCapsuleContact(
 108        Vector3d hullOrigin,
 109        FixedQuaternion hullRotation,
 110        ReadOnlySpan<Vector3d> hullLocalPoints,
 111        ReadOnlySpan<int> triangleVertexIndices,
 112        ReadOnlySpan<int> edgeVertexPairs,
 113        Vector3d capsuleCenter,
 114        FixedQuaternion capsuleRotation,
 115        Vector3d capsuleLocalAxisDirection,
 116        Fixed64 capsuleAxisLength,
 117        Fixed64 capsuleRadius,
 118        out FixedContactAnchors contact)
 119    {
 110120        ValidateRotation(hullRotation, nameof(hullRotation));
 110121        ValidateRotation(capsuleRotation, nameof(capsuleRotation));
 109122        ValidateHull(
 109123            hullLocalPoints,
 109124            triangleVertexIndices,
 109125            edgeVertexPairs);
 109126        if (edgeVertexPairs.Length == 0)
 127        {
 1128            throw new ArgumentException(
 1129                "A convex-hull capsule contact requires hull edge topology.",
 1130                nameof(edgeVertexPairs));
 131        }
 108132        if (!capsuleLocalAxisDirection.IsNormalized())
 133        {
 1134            throw new ArgumentException(
 1135                "The capsule local axis direction must be normalized.",
 1136                nameof(capsuleLocalAxisDirection));
 137        }
 107138        if (capsuleAxisLength < Fixed64.Zero)
 1139            throw new ArgumentOutOfRangeException(nameof(capsuleAxisLength));
 106140        if (capsuleRadius < Fixed64.Zero)
 1141            throw new ArgumentOutOfRangeException(nameof(capsuleRadius));
 142
 105143        return WideOrientedBox.TryGetConvexHullCenteredCapsuleContact(
 105144            hullOrigin,
 105145            hullRotation,
 105146            hullLocalPoints,
 105147            triangleVertexIndices,
 105148            edgeVertexPairs,
 105149            capsuleCenter,
 105150            capsuleRotation,
 105151            capsuleLocalAxisDirection,
 105152            capsuleAxisLength,
 105153            capsuleRadius,
 105154            out contact);
 155    }
 156
 157    private static void ValidateRotation(
 158        FixedQuaternion rotation,
 159        string parameterName)
 160    {
 252161        if (!rotation.IsNormalized())
 3162            throw new ArgumentException("The hull rotation must be normalized.", parameterName);
 249163    }
 164
 165    private static void ValidateHull(
 166        ReadOnlySpan<Vector3d> points,
 167        ReadOnlySpan<int> triangleVertexIndices,
 168        ReadOnlySpan<int> edgeVertexPairs)
 169    {
 137170        if (points.Length < 3)
 1171            throw new ArgumentException("A convex hull requires at least three points.", nameof(points));
 136172        if (triangleVertexIndices.Length == 0
 136173            || triangleVertexIndices.Length % 3 != 0)
 174        {
 2175            throw new ArgumentException(
 2176                "Triangle indices must be a nonempty multiple of three.",
 2177                nameof(triangleVertexIndices));
 178        }
 134179        if (edgeVertexPairs.Length % 2 != 0)
 180        {
 1181            throw new ArgumentException(
 1182                "Edge indices must contain complete vertex pairs.",
 1183                nameof(edgeVertexPairs));
 184        }
 185
 133186        ValidateIndices(points.Length, triangleVertexIndices, nameof(triangleVertexIndices));
 132187        ValidateIndices(points.Length, edgeVertexPairs, nameof(edgeVertexPairs));
 132188    }
 189
 190    private static void ValidateIndices(
 191        int pointCount,
 192        ReadOnlySpan<int> indices,
 193        string parameterName)
 194    {
 14082195        for (int index = 0; index < indices.Length; index++)
 196        {
 6777197            if ((uint)indices[index] >= (uint)pointCount)
 1198                throw new ArgumentOutOfRangeException(parameterName);
 199        }
 264200    }
 201}