< Summary

Information
Class: FixedMathSharp.Geometry.ConvexHullCylinderContact
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/ConvexHullCylinderContact.cs
Line coverage
100%
Covered lines: 125
Uncovered lines: 0
Coverable lines: 125
Total lines: 202
Line coverage: 100%
Branch coverage
100%
Covered branches: 92
Total branches: 92
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
TryGetContactWithContainedCenter(...)100%22100%
TryGetContact(...)100%8888100%
GetTriangle(...)100%11100%
GetGeometry(...)100%22100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/ConvexHullCylinderContact.cs

#LineLine coverage
 1//=======================================================================
 2// ConvexHullCylinderContact.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;
 9using static FixedMathSharp.Geometry.CylinderContactAlgebra;
 10
 11namespace FixedMathSharp.Geometry;
 12
 13/// <summary>Whole-volume contact between a validated closed convex hull and a finite cylinder or stadium slab.</summary
 14internal static class ConvexHullCylinderContact
 15{
 16    /// <summary>
 17    /// Gets whole-volume contact when the cylinder center is inside or on the
 18    /// validated closed hull. False declines center admission, not exterior overlap.
 19    /// </summary>
 20    /// <remarks>A positive planar core describes a stadium slab; its height is twice the admitted half-thickness.</rema
 21    internal static bool TryGetContactWithContainedCenter(in ScaledRigidFrame3d source, ReadOnlySpan<Vector3d> points,
 22        ReadOnlySpan<int> triangles, Vector3d center, FixedQuaternion rotation, Fixed64 height, Fixed64 radius,
 23        out FixedContactAnchors contact, Vector2d coreDirection = default, Fixed64 coreLength = default)
 24    {
 11625        contact = default;
 11726        if (!WideOrientedBox.ContainsConvexHullPoint(source, points, triangles, center)) return false;
 11527        bool found = TryGetContact(source, points, triangles, center, rotation, height, radius, out contact, coreDirecti
 28        System.Diagnostics.Debug.Assert(found, "An admitted center must have whole-volume contact.");
 11529        return found;
 30    }
 31
 32    internal static bool TryGetContact(in ScaledRigidFrame3d source, ReadOnlySpan<Vector3d> points,
 33        ReadOnlySpan<int> triangles, Vector3d center, FixedQuaternion rotation, Fixed64 height, Fixed64 radius,
 34        out FixedContactAnchors contact, Vector2d coreDirection = default, Fixed64 coreLength = default)
 35    {
 24136        contact = default;
 24137        var hull = new CylinderHullSupport(source, points, center, rotation, height, radius);
 48238        WideDirection3d coreOffset = default, coreAxis = default;
 24139        TriangleCircularGeometry coreChart = default;
 24140        if (coreLength != Fixed64.Zero)
 41        {
 11942            coreChart = GetGeometry(GetTriangle(points, triangles, 0), source, hull, triangles, 0)
 11943                .WithCore(coreDirection, coreLength, out coreOffset);
 11944            coreChart = coreChart.WithValueShift(hull.GetCoreValueShift(coreChart, coreOffset));
 11945            coreAxis = new WideDirection3d(Signed576.ExtendValue(Signed192.Raw(coreDirection.X)), default,
 11946                Signed576.ExtendValue(Signed192.Raw(coreDirection.Y)));
 47        }
 48248        Span<ulong> bestValues = stackalloc ulong[ConvexContactCandidate.Slots * Words], values = stackalloc ulong[Conve
 48249        Span<int> bestSigns = stackalloc int[ConvexContactCandidate.Slots], signs = stackalloc int[ConvexContactCandidat
 48250        Span<ulong> bestDirection = stackalloc ulong[3 * Words], direction = stackalloc ulong[3 * Words];
 48251        Span<int> bestDirectionSigns = stackalloc int[3], directionSigns = stackalloc int[3];
 96452        int bestTriangle = -1, bestMask = 0, bestCoreSign = 0, gap = 0;
 24153        bool certified = false;
 99854        for (int pass = coreAxis.IsZero ? 1 : 0; pass <= 1 && !certified; pass++)
 55        {
 56            // A failed face seed must not change the complete fan's tie order.
 26657            bestTriangle = -1;
 504458            for (int index = 0; index < triangles.Length; index += 3)
 59            {
 233360                FixedTriangle triangle = GetTriangle(points, triangles, index);
 233361                var geometry = GetGeometry(triangle, source, hull, triangles, index, coreChart);
 62                int candidateGap, mask, coreSign;
 233363                bool found = pass == 0
 233364                    ? TriangleCylinderAnalyticFeatures.TryGetSeed(geometry, coreOffset, coreAxis, values, signs, directi
 233365                        out candidateGap, out mask, out coreSign, hull, includeSeam: index == 0)
 233366                    : TriangleCylinderAnalyticFeatures.TryGetBest(geometry, coreOffset, coreAxis, values, signs,
 233367                        direction, directionSigns, out candidateGap, out mask, out coreSign, out _, hull);
 234168                if (!found) return false;
 232569                if (bestTriangle >= 0 && WideConvexPrismRelations.CompareConvexContactCandidates(
 232570                        new ConvexContactCandidate(values, signs, candidateGap), new ConvexContactCandidate(bestValues, 
 79871                values.CopyTo(bestValues); signs.CopyTo(bestSigns);
 79872                direction.CopyTo(bestDirection); directionSigns.CopyTo(bestDirectionSigns);
 159673                bestTriangle = index; bestMask = mask; bestCoreSign = coreSign; gap = candidateGap;
 39974                if (hull.HasBallMinimumCertificate(source, triangles, new ConvexContactCandidate(bestValues, bestSigns, 
 13875                { certified = true; break; }
 76            }
 25877            if (pass == 0 && !certified)
 7178                certified = hull.HasExtrudedBallMinimumCertificate(source, triangles, coreChart, coreOffset, coreAxis,
 7179                    new ConvexContactCandidate(bestValues, bestSigns, gap));
 80        }
 23481        if (bestTriangle < 0) return false;
 23282        var bestGeometry = GetGeometry(GetTriangle(points, triangles, bestTriangle), source, hull, triangles, bestTriang
 25583        if (bestCoreSign != 0) bestGeometry = bestGeometry.AtCoreRegion(coreOffset, bestCoreSign);
 23284        var analytic = new ConvexContactCandidate(bestValues, bestSigns, gap);
 23285        bestGeometry.GetAnalyticDepth(analytic, bestDirectionSigns, bestMask, out Fixed64 depth, out bool clamped);
 86
 23287        int valueWords = bestGeometry.ValueWords;
 46488        Span<ulong> rootValues = stackalloc ulong[5 * valueWords]; Span<sbyte> rootSigns = stackalloc sbyte[5];
 23289        Span<ulong> rootCell = stackalloc ulong[(16 * (valueWords * 64 + 11) + 255) / 64];
 23290        TriangleCylinderEdgeContacts.Selection rootSelection = default;
 23291        if (!certified && radius != Fixed64.Zero)
 296092            for (int index = 0; index < triangles.Length; index += 3)
 93            {
 136594                var geometry = GetGeometry(GetTriangle(points, triangles, index), source, hull, triangles, index, coreCh
 136595                if (!TriangleCylinderEdgeContacts.TryKeepContacts(geometry, coreOffset, coreAxis, analytic, depth, clamp
 136696                        rootValues, rootSigns, rootCell, ref rootSelection, hull, index)) return false;
 97            }
 23198        Vector3d origin = source.IsRigid ? source.RigidOrigin : center;
 23199        FixedQuaternion anchorRotation = source.IsRigid ? source.Rotation : rotation;
 231100        if (rootSelection.HasValue)
 101        {
 18102            FixedTriangle triangle = GetTriangle(points, triangles, rootSelection.Triangle);
 18103            var geometry = GetGeometry(triangle, source, hull, triangles, rootSelection.Triangle, coreChart);
 25104            if (rootSelection.CoreSign != 0) geometry = geometry.AtCoreRegion(coreOffset, rootSelection.CoreSign);
 18105            TriangleCylinderEdgeContacts.GetMaterials(geometry, coreAxis, coreDirection, coreLength, triangle, rootSelec
 18106                out Vector3d normal, out Vector3d radial, out Vector3d point, out int integralMask);
 20107            if (rootSelection.IsZero) { depth = Fixed64.Zero; clamped = false; }
 108            else
 109            {
 17110                FiniteAxisValueRoot root = TriangleCylinderEdgeContacts.Restore(rootValues, rootSigns, rootCell, rootSel
 17111                ConvexContactValueRoot.GetRoundedDepth(geometry.RawScale, geometry.ValueShift, ref root, out depth, out 
 112            }
 18113            FixedPointAnchor cylinderAnchor = TriangleCircularGeometry.GetSupport(center, rotation, Signed192.Raw(height
 18114            if (rootSelection.CoreSign != 0)
 115            {
 7116                Vector3d core = TriangleCapsuleSlabEndpointWitnesses.GetCore(coreDirection, coreLength, rootSelection.Co
 7117                cylinderAnchor = TriangleCylinderContact.AddCoreEndpoint(cylinderAnchor, core, coreDirection, coreLength
 118            }
 18119            contact = new FixedContactAnchors(new FixedPointAnchor(origin, anchorRotation, point),
 18120                cylinderAnchor, normal, depth, clamped);
 18121            return true;
 122        }
 213123        Vector3d analyticNormal = WideConvexPrismRelations.GetConvexContactCandidateNormal(analytic);
 426124        bestDirection.CopyTo(values); bestDirectionSigns.CopyTo(signs);
 426125        Slot(values, 1).Clear(); signs[1] = 0;
 213126        bool pole = bestDirectionSigns[0] == 0 && bestDirectionSigns[2] == 0;
 213127        Vector3d analyticRadial = pole ? default
 213128            : -WideConvexPrismRelations.GetConvexContactCandidateScaledNormal(new ConvexContactCandidate(values, signs, 
 213129        Vector3d analyticCore = default;
 213130        int analyticIntegralMask = 5;
 213131        if (bestCoreSign != 0)
 132        {
 16133            analyticCore = TriangleCapsuleSlabEndpointWitnesses.GetCore(coreDirection, coreLength, bestCoreSign, out Fix
 16134            if (radius != Fixed64.Zero)
 8135                analyticRadial = TriangleCapsuleSlabEndpointWitnesses.AdjustAnalytic(bestDirection, bestDirectionSigns,
 8136                    radius, analyticCore, term, analyticRadial, out analyticIntegralMask);
 137        }
 138        // A triangulated support face may carry the matching point in a different
 139        // triangle from the first candidate. Certify the finite witness before rounding.
 588140        for (int dimension = 3; dimension >= 1; dimension--)
 4326141            for (int index = 0; index < triangles.Length; index += 3)
 142            {
 2082143                FixedTriangle triangle = GetTriangle(points, triangles, index);
 2082144                var geometry = GetGeometry(triangle, source, hull, triangles, index, coreChart);
 2082145                var feature = bestCoreSign == 0 ? geometry : geometry.AtCoreRegion(coreOffset, bestCoreSign);
 2082146                int mask = geometry.GetSupportMask(bestDirection, bestDirectionSigns);
 2082147                int count = (mask & 1) + ((mask >> 1) & 1) + ((mask >> 2) & 1);
 2082148                if (count != dimension) continue;
 454149                int vertex = (mask & 1) != 0 ? 0 : (mask & 2) != 0 ? 1 : 2;
 454150                if (!hull.Supports(geometry, geometry.Vertex(vertex), bestDirection, bestDirectionSigns)) continue;
 151                FixedPointAnchor cylinderAnchor;
 152                Vector3d point;
 244153                int cap = bestDirectionSigns[1];
 244154                if (!coreAxis.IsZero && bestCoreSign == 0)
 155                {
 96156                    Vector3d radial = analyticRadial;
 96157                    if (!TriangleCapsuleSlabWitnesses.TryGetPoints(geometry, triangle, mask, bestDirection, bestDirectio
 96158                            coreOffset, coreDirection, coreLength, ref radial, out point, out Vector3d coreAndAxialPoint
 96159                            out FixedPointAnchorTerm3d term)) continue;
 96160                    cylinderAnchor = new FixedPointAnchor(center, rotation, coreAndAxialPoint, radial, term);
 161                }
 148162                else if (cap == 0)
 163                {
 41164                    if (!TriangleCylinderWitnesses.TryGetSidePoint(feature, triangle, mask, bestDirection, bestDirection
 41165                            out point, out Fixed64 axial, out int boundaryCap)) continue;
 40166                    cylinderAnchor = boundaryCap != 0
 40167                        ? TriangleCircularGeometry.GetSupport(center, rotation, Signed192.Raw(height), analyticRadial, b
 40168                        : new FixedPointAnchor(center, rotation, new Vector3d(Fixed64.Zero, axial, Fixed64.Zero), analyt
 169                }
 170                else
 171                {
 107172                    Vector3d radial = analyticRadial;
 107173                    if (pole)
 174                    {
 30175                        if (!TriangleCylinderWitnesses.TryGetCapPoint(feature, triangle, mask, out point, out radial)) c
 176                    }
 77177                    else if (!TriangleCylinderRimWitnesses.TryGetAnalyticPoint(feature, triangle, mask,
 77178                                 bestDirection, bestDirectionSigns, cap, geometry.Radius, out point)) continue;
 76179                    cylinderAnchor = TriangleCircularGeometry.GetSupport(center, rotation, Signed192.Raw(height), radial
 180                }
 212181                if (bestCoreSign != 0)
 16182                    cylinderAnchor = TriangleCylinderContact.AddCoreEndpoint(cylinderAnchor, analyticCore, coreDirection
 16183                        bestCoreSign, analyticIntegralMask);
 212184                contact = new FixedContactAnchors(new FixedPointAnchor(origin, anchorRotation, point), cylinderAnchor,
 212185                    analyticNormal, depth, clamped);
 212186                return true;
 187            }
 188        System.Diagnostics.Debug.Fail("A whole-hull minimum must have a finite matching witness.");
 1189        return false;
 190    }
 191
 192    private static FixedTriangle GetTriangle(ReadOnlySpan<Vector3d> points, ReadOnlySpan<int> triangles, int index) =>
 6149193        new(points[triangles[index]], points[triangles[index + 1]], points[triangles[index + 2]]);
 194
 195    private static TriangleCircularGeometry GetGeometry(FixedTriangle triangle, in ScaledRigidFrame3d source,
 196        in CylinderHullSupport hull, ReadOnlySpan<int> triangles, int index, in TriangleCircularGeometry coreChart = def
 197    {
 6149198        var geometry = new TriangleCircularGeometry(triangle, source, hull, triangles[index], triangles[index + 1], tria
 6149199        return coreChart.RawScale.Sign == 0 ? geometry : geometry.WithCoreChart(coreChart);
 200    }
 201
 202}