< Summary

Information
Class: FixedMathSharp.Geometry.TriangleCylinderContact
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Triangles/TriangleCylinderContact.cs
Line coverage
100%
Covered lines: 103
Uncovered lines: 0
Coverable lines: 103
Total lines: 181
Line coverage: 100%
Branch coverage
100%
Covered branches: 66
Total branches: 66
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
TryGetContact(...)100%22100%
TryGetContact(...)100%44100%
DoesPenetrate(...)100%22100%
TryGetContact(...)100%5656100%
AddCoreEndpoint(...)100%22100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Triangles/TriangleCylinderContact.cs

#LineLine coverage
 1//=======================================================================
 2// TriangleCylinderContact.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>Complete finite-cylinder/triangle support-fan contact ownership.</summary>
 14internal static class TriangleCylinderContact
 15{
 16    internal static bool TryGetContact(FixedTriangle triangle, Vector3d origin, FixedQuaternion rotation,
 17        Vector3d cylinderCenter, FixedQuaternion cylinderRotation, Signed192 height, Fixed64 radius,
 18        out FixedContactAnchors contact, out bool isCapFaceContact,
 19        Vector2d coreDirection = default, Fixed64 coreLength = default)
 20    {
 82821        contact = default; isCapFaceContact = false;
 41422        if (triangle.IsDegenerate)
 323            return false;
 41124        var geometry = new TriangleCircularGeometry(triangle, origin, rotation,
 41125            cylinderCenter, cylinderRotation, height, radius);
 41126        return TryGetContact(triangle, geometry, origin, rotation, cylinderCenter, cylinderRotation,
 41127            height, radius, out contact, out isCapFaceContact, coreDirection, coreLength);
 28    }
 29
 30    internal static bool TryGetContact(FixedTriangle triangle, in ScaledRigidFrame3d sourceFrame,
 31        Vector3d cylinderCenter, FixedQuaternion cylinderRotation, Signed192 height, Fixed64 radius,
 32        out FixedContactAnchors contact, out bool isCapFaceContact,
 33        Vector2d coreDirection = default, Fixed64 coreLength = default)
 34    {
 2535        if (sourceFrame.IsRigid)
 136            return TryGetContact(triangle, sourceFrame.RigidOrigin, sourceFrame.Rotation,
 137                cylinderCenter, cylinderRotation, height, radius, out contact, out isCapFaceContact, coreDirection, core
 4838        contact = default; isCapFaceContact = false;
 2439        var geometry = new TriangleCircularGeometry(triangle, sourceFrame, cylinderCenter, cylinderRotation, height, rad
 40        // Authored area can be sub-epsilon while exact scale gives a large
 41        // physical face. Only exact collapse invalidates the affine fan.
 2542        if (geometry.FaceNormal.IsZero) return false;
 2343        return TryGetContact(triangle, geometry, cylinderCenter, cylinderRotation, cylinderCenter, cylinderRotation,
 2344            height, radius, out contact, out isCapFaceContact, coreDirection, coreLength);
 45    }
 46
 47    internal static bool DoesPenetrate(FixedTriangle triangle, in ScaledRigidFrame3d sourceFrame,
 48        Vector3d center, FixedQuaternion rotation, Fixed64 height, Fixed64 radius)
 49    {
 44150        var geometry = new TriangleCircularGeometry(triangle, sourceFrame, center, rotation, Signed192.Raw(height), radi
 44251        if (geometry.FaceNormal.IsZero) return false;
 44052        return TryGetContact(triangle, geometry, center, rotation, center, rotation, Signed192.Raw(height), radius,
 44053            out _, out _, default, default, strictOnly: true);
 54    }
 55
 56    private static bool TryGetContact(FixedTriangle triangle, in TriangleCircularGeometry inputGeometry,
 57        Vector3d origin, FixedQuaternion rotation, Vector3d cylinderCenter, FixedQuaternion cylinderRotation,
 58        Signed192 height, Fixed64 radius, out FixedContactAnchors contact, out bool isCapFaceContact,
 59        Vector2d coreDirection, Fixed64 coreLength, bool strictOnly = false)
 60    {
 174861        contact = default; isCapFaceContact = false;
 174862        WideDirection3d coreOffset = default, coreAxis = default;
 63        TriangleCircularGeometry coreGeometry;
 87464        scoped ref readonly TriangleCircularGeometry geometry = ref inputGeometry;
 87465        if (coreLength != Fixed64.Zero)
 66        {
 15867            coreGeometry = inputGeometry.WithCore(coreDirection, coreLength, out coreOffset);
 15868            geometry = ref coreGeometry;
 15869            coreAxis = new WideDirection3d(Signed576.ExtendValue(Signed192.Raw(coreDirection.X)), default,
 15870                Signed576.ExtendValue(Signed192.Raw(coreDirection.Y)));
 71        }
 87472        Span<ulong> values = stackalloc ulong[ConvexContactCandidate.Slots * Words];
 87473        Span<int> signs = stackalloc int[ConvexContactCandidate.Slots];
 87474        Span<ulong> direction = stackalloc ulong[3 * Words];
 87475        Span<int> directionSigns = stackalloc int[3];
 87476        if (!TriangleCylinderAnalyticFeatures.TryGetBest(geometry, coreOffset, coreAxis, values, signs, direction, direc
 87477                out int gapSign, out int mask, out int coreSign, out bool faceMinimumCertified))
 43078            return false;
 44879        if (strictOnly && gapSign == 0) return false;
 44080        bool strictOverlap = gapSign > 0;
 44081        var best = new ConvexContactCandidate(values, signs, gapSign);
 82        TriangleCircularGeometry endpointGeometry;
 44083        scoped ref readonly TriangleCircularGeometry analyticGeometry = ref geometry;
 44084        if (coreSign != 0)
 85        {
 4886            endpointGeometry = geometry.AtCoreRegion(coreOffset, coreSign);
 4887            analyticGeometry = ref endpointGeometry;
 88        }
 44089        analyticGeometry.GetAnalyticDepth(best, directionSigns, mask, out Fixed64 depth, out bool clamped);
 132090        Vector3d normal = default, radialPoint = default, rootPoint = default;
 44091        bool edgeWinner = false;
 44092        int integralRadialMask = 5;
 44093        int cap = directionSigns[1];
 44094        if (radius != Fixed64.Zero && !faceMinimumCertified)
 95        {
 25396            if (!TriangleCylinderEdgeContacts.TryGetContact(geometry, coreOffset, coreAxis, coreDirection, coreLength,
 25397                    triangle, best, depth, clamped, radius, out edgeWinner, out normal, out radialPoint, out rootPoint, 
 25398                    out bool edgeClamped, out int edgeMask, out int edgeCap, out int edgeCoreSign, out integralRadialMas
 799                return false;
 246100            if (edgeWinner)
 101            {
 213102                mask = edgeMask; cap = edgeCap; coreSign = edgeCoreSign;
 142103                depth = edgeDepth; clamped = edgeClamped;
 104            }
 105        }
 472106        if (strictOnly) return strictOverlap;
 394107        bool pole = !edgeWinner && directionSigns[0] == 0 && directionSigns[2] == 0;
 394108        if (!edgeWinner)
 109        {
 323110            normal = WideConvexPrismRelations.GetConvexContactCandidateNormal(best);
 323111            if (!pole && (coreAxis.IsZero || coreSign != 0))
 112            {
 113                // Round R*Nrad/|Nrad| directly from the selected exact direction.
 114                // A sub-raw full-normal component must not erase a finite rim.
 179115                direction.CopyTo(values[..(3 * Words)]);
 179116                directionSigns.CopyTo(signs[..3]);
 358117                Slot(values, 1).Clear(); signs[1] = 0;
 179118                radialPoint = -WideConvexPrismRelations.GetConvexContactCandidateScaledNormal(best, radius);
 119            }
 120        }
 394121        Vector3d core = default;
 394122        if (coreSign != 0)
 123        {
 47124            core = TriangleCapsuleSlabEndpointWitnesses.GetCore(coreDirection, coreLength, coreSign,
 47125                out FixedPointAnchorTerm3d term);
 47126            if (!edgeWinner && radius != Fixed64.Zero)
 17127                radialPoint = TriangleCapsuleSlabEndpointWitnesses.AdjustAnalytic(direction, directionSigns,
 17128                    radius, core, term, radialPoint, out integralRadialMask);
 129        }
 394130        isCapFaceContact = pole && mask == 7;
 394131        FixedPointAnchor cylinderAnchor = TriangleCircularGeometry.GetSupport(cylinderCenter, cylinderRotation,
 394132            height, radialPoint, cap);
 133        FixedPointAnchor triangleAnchor;
 394134        if (!coreAxis.IsZero && coreSign == 0)
 135        {
 100136            TriangleCapsuleSlabWitnesses.GetPoints(geometry, triangle, mask, direction, directionSigns,
 100137                coreOffset, coreDirection, coreLength, ref radialPoint, out Vector3d point,
 100138                out Vector3d coreAndAxialPoint, out FixedPointAnchorTerm3d exactTerm);
 100139            triangleAnchor = new FixedPointAnchor(origin, rotation, point);
 100140            cylinderAnchor = new FixedPointAnchor(cylinderCenter, cylinderRotation, coreAndAxialPoint, radialPoint, exac
 141        }
 294142        else if (cap == 0)
 143        {
 122144            bool admitted = TriangleCylinderWitnesses.TryGetSidePoint(analyticGeometry, triangle, mask,
 122145                direction, directionSigns, out Vector3d point, out Fixed64 axial, out int boundaryCap);
 146            System.Diagnostics.Debug.Assert(admitted);
 122147            triangleAnchor = new FixedPointAnchor(origin, rotation, point);
 122148            cylinderAnchor = boundaryCap != 0
 122149                ? TriangleCircularGeometry.GetSupport(cylinderCenter, cylinderRotation, height, radialPoint, boundaryCap
 122150                : new FixedPointAnchor(cylinderCenter, cylinderRotation,
 122151                    new Vector3d(Fixed64.Zero, axial, Fixed64.Zero), radialPoint);
 152        }
 153        else
 154        {
 172155            Vector3d projectedRadial = default;
 172156            Vector3d point = edgeWinner ? rootPoint
 172157                : pole ? TriangleCylinderWitnesses.GetCapPoint(analyticGeometry, triangle, mask, out projectedRadial)
 172158                : TriangleCylinderRimWitnesses.GetAnalyticPoint(analyticGeometry, triangle, mask, direction, directionSi
 172159            triangleAnchor = new FixedPointAnchor(origin, rotation, point);
 172160            if (pole)
 44161                cylinderAnchor = new FixedPointAnchor(cylinderCenter, cylinderRotation,
 44162                    cylinderAnchor.LocalPoint, projectedRadial, cylinderAnchor.ExactLocalTerm);
 163        }
 394164        if (coreSign != 0)
 47165            cylinderAnchor = AddCoreEndpoint(cylinderAnchor, core, coreDirection, coreLength, coreSign, integralRadialMa
 394166        contact = new FixedContactAnchors(triangleAnchor, cylinderAnchor, normal, depth, clamped);
 394167        return true;
 168    }
 169
 170    internal static FixedPointAnchor AddCoreEndpoint(FixedPointAnchor anchor, Vector3d core,
 171        Vector2d axis, Fixed64 length, int coreSign, int integralRadialMask)
 172    {
 70173        FixedPointAnchorTerm3d term = TriangleCapsuleSlabEndpointWitnesses.CreateTerm(axis,
 70174            coreSign > 0 ? -length : length, core, integralRadialMask);
 175        // Stadium slab heights are twice an authored half-thickness, so the
 176        // cap coordinate is exact and only the half-core residual remains.
 70177        return new FixedPointAnchor(anchor.Origin, anchor.Rotation,
 70178            new Vector3d(core.X, anchor.LocalPoint.Y, core.Z), anchor.LocalDisplacement, term);
 179    }
 180
 181}