< Summary

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

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetGenerator(...)100%1616100%
RoundRadial(...)100%11100%
RoundAxial(...)100%11100%
Negate(...)100%11100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// TriangleConeWitnesses.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;
 10using static FixedMathSharp.Geometry.ContactQuadratic;
 11using static FixedMathSharp.Geometry.TriangleQuadraticSlice;
 12
 13namespace FixedMathSharp.Geometry;
 14
 15/// <summary>Matched authored-frame witnesses on the cone's free generator.</summary>
 16internal static class TriangleConeWitnesses
 17{
 18    internal static void GetGenerator(in TriangleCircularGeometry geometry, FixedTriangle triangle,
 19        Fixed64 height, Fixed64 radius, int mask, ReadOnlySpan<ulong> normal, ReadOnlySpan<int> normalSigns,
 20        Vector3d center, FixedQuaternion rotation, out Vector3d trianglePoint, out FixedPointAnchor coneAnchor)
 21    {
 8022        trianglePoint = default; coneAnchor = default;
 4023        ReadOnlySpan<ulong> root = Slot(normal, 6);
 24        // Only compact face/generator owners enter here: effective normal
 25        // height <458 bits. Oversized projected axes explicitly defer equality.
 4026        Span<ulong> d = stackalloc ulong[6 * Words];
 4027        Span<int> dSigns = stackalloc int[6];
 4028        Span<ulong> distances = stackalloc ulong[6 * Words];
 4029        Span<int> distanceSigns = stackalloc int[6];
 4030        Span<ulong> projections = stackalloc ulong[6 * Words];
 4031        Span<int> projectionSigns = stackalloc int[6];
 4032        Span<ulong> weights = stackalloc ulong[6 * Words];
 4033        Span<int> weightSigns = stackalloc int[6];
 4034        Span<ulong> work = stackalloc ulong[14 * Words];
 4035        Span<int> workSigns = stackalloc int[14];
 8036        ContactQuadratic component = At(work, workSigns, 0), product = At(work, workSigns, 1);
 8037        ContactQuadratic bound = At(work, workSigns, 2), sum = At(work, workSigns, 3);
 12038        ContactQuadratic denominator = At(work, workSigns, 4), tNumerator = At(work, workSigns, 5), tDenominator = At(wo
 8039        Signed192 h = Signed192.Raw(height), r = Signed192.Raw(radius);
 4040        Signed832 hh = Signed832.ExtendValue(WideArithmetic.MultiplySigned192(h, h));
 4041        Signed832 rr = Signed832.ExtendValue(WideArithmetic.MultiplySigned192(r, r));
 4042        Signed832 length = WideArithmetic.AddSigned832(hh, rr);
 32043        for (int axis = 0; axis < 3; axis++)
 44        {
 12045            TriangleConeGeneratorFeatures.Component(normal, normalSigns, axis, component);
 12046            Scale(component, axis == 1 ? hh : Negate(rr), At(d, dSigns, axis));
 47        }
 4048        TriangleConeGeneratorFeatures.Component(normal, normalSigns, 1, component);
 4049        Scale(component, Negate(Signed832.ExtendValue(Signed576.ExtendValue(h))), product);
 4050        Scale(product, length, component);
 4051        Scale(component, Signed832.ExtendValue(Signed576.ExtendValue(geometry.RawScale)), bound);
 52        System.Diagnostics.Debug.Assert(bound.Sign(root) > 0);
 32053        for (int vertex = 0; vertex < 3; vertex++)
 54        {
 12055            WideDirection3d p = geometry.Vertex(vertex);
 12056            ContactQuadratic distance = At(distances, distanceSigns, vertex);
 12057            TriangleConeGeneratorFeatures.Component(normal, normalSigns, 0, component);
 12058            Scale(component, Signed832.ExtendValue(p.Z), distance);
 12059            TriangleConeGeneratorFeatures.Component(normal, normalSigns, 2, component);
 12060            Scale(component, Signed832.ExtendValue(p.X), product);
 12061            distance.Add(product, -1);
 12062            sum.Clear();
 96063            for (int axis = 0; axis < 3; axis++)
 64            {
 36065                Signed576 coordinate = CylinderContactAlgebra.Component(p, axis);
 48066                if (axis == 1) coordinate = WideArithmetic.SubtractSigned576(coordinate, geometry.HalfHeight);
 36067                Scale(At(d, dSigns, axis), Signed832.ExtendValue(coordinate), product);
 36068                sum.Add(product);
 69            }
 12070            ContactQuadratic projection = At(projections, projectionSigns, vertex);
 36071            sum.CopyTo(projection); projection.Add(sum); projection.Add(bound, -1);
 72        }
 8073        weights.Clear(); weightSigns.Clear();
 4074        bool found = TryGetWeights(mask, distances, distanceSigns, projections, projectionSigns, bound, root,
 4075            weights, weightSigns, out bool centered);
 76        // The complete triangle support fan admitted this exact generator and
 77        // selected feature together, so their finite slice contains a witness.
 78        // General slice callers still own TryGetWeights' legitimate failure;
 79        // this matched-feature owner never declines or changes range handling.
 80        System.Diagnostics.Debug.Assert(found);
 4081        SumWeights(weights, weightSigns, denominator);
 4082        trianglePoint = new Vector3d(
 4083            RoundTriangleCoordinate(geometry, triangle, 0, weights, weightSigns, denominator, root),
 4084            RoundTriangleCoordinate(geometry, triangle, 1, weights, weightSigns, denominator, root),
 4085            RoundTriangleCoordinate(geometry, triangle, 2, weights, weightSigns, denominator, root));
 4086        if (centered)
 87        {
 88            // The larger blended triangle weights must not be reprojected:
 89            // their semantic generator parameter is exactly one half.
 290            tNumerator.Set(Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(1))));
 291            tDenominator.Set(Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(2))));
 92        }
 93        else
 94        {
 3895            SumWeighted(projections, projectionSigns, weights, weightSigns, root, tNumerator);
 3896            Multiply(denominator, bound, root, tDenominator);
 3897            tNumerator.Add(tDenominator);
 7698            tDenominator.CopyTo(product); tDenominator.Add(product);
 99        }
 40100        int endpoint = tNumerator.Sign(root) == 0 ? 1 : 0;
 80101        tNumerator.CopyTo(component); component.Add(tDenominator, -1);
 41102        if (component.Sign(root) == 0) endpoint = -1;
 40103        Vector3d conePoint = new(
 40104            RoundRadial(0, normal, normalSigns, rr, h, tNumerator, tDenominator, root, radius),
 40105            RoundAxial(h, tNumerator, tDenominator, root),
 40106            RoundRadial(2, normal, normalSigns, rr, h, tNumerator, tDenominator, root, radius));
 40107        coneAnchor = endpoint == 0 ? new FixedPointAnchor(center, rotation, conePoint)
 40108            : TriangleCircularGeometry.GetSupport(center, rotation, Signed192.Raw(height),
 40109                new Vector3d(conePoint.X, Fixed64.Zero, conePoint.Z), -endpoint);
 40110    }
 111
 112    private static Fixed64 RoundRadial(int axis, ReadOnlySpan<ulong> normal, ReadOnlySpan<int> signs,
 113        Signed832 radiusSquared, Signed192 height, ContactQuadratic tNumerator, ContactQuadratic tDenominator,
 114        ReadOnlySpan<ulong> root, Fixed64 radius)
 115    {
 116        // Endpoint weights <658 bits give t numerators <1448 and final
 117        // coordinate numerators <2040. Center blends use t=1/2 directly.
 80118        Span<ulong> work = stackalloc ulong[8 * Words];
 80119        Span<int> workSigns = stackalloc int[8];
 160120        ContactQuadratic component = At(work, workSigns, 0), scaled = At(work, workSigns, 1);
 160121        ContactQuadratic numerator = At(work, workSigns, 2), denominator = At(work, workSigns, 3);
 80122        TriangleConeGeneratorFeatures.Component(normal, signs, axis, component);
 80123        Scale(component, radiusSquared, scaled);
 80124        Multiply(scaled, tNumerator, root, numerator);
 80125        TriangleConeGeneratorFeatures.Component(normal, signs, 1, component);
 80126        Scale(component, Signed832.ExtendValue(Signed576.ExtendValue(height)), scaled);
 80127        Multiply(scaled, tDenominator, root, denominator);
 160128        numerator.MultiplySign(-1); denominator.MultiplySign(-1);
 80129        return RoundRatio(numerator, denominator, root, -radius.m_rawValue, radius.m_rawValue);
 130    }
 131
 132    private static Fixed64 RoundAxial(Signed192 height, ContactQuadratic tNumerator,
 133        ContactQuadratic tDenominator, ReadOnlySpan<ulong> root)
 134    {
 40135        Span<ulong> work = stackalloc ulong[6 * Words];
 40136        Span<int> signs = stackalloc int[6];
 120137        ContactQuadratic difference = At(work, signs, 0), numerator = At(work, signs, 1), denominator = At(work, signs, 
 120138        tDenominator.CopyTo(difference); difference.Add(tNumerator, -1); difference.Add(tNumerator, -1);
 40139        Scale(difference, Signed832.ExtendValue(Signed576.ExtendValue(height)), numerator);
 80140        tDenominator.CopyTo(denominator); denominator.Add(tDenominator);
 40141        return RoundRatio(numerator, denominator, root);
 142    }
 143
 120144    private static Signed832 Negate(Signed832 value) => WideArithmetic.SubtractSigned832(default, value);
 145}