< Summary

Information
Class: FixedMathSharp.Geometry.SegmentConeSurfaceCandidates
Assembly: FixedMathSharp
File(s): File 1: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Apex.cs
File 2: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Axis.cs
File 3: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.cs
File 4: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Families.cs
File 5: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.FamilyCircles.cs
File 6: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.FamilyEvents.cs
File 7: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.FamilyNormalCones.cs
File 8: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.FamilyParameters.cs
File 9: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.MeridionalRim.cs
File 10: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.NormalQueries.cs
File 11: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Rim.cs
File 12: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.RimPoints.cs
File 13: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Side.cs
File 14: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.SideWitnesses.cs
Line coverage
100%
Covered lines: 1446
Uncovered lines: 0
Coverable lines: 1446
Total lines: 2484
Line coverage: 100%
Branch coverage
100%
Covered branches: 942
Total branches: 942
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: AccumulateApex(...)100%1616100%
File 1: HasApexTouchDomain(...)100%88100%
File 1: TryGetApexParameter(...)100%11100%
File 1: TryBuildApex(...)100%3636100%
File 1: ContainsCenteredRatio(...)100%22100%
File 1: CompareWeightedSquares(...)100%11100%
File 1: GetApexContact(...)100%88100%
File 1: MaterializeRationalNormal(...)100%66100%
File 1: MaterializeRationalNormal(...)100%11100%
File 2: AccumulateAxis(...)100%1010100%
File 2: GetAxisParameter(...)100%11100%
File 3: CompareDepths(...)100%2222100%
File 3: CompareRimToAnalyticDepth(...)100%22100%
File 3: BuildAnalyticSquaredDepth(...)100%3838100%
File 3: AccumulateSegmentConeSurfaceCandidates(...)100%11100%
File 3: AccumulateSegmentConeSurfaceCandidates(...)100%11100%
File 3: AccumulateSegmentConeSurfaceCandidates(...)100%22100%
File 4: AccumulateBase(...)100%88100%
File 4: GetBaseContact(...)100%22100%
File 4: MaterializeBaseContact(...)100%11100%
File 4: MaterializeBaseContact(...)100%66100%
File 4: RoundSourceSegmentPoint(...)100%44100%
File 4: RoundSegmentPoint(...)100%22100%
File 4: ClipSideEndpoint(...)100%66100%
File 5: BuildFamilyCircle(...)100%2828100%
File 5: FamilyCircleLine(...)100%66100%
File 5: BuildFamilyCircleAnchors(...)100%44100%
File 6: GetMaximumFamilyEventCount(...)100%1616100%
File 6: AccumulateFamilyEvents(...)100%6262100%
File 6: AddFamilyEvent(...)100%1414100%
File 6: TryGetFamilyWorldAnchors(...)100%66100%
File 6: GetFamilyContact(...)100%1010100%
File 6: FamilyWorldNormal(...)100%1818100%
File 6: ExtendFamily(...)100%11100%
File 6: ExtendFamily(...)100%11100%
File 7: BuildFamilyRimBound(...)100%1010100%
File 7: BuildFamilyAxis(...)100%3030100%
File 8: BuildFamilyEvent(...)100%1010100%
File 8: BuildFamilyParameter(...)100%1818100%
File 8: BuildFamilyIntervalParameter(...)100%2222100%
File 8: GetFamilyIntervalBound(...)100%1616100%
File 8: FamilyParameterLocation(...)100%1010100%
File 8: IsInInterval(...)100%3838100%
File 8: FamilyConstraint(...)100%2828100%
File 8: BuildFamilyInterval(...)100%44100%
File 9: IsMeridionalRim(...)100%66100%
File 9: AccumulateMeridionalRim(...)100%3030100%
File 9: BuildMeridionalRim(...)100%2020100%
File 9: GetMeridionalRimContact(...)100%22100%
File 9: MaterializeMeridionalRim(...)100%88100%
File 10: TryGetNormalDotSign(...)100%2424100%
File 10: TransformNormalCovector(...)100%22100%
File 10: QuadraticNormalDotSign(...)100%66100%
File 10: GetRimRootNormalDotSign(...)100%44100%
File 11: TryGetRimSquaredDepth(...)100%22100%
File 11: AccumulateRimRoots(...)100%1212100%
File 11: AccumulateRimChart(...)100%1212100%
File 11: GetRimBasis(...)100%66100%
File 11: GetRimParameter(...)100%11100%
File 11: IsRimParameterInInterval(...)100%2020100%
File 11: AdmitRimParameter(...)100%88100%
File 11: LinearSign(...)100%11100%
File 11: ContainsRimFoot(...)100%2222100%
File 11: GetRimRootContact(...)100%66100%
File 12: AccumulateRimPoints(...)100%5050100%
File 12: HasSlantedHorizontalRimFoot(...)100%88100%
File 12: HasRimTouchDomain(...)100%1010100%
File 12: TryGetRimPoint(...)100%2222100%
File 12: BuildRimPointNormal(...)100%88100%
File 12: AdmitsEndpointNormal(...)100%66100%
File 12: HasRimCircleDomain(...)100%66100%
File 12: GetRimPointContact(...)100%44100%
File 12: MaterializeRimPoint(...)100%44100%
File 12: MaterializeRadialDirection(...)100%22100%
File 12: MaterializeQuadraticNormal(...)100%22100%
File 13: AccumulateSide(...)100%3838100%
File 13: BuildSideNormal(...)100%1212100%
File 13: BuildSidePointNormal(...)100%11100%
File 13: HasSideCircleDomain(...)100%44100%
File 13: BuildSideMetric(...)100%44100%
File 13: TryBuildSideFoot(...)100%1212100%
File 13: AdmitsSideParameter(...)100%22100%
File 13: ContainsQuadraticParameter(...)100%66100%
File 13: HasSideInterval(...)100%2020100%
File 14: GetSideContact(...)100%11100%
File 14: MaterializeSidePoint(...)100%44100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Apex.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.Apex.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/// <content>Rational apex feet and exact zero-depth apex normal families.</content>
 14internal static partial class SegmentConeSurfaceCandidates
 15{
 16    private static void AccumulateApex(in SegmentConeSurfaceGeometry geometry, ref ConeSurfaceSelection selection)
 17    {
 17918        int Words = geometry.Words;
 35819        Span<ulong> data = stackalloc ulong[6 * Words]; Span<int> fieldSigns = stackalloc int[6];
 53720        ContactQuadratic x = ContactQuadratic.At(data, fieldSigns, 0, Words), y = ContactQuadratic.At(data, fieldSigns, 
 124221        for (int endpoint = geometry.Edge.IsZero ? 0 : -1; endpoint <= (geometry.Edge.IsZero ? 0 : 1); endpoint++)
 22        {
 44323            if (!TryBuildApex(geometry, endpoint, out Signed832 numerator, out Signed832 denominator, x, y, z))
 24                continue;
 19725            ConeSurfacePointLocation location = numerator.IsZero ? ConeSurfacePointLocation.Start
 19726                : WideArithmetic.SubtractSigned832(denominator, numerator).IsZero ? ConeSurfacePointLocation.End : ConeS
 27            // A point in the finite cone at apex height is the apex itself.
 19728            ConeSurfaceFamily family = y.Signs[0] == 0 ? ConeSurfaceFamily.NormalCone : ConeSurfaceFamily.None;
 19729            if (family == ConeSurfaceFamily.NormalCone && !HasApexTouchDomain(geometry, endpoint))
 30                continue;
 19531            selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Apex, family, -1, endpoint,
 32        }
 17833    }
 34
 35    private static bool HasApexTouchDomain(in SegmentConeSurfaceGeometry geometry, int endpoint)
 36    {
 1337        int Words = geometry.Words;
 1338        if (geometry.Radius.IsZero)
 339            return true;
 40        // Scale an apex normal to ny=-R. Its radial components range over
 41        // the disk of radius H, so tangent projection spans -R*Ey +/- H|Er|.
 1042        Span<ulong> values = stackalloc ulong[2 * Words];
 1043        Span<int> signs = stackalloc int[2];
 1044        Span<ulong> root = stackalloc ulong[Words];
 1045        ContactQuadratic limit = ContactQuadratic.At(values, signs, 0, Words);
 1046        Signed832 axial = Signed832.ExtendValue(WideArithmetic.MultiplySigned576(geometry.Edge.Y, Signed192.Raw(geometry
 1047        limit.Set(axial);
 1048        if (endpoint == 1 || endpoint < 0 && axial.Sign > 0)
 249            limit.MultiplySign(-1);
 2050        Import(Signed576.ExtendValue(Signed192.Raw(geometry.Input.Height)), limit.Radical); limit.Signs[1] = 1;
 1051        Import(CircularRimContactAlgebra.RadialDot(geometry.Edge, geometry.Edge), root);
 1052        return limit.Sign(root) >= 0;
 53    }
 54
 55    private static bool TryGetApexParameter(in SegmentConeSurfaceGeometry geometry, int endpoint,
 56        out Signed832 numerator, out Signed832 denominator)
 57    {
 48458        int Words = geometry.Words;
 96859        Span<ulong> values = stackalloc ulong[6 * Words]; Span<int> signs = stackalloc int[6];
 48460        return TryBuildApex(geometry, endpoint, out numerator, out denominator,
 48461            ContactQuadratic.At(values, signs, 0, Words), ContactQuadratic.At(values, signs, 1, Words), ContactQuadratic
 62    }
 63
 64    private static bool TryBuildApex(in SegmentConeSurfaceGeometry geometry, int endpoint,
 65        out Signed832 numerator, out Signed832 denominator, ContactQuadratic x, ContactQuadratic y, ContactQuadratic z)
 66    {
 112167        int Words = geometry.Words;
 112168        WideDirection3d offset = new(geometry.A.X, WideArithmetic.SubtractSigned576(geometry.A.Y, geometry.Cap), geometr
 112169        denominator = endpoint < 0 ? geometry.Edge.SquaredLength : Signed832.ExtendValue(Signed192.Signed(1));
 112170        numerator = endpoint < 0 ? WideArithmetic.SubtractSigned832(default, WideDirection3d.Dot(offset, geometry.Edge))
 112171            : endpoint == 0 ? default : denominator;
 336372        x.Clear(); y.Clear(); z.Clear();
 112173        if (numerator.Sign < 0 || WideArithmetic.SubtractSigned832(denominator, numerator).Sign < 0
 120774            || endpoint < 0 && (numerator.IsZero || WideArithmetic.SubtractSigned832(denominator, numerator).IsZero)) re
 207075        Span<ulong> values = stackalloc ulong[6 * Words]; Span<int> signs = stackalloc int[6];
 310576        ContactQuadratic term = ContactQuadratic.At(values, signs, 0, Words), divisor = ContactQuadratic.At(values, sign
 103577        divisor.Set(denominator);
 828078        for (int axis = 0; axis < 3; axis++)
 79        {
 310580            ContactQuadratic coordinate = axis == 0 ? x : axis == 1 ? y : z;
 310581            ContactQuadratic.Scale(divisor, Component(offset, axis), coordinate);
 931582            pointY.Set(numerator); ContactQuadratic.Scale(pointY, Component(geometry.Edge, axis), term); coordinate.Add(
 83        }
 105184        if (y.Signs[0] > 0 || CompareWeightedSquares(x, z, geometry.Input.Radius, y, geometry.Input.Height) > 0) return 
 305785        y.CopyTo(pointY); ContactQuadratic.Scale(divisor, geometry.Cap, term); pointY.Add(term);
 111486        if (!ContainsCenteredRatio(geometry, x, pointY, z, denominator)) return false;
 92487        if (endpoint >= 0)
 88        {
 68189            WideDirection3d n = endpoint == 0 ? offset : new(geometry.B.X,
 68190                WideArithmetic.SubtractSigned576(geometry.B.Y, geometry.Cap), geometry.B.Z);
 68191            int dot = WideDirection3d.Dot(n, geometry.Edge).Sign;
 73092            if (endpoint == 0 ? dot > 0 : dot < 0) return false;
 93        }
 87594        return true;
 95    }
 96
 97    private static bool ContainsCenteredRatio(in SegmentConeSurfaceGeometry geometry,
 98        ContactQuadratic x, ContactQuadratic y, ContactQuadratic z, Signed832 denominator)
 99    {
 1160100        int Words = geometry.Words;
 2320101        Span<ulong> values = stackalloc ulong[6 * Words]; Span<int> signs = stackalloc int[6];
 3480102        ContactQuadratic axial = ContactQuadratic.At(values, signs, 0, Words), divisor = ContactQuadratic.At(values, sig
 3480103        divisor.Set(denominator); ContactQuadratic.Scale(divisor, geometry.Cap, axial); axial.Add(y, -1);
 104        System.Diagnostics.Debug.Assert(axial.Signs[0] >= 0);
 2320105        ContactQuadratic.Scale(divisor, geometry.FullHeight, bound); bound.Add(axial, -1);
 1160106        return bound.Signs[0] >= 0 && CompareWeightedSquares(x, z, geometry.Input.Height, axial, geometry.Input.Radius) 
 107    }
 108
 109    private static int CompareWeightedSquares(ContactQuadratic x, ContactQuadratic z, Fixed64 radialWeight,
 110        ContactQuadratic y, Fixed64 axialWeight)
 111    {
 2164112        int Words = x.FieldWords;
 4328113        Span<ulong> values = stackalloc ulong[8 * Words]; Span<int> signs = stackalloc int[8];
 8656114        ContactQuadratic radial = ContactQuadratic.At(values, signs, 0, Words), axial = ContactQuadratic.At(values, sign
 2164115        ContactQuadratic.Multiply(x, x, ReadOnlySpan<ulong>.Empty, radial);
 4328116        ContactQuadratic.Multiply(z, z, ReadOnlySpan<ulong>.Empty, term); radial.Add(term);
 2164117        ContactQuadratic.Scale(radial, Signed576.ExtendValue(WideArithmetic.MultiplySigned192(Signed192.Raw(radialWeight
 2164118        ContactQuadratic.Multiply(y, y, ReadOnlySpan<ulong>.Empty, axial);
 2164119        ContactQuadratic.Scale(axial, Signed576.ExtendValue(WideArithmetic.MultiplySigned192(Signed192.Raw(axialWeight),
 4328120        term.Add(factor, -1); return term.Signs[0];
 121    }
 122
 123    internal static FixedContactAnchors GetApexContact(in SegmentConeSurfaceCandidate candidate)
 124    {
 142125        var geometry = new SegmentConeSurfaceGeometry(candidate.Input); int Words = geometry.Words;
 142126        Span<ulong> values = stackalloc ulong[14 * Words]; Span<int> signs = stackalloc int[14];
 213127        ContactQuadratic x = ContactQuadratic.At(values, signs, 0, Words), y = ContactQuadratic.At(values, signs, 1, Wor
 284128            divisor = ContactQuadratic.At(values, signs, 3, Words), metric = ContactQuadratic.At(values, signs, 4, Words
 71129        bool admitted = TryBuildApex(geometry, candidate.RootOrdinal, out Signed832 numerator, out Signed832 denominator
 130        System.Diagnostics.Debug.Assert(admitted);
 71131        Vector3d normal = MaterializeRationalNormal(x, y, z, candidate.Input.ConeRotation);
 71132        metric.Clear();
 568133        for (int axis = 0; axis < 3; axis++)
 134        {
 213135            ContactQuadratic component = axis == 0 ? x : axis == 1 ? y : z;
 426136            ContactQuadratic.Multiply(component, component, ReadOnlySpan<ulong>.Empty, square); metric.Add(square);
 137        }
 142138        divisor.Set(denominator); ContactQuadratic.Scale(divisor, Signed576.ExtendValue(geometry.RawScale), scaled);
 71139        ContactQuadratic.Multiply(scaled, scaled, ReadOnlySpan<ulong>.Empty, divisor);
 71140        bool represented = ContactQuadratic.TryRoundSquareRootRatio(metric, divisor, ReadOnlySpan<ulong>.Empty, out Fixe
 142141        divisor.Set(denominator); scaled.Set(numerator);
 71142        Vector3d point = RoundSourceSegmentPoint(geometry, scaled, divisor, ReadOnlySpan<ulong>.Empty);
 71143        return new FixedContactAnchors(new FixedPointAnchor(candidate.Input.Origin, candidate.Input.Rotation, point),
 71144            TriangleCircularGeometry.GetSupport(candidate.Input.Center, candidate.Input.ConeRotation, Signed192.Raw(cand
 71145            normal, represented ? depth : Fixed64.MaxValue, !represented);
 146    }
 147
 148    private static Vector3d MaterializeRationalNormal(ContactQuadratic x, ContactQuadratic y, ContactQuadratic z, FixedQ
 149    {
 87150        int Words = x.FieldWords;
 174151        Span<ulong> local = stackalloc ulong[3 * Words], values = stackalloc ulong[7 * Words];
 348152        Span<int> localSigns = stackalloc int[3], signs = stackalloc int[7]; values.Clear(); signs.Clear();
 696153        for (int axis = 0; axis < 3; axis++)
 154        {
 261155            ContactQuadratic value = axis == 0 ? x : axis == 1 ? y : z;
 522156            value.Rational.CopyTo(Slot(local, axis, Words)); localSigns[axis] = value.Signs[0];
 157        }
 87158        WriteWorldDirection(new WideRationalBasis3d(rotation), local, localSigns, values[..(3 * Words)], signs[..3]);
 87159        return WideConvexPrismRelations.GetConvexContactCandidateNormal(new ConvexContactCandidate(values, signs, 0, Wor
 160    }
 161
 162    private static Vector3d MaterializeRationalNormal(Signed832 x, Signed832 y, Signed832 z, FixedQuaternion rotation)
 163    {
 32164        Span<ulong> values = stackalloc ulong[6 * Words]; Span<int> signs = stackalloc int[6];
 48165        ContactQuadratic a = ContactQuadratic.At(values, signs, 0, Words), b = ContactQuadratic.At(values, signs, 1, Wor
 64166        a.Set(x); b.Set(y); c.Set(z); return MaterializeRationalNormal(a, b, c, rotation);
 167    }
 168}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Axis.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.Axis.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/// <content>The zero-radius cone's finite axis and exact normal domains.</content>
 13internal static partial class SegmentConeSurfaceCandidates
 14{
 15    private static void AccumulateAxis(in SegmentConeSurfaceGeometry geometry, ref ConeSurfaceSelection selection)
 16    {
 17
 17818        if (!geometry.Radius.IsZero)
 15919            return;
 1920        if (geometry.Edge.X.IsZero && geometry.Edge.Z.IsZero)
 21        {
 22            // Accumulation's finite intersection precondition proves that
 23            // this coaxial interval has at least one admitted point.
 824            selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Side,
 825                ConeSurfaceFamily.SegmentInterval, 0, 0, ConeSurfacePointLocation.SegmentIntervalUnspecified));
 826            return;
 27        }
 1128        GetAxisParameter(geometry, out Signed832 numerator, out Signed832 denominator);
 1129        ConeSurfacePointLocation location = numerator.IsZero ? ConeSurfacePointLocation.Start
 1130            : WideArithmetic.SubtractSigned832(denominator, numerator).IsZero ? ConeSurfacePointLocation.End : ConeSurfa
 1131        selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Side,
 1132            ConeSurfaceFamily.NormalCone, 0, 0, location));
 1133    }
 34
 35    private static void GetAxisParameter(in SegmentConeSurfaceGeometry geometry,
 36        out Signed832 numerator, out Signed832 denominator)
 37    {
 38
 39        // A non-coaxial segment already certified to intersect a zero-radius
 40        // cone has exactly one finite radial-axis crossing. Reuse that proof;
 41        // its projection parameter does not require a second admission test.
 136742        denominator = CircularRimContactAlgebra.RadialDot(geometry.Edge, geometry.Edge);
 136743        numerator = WideArithmetic.SubtractSigned832(default, CircularRimContactAlgebra.RadialDot(geometry.A, geometry.E
 136744    }
 45
 46}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.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;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <summary>Exact finite-segment witnesses paired with finite-cone support features.</summary>
 15/// <content>Finite support strata, exact halfspace-clipped families, retained certificates, and caller-owned selection.
 16internal static partial class SegmentConeSurfaceCandidates
 17{
 18    // Four quartic charts contribute at most 16 roots, with two horizontal
 19    // principal feet, four endpoint rim branches, six side branches, three
 20    // apex feet and one base descriptor. Other strata replace these charts.
 21    internal const int MaximumCandidates = 32;
 22
 23    /// <summary>Compares the exact nonnegative depths of certificates from the same input segment and cone frame.</summ
 24    /// <remarks>Clipping a retained family changes its witnesses, but not its source depth. No rounded anchor or depth 
 25    internal static int CompareDepths(in SegmentConeSurfaceCandidate first, in SegmentConeSurfaceCandidate second)
 26    {
 21827        int Words = first.Input.Words;
 21828        int ValueWords = first.Input.ValueWords;
 21829        int ValueCellWords = (16 * (ValueWords * 64 + 11) + 255) / 64;
 21830        var geometry = new SegmentConeSurfaceGeometry(first.Input);
 21831        bool firstRoot = first.Feature == ConeSurfaceFeature.Rim && first.Family == ConeSurfaceFamily.None && first.Char
 21832        bool secondRoot = second.Feature == ConeSurfaceFeature.Rim && second.Family == ConeSurfaceFamily.None && second.
 21833        if (!firstRoot && !secondRoot)
 34        {
 39035            Span<ulong> a = stackalloc ulong[ConvexContactCandidate.Slots * Words], b = stackalloc ulong[ConvexContactCa
 39036            Span<int> aSigns = stackalloc int[ConvexContactCandidate.Slots], bSigns = stackalloc int[ConvexContactCandid
 39037            int aSign = BuildAnalyticSquaredDepth(geometry, first, a, aSigns), bSign = BuildAnalyticSquaredDepth(geometr
 19538            return WideConvexPrismRelations.CompareConvexContactCandidates(new ConvexContactCandidate(a, aSigns, aSign, 
 39        }
 2340        if (!firstRoot || !secondRoot)
 1841            return firstRoot ? CompareRimToAnalyticDepth(geometry, first, second) : -CompareRimToAnalyticDepth(geometry,
 42
 1043        Span<ulong> firstValues = stackalloc ulong[5 * ValueWords], secondValues = stackalloc ulong[5 * ValueWords];
 1044        Span<sbyte> firstSigns = stackalloc sbyte[5], secondSigns = stackalloc sbyte[5];
 1045        Span<ulong> firstCell = stackalloc ulong[ValueCellWords], secondCell = stackalloc ulong[ValueCellWords];
 546        bool firstPositive = TryGetRimSquaredDepth(geometry, first, firstValues, firstSigns, firstCell, out FiniteAxisVa
 547        bool secondPositive = TryGetRimSquaredDepth(geometry, second, secondValues, secondSigns, secondCell, out FiniteA
 48        // A zero depth is outside the value isolator's (0,1] domain. The same
 49        // input precondition makes both positive roots' scale/shift identical.
 550        return !firstPositive || !secondPositive ? firstPositive.CompareTo(secondPositive)
 551            : WideFiniteAxisIntersection.CompareFiniteValueRoots(firstValue, secondValue);
 52    }
 53
 54    private static int CompareRimToAnalyticDepth(in SegmentConeSurfaceGeometry geometry,
 55        in SegmentConeSurfaceCandidate rim, in SegmentConeSurfaceCandidate analytic)
 56    {
 1857        int Words = geometry.Words;
 1858        int ValueWords = geometry.ValueWords;
 1859        int ValueCellWords = (16 * (ValueWords * 64 + 11) + 255) / 64;
 1860        Span<ulong> data = stackalloc ulong[ConvexContactCandidate.Slots * Words];
 1861        Span<int> signs = stackalloc int[ConvexContactCandidate.Slots];
 1862        int gapSign = BuildAnalyticSquaredDepth(geometry, analytic, data, signs);
 1863        Span<ulong> values = stackalloc ulong[5 * ValueWords];
 1864        Span<sbyte> valueSigns = stackalloc sbyte[5];
 1865        Span<ulong> cell = stackalloc ulong[ValueCellWords];
 1866        return TryGetRimSquaredDepth(geometry, rim, values, valueSigns, cell, out FiniteAxisValueRoot value)
 1867            ? ConvexContactValueRoot.CompareRootSquared(geometry.RawScale, geometry.ValueShift, ref value, new ConvexCon
 1868            : -gapSign;
 69    }
 70
 71    private static int BuildAnalyticSquaredDepth(in SegmentConeSurfaceGeometry geometry,
 72        in SegmentConeSurfaceCandidate candidate, Span<ulong> destination, Span<int> destinationSigns)
 73    {
 40874        int Words = geometry.Words;
 81675        destination.Clear(); destinationSigns.Clear();
 40876        ContactQuadratic numerator = new(destination.Slice(7 * Words, 2 * Words), destinationSigns.Slice(7, 2));
 40877        Span<ulong> root = destination.Slice(9 * Words, Words);
 40878        Span<ulong> scratch = stackalloc ulong[24 * Words];
 40879        Span<int> scratchSigns = stackalloc int[24];
 81680        ContactQuadratic denominator = At(scratch, scratchSigns, 10, Words), product = At(scratch, scratchSigns, 11, Wor
 40881        Signed832 one = Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(1)));
 40882        denominator.Set(one);
 40883        if (candidate.Family == ConeSurfaceFamily.NormalCone || candidate.Feature == ConeSurfaceFeature.Side && geometry
 84        {
 1485            Slot(destination, 10, Words)[0] = 1;
 1486            return 0;
 87        }
 39488        if (candidate.Feature == ConeSurfaceFeature.Apex)
 89        {
 25290            ContactQuadratic x = At(scratch, scratchSigns, 0, Words), y = At(scratch, scratchSigns, 1, Words), z = At(sc
 8491            bool admitted = TryBuildApex(geometry, candidate.RootOrdinal, out _, out Signed832 divisor, x, y, z);
 92            System.Diagnostics.Debug.Assert(admitted);
 67293            for (int axis = 0; axis < 3; axis++)
 94            {
 25295                ContactQuadratic coordinate = axis == 0 ? x : axis == 1 ? y : z;
 50496                Multiply(coordinate, coordinate, root, product); numerator.Add(product);
 97            }
 16898            product.Set(divisor); Multiply(product, product, root, denominator);
 99        }
 310100        else if (candidate.Feature == ConeSurfaceFeature.Base)
 101        {
 62102            product.Set(Signed832.ExtendValue(WideArithmetic.AddSigned576(candidate.RootOrdinal == 1 ? geometry.B.Y : ge
 62103            Multiply(product, product, root, numerator);
 104        }
 248105        else if (candidate.Feature == ConeSurfaceFeature.Side && candidate.Family == ConeSurfaceFamily.RotationCircle)
 106        {
 56107            product.Set(Signed832.ExtendValue(WideArithmetic.SubtractSigned576(geometry.Cap, candidate.RootOrdinal == 1 
 56108            ContactQuadratic square = At(scratch, scratchSigns, 0, Words);
 56109            Multiply(product, product, root, square);
 112110            Signed192 h = Signed192.Raw(geometry.Input.Height), r = Signed192.Raw(geometry.Input.Radius);
 56111            Scale(square, Signed832.ExtendValue(WideArithmetic.MultiplySigned192(r, r)), numerator);
 56112            denominator.Set(Signed832.ExtendValue(WideArithmetic.AddSigned320(WideArithmetic.MultiplySigned192(h, h), Wi
 113        }
 192114        else if (candidate.Feature == ConeSurfaceFeature.Side)
 115        {
 78116            bool normal = BuildSideNormal(geometry, candidate.RootOrdinal, candidate.Chart, scratch, scratchSigns, root)
 117            System.Diagnostics.Debug.Assert(normal);
 78118            BuildSideMetric(geometry, candidate.RootOrdinal, scratch, scratchSigns, root);
 78119            Multiply(At(scratch, scratchSigns, 8, Words), At(scratch, scratchSigns, 8, Words), root, numerator);
 78120            At(scratch, scratchSigns, 7, Words).CopyTo(denominator);
 121        }
 122        else
 123        {
 114124            if (candidate.RootOrdinal <= -3)
 125            {
 28126                bool admitted = BuildMeridionalRim(geometry, candidate.RootOrdinal, candidate.Chart == -2 ? 1 : -1, scra
 127                System.Diagnostics.Debug.Assert(admitted);
 28128                Multiply(At(scratch, scratchSigns, 7, Words), At(scratch, scratchSigns, 7, Words), root, denominator);
 129            }
 130            else
 131            {
 86132                bool admitted = TryGetRimPoint(geometry, candidate.RootOrdinal, out WideDirection3d radialAxis, out Sign
 133                System.Diagnostics.Debug.Assert(admitted);
 86134                if (candidate.Family == ConeSurfaceFamily.RotationCircle)
 135                {
 56136                    numerator.Set(WideArithmetic.AddSigned832(WideArithmetic.MultiplySigned576(geometry.Radius, geometry
 137                }
 138                else
 139                {
 30140                    Signed832 radialSquare = radialAxis.SquaredLength;
 30141                    Import(radialSquare, root);
 30142                    BuildRimPointNormal(geometry, radialAxis, coefficient, axial, radialSquare, candidate.Chart == -2 ? 
 30143                    WideArithmetic.MultiplyMagnitudes(root, root, denominator.Rational);
 30144                    denominator.Signs[0] = 1;
 145                }
 146            }
 114147            if (candidate.Family != ConeSurfaceFamily.RotationCircle)
 148            {
 464149                for (int axis = 0; axis < 3; axis++)
 150                {
 348151                    Multiply(At(scratch, scratchSigns, axis, Words), At(scratch, scratchSigns, axis, Words), root, produ
 152                }
 153            }
 154        }
 155        // These are the same squared metrics used by each feature's depth
 156        // materializer. The largest meridional coefficients are <2000 bits;
 157        // denominator scaling adds <268 bits, within the existing 40 limbs.
 788158        Span<ulong> scale = stackalloc ulong[Words], scaleSquared = stackalloc ulong[Words];
 394159        Import(Signed576.ExtendValue(geometry.RawScale), scale);
 394160        WideArithmetic.MultiplyMagnitudes(scale, scale, scaleSquared);
 394161        Scale(denominator, scaleSquared, 1, product);
 162        System.Diagnostics.Debug.Assert(product.Signs[1] == 0 && product.Signs[0] > 0);
 394163        product.Rational.CopyTo(Slot(destination, 10, Words));
 394164        return numerator.Sign(root) == 0 ? 0 : 1;
 165    }
 166
 167    internal static bool AccumulateSegmentConeSurfaceCandidates(FixedSegment segment,
 168        Vector3d origin, FixedQuaternion rotation, Vector3d coneCenter,
 169        FixedQuaternion coneRotation, Fixed64 height, Fixed64 radius,
 170        scoped ref ConeSurfaceSelection selection)
 171    {
 177172        var input = new SegmentConeSurfaceInput(segment, origin, rotation, coneCenter, coneRotation, height, radius);
 177173        return AccumulateSegmentConeSurfaceCandidates(input, ref selection);
 174    }
 175
 176    internal static bool AccumulateSegmentConeSurfaceCandidates(FixedSegment segment,
 177        in ScaledRigidFrame3d sourceFrame, Vector3d center, FixedQuaternion rotation,
 178        Fixed64 height, Fixed64 radius, scoped ref ConeSurfaceSelection selection) =>
 3179        AccumulateSegmentConeSurfaceCandidates(new SegmentConeSurfaceInput(segment, sourceFrame, center, rotation, heigh
 180
 181    private static bool AccumulateSegmentConeSurfaceCandidates(in SegmentConeSurfaceInput input, scoped ref ConeSurfaceS
 182    {
 180183        FixedSegment segment = input.Segment;
 180184        var geometry = new SegmentConeSurfaceGeometry(input);
 180185        if (!geometry.Finite.IntersectsTransformedSegment(geometry.Finite.Transform(segment.Start),
 180186                geometry.Finite.Transform(segment.End)))
 1187            return false;
 179188        int first = selection.Count;
 179189        AccumulateApex(geometry, ref selection);
 178190        AccumulateBase(geometry, ref selection);
 178191        AccumulateSide(geometry, ref selection);
 178192        AccumulateAxis(geometry, ref selection);
 178193        AccumulateRimPoints(geometry, ref selection);
 178194        AccumulateMeridionalRim(geometry, ref selection);
 178195        AccumulateRimRoots(geometry, ref selection);
 178196        return selection.Count != first;
 197    }
 198}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Families.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.Families.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;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <content>Explicit finite parameter domains for degenerate support families.</content>
 15internal static partial class SegmentConeSurfaceCandidates
 16{
 17    private static void AccumulateBase(in SegmentConeSurfaceGeometry geometry, ref ConeSurfaceSelection selection)
 18    {
 19
 17820        if (geometry.Edge.Y.IsZero)
 21        {
 8422            selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Base, ConeSurfaceFamily.Seg
 8423            return;
 24        }
 9425        int endpoint = geometry.Edge.Y.Sign > 0 ? 1 : 0;
 9426        Vector3d point = endpoint == 0 ? geometry.Input.Segment.Start : geometry.Input.Segment.End;
 9427        if (geometry.Finite.ContainsTransformedPoint(geometry.Finite.Transform(point)))
 5428            selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Base,
 5429                ConeSurfaceFamily.None, 0, endpoint, endpoint == 0 ? ConeSurfacePointLocation.Start : ConeSurfacePointLo
 9430    }
 31
 32    internal static FixedContactAnchors GetBaseContact(in SegmentConeSurfaceCandidate candidate) =>
 1633        MaterializeBaseContact(candidate.Input, candidate.RootOrdinal == 0 ? Fixed64.Zero : Fixed64.One);
 34
 35    private static FixedContactAnchors MaterializeBaseContact(in SegmentConeSurfaceInput input, Fixed64 parameter)
 36    {
 1637        int Words = input.Words;
 1638        var geometry = new SegmentConeSurfaceGeometry(input);
 1639        Span<ulong> values = stackalloc ulong[4 * Words];
 1640        Span<int> signs = stackalloc int[4];
 3241        ContactQuadratic numerator = At(values, signs, 0, Words), denominator = At(values, signs, 1, Words);
 1642        numerator.Set(Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Raw(parameter))));
 1643        denominator.Set(Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Raw(Fixed64.One))));
 1644        return MaterializeBaseContact(geometry, numerator, denominator, ReadOnlySpan<ulong>.Empty);
 45    }
 46
 47    private static FixedContactAnchors MaterializeBaseContact(in SegmentConeSurfaceGeometry geometry,
 48        ContactQuadratic numerator, ContactQuadratic denominator, ReadOnlySpan<ulong> root)
 49    {
 1650        int Words = geometry.Words;
 1651        Span<ulong> values = stackalloc ulong[8 * Words];
 1652        Span<int> signs = stackalloc int[8];
 6453        ContactQuadratic coordinate = At(values, signs, 0, Words), product = At(values, signs, 1, Words), divisor = At(v
 1654        Scale(denominator, Signed832.ExtendValue(geometry.RawScale), divisor);
 1655        Vector3d radial = default;
 12856        for (int axis = 0; axis < 3; axis++)
 57        {
 4858            Scale(denominator, Signed832.ExtendValue(Component(geometry.A, axis)), coordinate);
 9659            Scale(numerator, Signed832.ExtendValue(Component(geometry.Edge, axis)), product); coordinate.Add(product);
 6460            if (axis == 0) radial.X = RoundRatio(coordinate, divisor, root);
 4861            else if (axis == 2) radial.Z = RoundRatio(coordinate, divisor, root);
 62            else
 63            {
 1664                coordinate.CopyTo(gap);
 3265                Scale(denominator, Signed832.ExtendValue(geometry.Cap), product); gap.Add(product);
 66            }
 67        }
 1668        Fixed64 depth = RoundRatio(gap, divisor, root, 0, long.MaxValue);
 1669        Vector3d normal = MaterializeRationalNormal(default,
 1670            Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(1))), default, geometry.Input.ConeRotation);
 1671        return new FixedContactAnchors(
 1672            new FixedPointAnchor(geometry.Input.Origin, geometry.Input.Rotation,
 1673                RoundSourceSegmentPoint(geometry, numerator, denominator, root)),
 1674            TriangleCircularGeometry.GetSupport(geometry.Input.Center, geometry.Input.ConeRotation,
 1675                Signed192.Raw(geometry.Input.Height), radial, 1), normal, depth, false);
 76    }
 77
 78    private static Vector3d RoundSourceSegmentPoint(in SegmentConeSurfaceGeometry geometry,
 79        ContactQuadratic numerator, ContactQuadratic denominator, ReadOnlySpan<ulong> root)
 80    {
 198281        if (!geometry.Input.IsAffine) return RoundSegmentPoint(geometry.Input.Segment, numerator, denominator, root);
 1282        int Words = Math.Max(numerator.FieldWords, denominator.FieldWords);
 2483        Span<ulong> values = stackalloc ulong[6 * Words]; Span<int> signs = stackalloc int[6];
 3684        ContactQuadratic coordinate = At(values, signs, 0, Words), term = At(values, signs, 1, Words), divisor = At(valu
 1285        Scale(denominator, Signed576.ExtendValue(geometry.RawScale), divisor);
 1286        Vector3d point = default;
 9687        for (int axis = 0; axis < 3; axis++)
 88        {
 3689            Scale(denominator, Component(geometry.A, axis), coordinate);
 7290            Scale(numerator, Component(geometry.Edge, axis), term); coordinate.Add(term);
 3691            point[axis] = RoundRatio(coordinate, divisor, root);
 92        }
 1293        return point;
 94    }
 95
 96    private static Vector3d RoundSegmentPoint(FixedSegment segment, ContactQuadratic numerator,
 97        ContactQuadratic denominator, ReadOnlySpan<ulong> root)
 98    {
 98599        int Words = Math.Max(numerator.FieldWords, denominator.FieldWords);
 985100        Span<ulong> values = stackalloc ulong[4 * Words];
 985101        Span<int> signs = stackalloc int[4];
 1970102        ContactQuadratic point = At(values, signs, 0, Words), product = At(values, signs, 1, Words);
 985103        Vector3d result = default;
 7880104        for (int axis = 0; axis < 3; axis++)
 105        {
 2955106            Scale(denominator, Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Raw(segment.Start[axis]))), point);
 5910107            Scale(numerator, Signed832.ExtendValue(Signed576.ExtendValue(WideArithmetic.Difference(segment.End[axis], se
 2955108            result[axis] = RoundRatio(point, denominator, root);
 109        }
 985110        return result;
 111    }
 112
 113    private static void ClipSideEndpoint(in SegmentConeSurfaceGeometry geometry, bool upper,
 114        Span<ulong> normals, Span<int> normalSigns, ReadOnlySpan<ulong> root)
 115    {
 216116        int Words = geometry.Words;
 216117        Span<ulong> values = stackalloc ulong[8 * Words];
 216118        Span<int> signs = stackalloc int[8];
 864119        ContactQuadratic bound = At(values, signs, 0, Words), denominator = At(values, signs, 1, Words), constant = At(v
 216120        ContactQuadratic metric = At(normals, normalSigns, 7, Words);
 216121        Scale(metric, Signed832.ExtendValue(geometry.A.Y), constant);
 432122        Multiply(At(normals, normalSigns, 8, Words), At(normals, normalSigns, 1, Words), root, product); constant.Add(pr
 216123        int direction = geometry.Edge.Y.Sign;
 216124        Scale(metric, Signed832.ExtendValue(geometry.Cap), bound);
 648125        bound.MultiplySign((upper ? 1 : -1) * direction); bound.Add(constant, -1); bound.MultiplySign(direction);
 432126        Scale(metric, Signed832.ExtendValue(geometry.Edge.Y), denominator); denominator.MultiplySign(direction);
 432127        ContactQuadratic current = At(normals, normalSigns, 5, Words), currentD = At(normals, normalSigns, 6, Words);
 216128        int comparison = CompareRatios(bound, denominator, root, current, currentD, root);
 216129        if (upper ? comparison < 0 : comparison > 0)
 130        {
 16131            bound.CopyTo(current); denominator.CopyTo(currentD);
 132        }
 216133    }
 134}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.FamilyCircles.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.FamilyCircles.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.ContactQuadratic;
 10
 11namespace FixedMathSharp.Geometry;
 12
 13/// <content>Unit-circle boundary roots and clipped apex-disk vertices.</content>
 14internal static partial class SegmentConeSurfaceCandidates
 15{
 16    private static bool BuildFamilyCircle(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry geomet
 17        scoped ReadOnlySpan<WideAxis3> fan, ConeSurfaceFamilyEvent item, scoped ref ConeSurfaceFamilyWitness witness)
 18    {
 146419        int FamilyWords = witness.FieldWords;
 292820        Span<ulong> work = stackalloc ulong[24 * FamilyWords]; Span<int> signs = stackalloc int[24];
 439221        ContactQuadratic u = At(work, signs, 0, FamilyWords), v = At(work, signs, 1, FamilyWords), d = At(work, signs, 2
 439222        ContactQuadratic a = At(work, signs, 3, FamilyWords), b = At(work, signs, 4, FamilyWords), c = At(work, signs, 5
 439223        ContactQuadratic aa = At(work, signs, 6, FamilyWords), bb = At(work, signs, 7, FamilyWords), cc = At(work, signs
 292824        ContactQuadratic product = At(work, signs, 9, FamilyWords), temporary = At(work, signs, 10, FamilyWords);
 439225        u.Clear(); v.Clear(); d.Set(ExtendFamily(Signed192.Signed(1)));
 146426        if (item.Kind == ConeSurfaceFamilyEventKind.CircleSeam)
 35427            (item.First % 2 == 0 ? u : v).Set(ExtendFamily(Signed192.Signed(item.First < 2 ? 1 : -1)));
 111028        else if (item.Kind == ConeSurfaceFamilyEventKind.CircleBoundary)
 29        {
 82430            FamilyCircleLine(candidate, geometry, fan, item, witness, item.First, a, b, c);
 247231            Multiply(a, a, witness.Root, d); Multiply(b, b, witness.Root, product); d.Add(product);
 129632            if (d.Sign(witness.Root) == 0) return false;
 105633            Multiply(c, c, witness.Root, product); d.CopyTo(temporary); temporary.Add(product, -1);
 37034            if (temporary.Sign(witness.Root) < 0) return false;
 35            // a*u+b*v+c=0 intersects u²+v²=1 at
 36            // (-a*c +/- b*sqrt(D-c²), -b*c -/+ a*sqrt(D-c²))/D.
 37            // Retaining this field preserves irrational singleton domains.
 66838            Multiply(a, c, witness.Root, u); u.MultiplySign(-1);
 66839            Multiply(b, c, witness.Root, v); v.MultiplySign(-1);
 33440            temporary.Rational.CopyTo(witness.Root);
 66841            b.Rational.CopyTo(u.Radical); u.Signs[1] = item.Branch * b.Signs[0];
 66842            a.Rational.CopyTo(v.Radical); v.Signs[1] = -item.Branch * a.Signs[0];
 43        }
 28644        else if (item.Kind == ConeSurfaceFamilyEventKind.DiskPair)
 45        {
 27646            FamilyCircleLine(candidate, geometry, fan, item, witness, item.First, a, b, c);
 27647            FamilyCircleLine(candidate, geometry, fan, item, witness, item.Second, aa, bb, cc);
 82848            Multiply(a, bb, witness.Root, d); Multiply(b, aa, witness.Root, product); d.Add(product, -1);
 27649            int direction = d.Sign(witness.Root);
 49150            if (direction == 0) return false;
 18351            Multiply(b, cc, witness.Root, u); Multiply(c, bb, witness.Root, product); u.Add(product, -1);
 18352            Multiply(c, aa, witness.Root, v); Multiply(a, cc, witness.Root, product); v.Add(product, -1);
 18353            u.MultiplySign(direction); v.MultiplySign(direction); d.MultiplySign(direction);
 18354            Multiply(u, u, witness.Root, temporary); Multiply(v, v, witness.Root, product); temporary.Add(product);
 12255            Multiply(d, d, witness.Root, product); temporary.Add(product, -1);
 6256            if (temporary.Sign(witness.Root) > 0) return false;
 57        }
 75858        Signed832 radial = candidate.Feature == ConeSurfaceFeature.Rim ? Signed832.ExtendValue(geometry.Radius)
 75859            : ExtendFamily(Signed192.Raw(candidate.Input.Height));
 151660        Scale(u, radial, witness[0]); Scale(v, radial, witness[2]);
 75861        if (candidate.Family == ConeSurfaceFamily.RotationCircle)
 116462        { witness[0].MultiplySign(-1); witness[2].MultiplySign(-1); }
 75863        if (candidate.Feature == ConeSurfaceFeature.Rim)
 64        {
 19465            TryGetRimPoint(geometry, candidate.RootOrdinal, out _, out _, out Signed576 offset, out _, out _);
 19466            Scale(d, Signed832.ExtendValue(offset), witness[1]);
 67        }
 68        else
 69        {
 112870            Scale(d, ExtendFamily(Signed192.Raw(candidate.Input.Radius)), witness[1]); witness[1].MultiplySign(-1);
 71        }
 75872        if (candidate.Family == ConeSurfaceFamily.NormalCone)
 73        {
 193674            for (int axis = 0; axis < 3; axis++) witness[3 + axis].CopyTo(witness[6 + axis]);
 17675            return true;
 76        }
 58277        BuildFamilyCircleAnchors(candidate, geometry, u, v, d, ref witness);
 58278        return true;
 79    }
 80
 81    private static void FamilyCircleLine(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry geometr
 82        scoped ReadOnlySpan<WideAxis3> fan, ConeSurfaceFamilyEvent item, scoped ConeSurfaceFamilyWitness witness,
 83        int index, ContactQuadratic a, ContactQuadratic b, ContactQuadratic c)
 84    {
 137685        int FamilyWords = witness.FieldWords;
 137686        FamilyConstraint(geometry, fan, item, witness, index, out Signed832 x, out Signed832 y, out Signed832 z);
 275287        Span<ulong> work = stackalloc ulong[2 * FamilyWords]; Span<int> signs = stackalloc int[2];
 137688        ContactQuadratic scalar = At(work, signs, 0, FamilyWords);
 137689        Signed832 radial = candidate.Feature == ConeSurfaceFeature.Rim ? Signed832.ExtendValue(geometry.Radius)
 137690            : ExtendFamily(Signed192.Raw(candidate.Input.Height));
 275291        scalar.Set(x); Scale(scalar, radial, a);
 275292        scalar.Set(z); Scale(scalar, radial, b);
 273293        if (candidate.Family == ConeSurfaceFamily.RotationCircle) { a.MultiplySign(-1); b.MultiplySign(-1); }
 137694        scalar.Set(y);
 137695        if (candidate.Feature == ConeSurfaceFeature.Rim)
 96        {
 20897            TryGetRimPoint(geometry, candidate.RootOrdinal, out _, out _, out Signed576 offset, out _, out _);
 20898            Scale(scalar, Signed832.ExtendValue(offset), c);
 99        }
 2336100        else { Scale(scalar, ExtendFamily(Signed192.Raw(candidate.Input.Radius)), c); c.MultiplySign(-1); }
 1168101    }
 102
 103    private static void BuildFamilyCircleAnchors(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry
 104        scoped ContactQuadratic u, scoped ContactQuadratic v, scoped ContactQuadratic d, scoped ref ConeSurfaceFamilyWit
 105    {
 582106        int FamilyWords = witness.FieldWords;
 1164107        Span<ulong> work = stackalloc ulong[12 * FamilyWords]; Span<int> signs = stackalloc int[12];
 1164108        ContactQuadratic oldD = At(work, signs, 0, FamilyWords), factor = At(work, signs, 1, FamilyWords);
 1164109        ContactQuadratic gap = At(work, signs, 2, FamilyWords), product = At(work, signs, 3, FamilyWords);
 1164110        ContactQuadratic temporary = At(work, signs, 4, FamilyWords), oldY = At(work, signs, 5, FamilyWords);
 1164111        witness[9].CopyTo(oldD); witness[4].CopyTo(oldY);
 1164112        Signed832 radius = ExtendFamily(Signed192.Raw(candidate.Input.Radius)), height = ExtendFamily(Signed192.Raw(cand
 582113        if (candidate.Feature == ConeSurfaceFeature.Rim)
 114        {
 388115            d.CopyTo(factor); factor.Add(factor);
 388116            Scale(oldD, radius, gap); gap.Add(gap);
 388117            Multiply(gap, u, witness.Root, witness[6]); Multiply(gap, v, witness.Root, witness[8]);
 582118            Scale(oldD, height, gap); Multiply(gap, d, witness.Root, witness[7]); witness[7].MultiplySign(-1);
 119        }
 120        else
 121        {
 388122            Signed832 metric = Signed832.ExtendValue(WideArithmetic.AddSigned320(
 388123                WideArithmetic.MultiplySigned192(Signed192.Raw(candidate.Input.Height), Signed192.Raw(candidate.Input.He
 388124                WideArithmetic.MultiplySigned192(Signed192.Raw(candidate.Input.Radius), Signed192.Raw(candidate.Input.Ra
 388125            Scale(d, metric, factor);
 776126            Scale(witness[11], Signed832.ExtendValue(geometry.Cap), gap); gap.Add(oldY, -1);
 776127            Scale(gap, radius, temporary); Scale(temporary, height, gap);
 776128            Multiply(gap, u, witness.Root, witness[6]); Multiply(gap, v, witness.Root, witness[8]);
 1164129            Scale(oldY, metric, gap); Scale(temporary, radius, product); gap.Add(product);
 388130            Multiply(gap, d, witness.Root, witness[7]);
 131        }
 4656132        for (int axis = 0; axis < 3; axis++)
 133        {
 3492134            Multiply(witness[3 + axis], factor, witness.Root, product); product.CopyTo(witness[3 + axis]);
 135        }
 582136        Multiply(oldD, factor, witness.Root, witness[9]);
 582137    }
 138}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.FamilyEvents.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.FamilyEvents.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.ContactQuadratic;
 10
 11namespace FixedMathSharp.Geometry;
 12
 13/// <content>Finite exact certificates for continuous families clipped by authored normal halfspaces.</content>
 14internal static partial class SegmentConeSurfaceCandidates
 15{
 16    // Full Signed320 authored covectors become <452 bits in the relative
 17    // frame. Circle coefficients are <652, their discriminant <1306, and
 18    // homogeneous normals <1504. Rational rim bounds are <1320 and their
 19    // substituted normals <2220. Interval midpoint products and side feet
 20    // stay <3700. These 4096-bit fields retain complete coordinates; squared
 21    // metrics below use separately sized complete-product scratch. Affine
 22    // source frames and full Signed832 clips select three-times-wider fields.
 23    internal const int FamilyWords = 64;
 24
 25    internal static int GetMaximumFamilyEventCount(in SegmentConeSurfaceCandidate candidate, int halfspaceCount)
 26    {
 27
 11328        if (halfspaceCount < 0) throw new ArgumentOutOfRangeException(nameof(halfspaceCount));
 29        checked
 30        {
 11131            int k = halfspaceCount + 4; // Segment polarity and finite-axis cap constraints.
 11132            if (candidate.Input.Radius == Fixed64.Zero && candidate.Feature != ConeSurfaceFeature.Base)
 2233                return (candidate.Family == ConeSurfaceFamily.SegmentInterval ? 3 : 1) * (6 + 6 * k + k * (k - 1));
 12334            if (candidate.Family == ConeSurfaceFamily.SegmentInterval) return 3;
 7635            if (candidate.Family == ConeSurfaceFamily.RotationCircle) return 4 + 2 * k;
 3436            if (candidate.Family == ConeSurfaceFamily.NormalCone)
 2537                return candidate.Feature == ConeSurfaceFeature.Apex ? 5 + 2 * k + k * (k - 1) / 2 : 2 + k;
 938            return 0;
 39        }
 40    }
 41
 42    internal static bool AccumulateFamilyEvents(in SegmentConeSurfaceCandidate candidate, scoped ReadOnlySpan<WideAxis3>
 43        ConeSurfacePointLocation location, scoped ref ConeSurfaceFamilySelection selection, in RationalSegmentInterval c
 44    {
 45
 27246        if (location == ConeSurfacePointLocation.SegmentIntervalUnspecified)
 147            throw new ArgumentException("A family query requires Start, Interior, or End incident halfspaces.", nameof(l
 27148        if (candidate.Family == ConeSurfaceFamily.None
 27149            || !clip.IsClipped && candidate.Family != ConeSurfaceFamily.SegmentInterval && candidate.PointLocation != lo
 8050            return false;
 51        // Clipping can turn an original interior point into a genuine endpoint;
 52        // its exact reconstructed parameter decides that stratum below.
 19153        var geometry = new SegmentConeSurfaceGeometry(candidate.Input);
 20254        if (geometry.Edge.IsZero && location != ConeSurfacePointLocation.Start) return false;
 18055        int before = selection.Count;
 18056        int firstParameter = candidate.Family != ConeSurfaceFamily.SegmentInterval ? -1
 18057            : location == ConeSurfacePointLocation.Start ? 3 : location == ConeSurfacePointLocation.End ? 4 : 0;
 18058        int lastParameter = firstParameter == 0 ? 2 : firstParameter;
 18059        int constraints = fan.Length + 4;
 89060        for (int parameter = firstParameter; parameter <= lastParameter; parameter++)
 61        {
 26662            if (candidate.Input.Radius == Fixed64.Zero && candidate.Feature != ConeSurfaceFeature.Base)
 63            {
 64                // A nonzero polyhedral cone has a coordinate direction, a
 65                // one-plane lineality direction, or a two-plane extreme ray.
 22466                for (int axis = 0; axis < 3; axis++)
 50467                for (int branch = -1; branch <= 1; branch += 2)
 16868                    AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.Axis, axis, -1, branch, para
 45469                for (int a = 0; a < constraints; a++)
 70                {
 159271                    for (int axis = 0; axis < 3; axis++)
 358272                    for (int branch = -1; branch <= 1; branch += 2)
 119473                        AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.AxisPlane, a, axis, bran
 175474                    for (int b = a + 1; b < constraints; b++)
 406875                    for (int branch = -1; branch <= 1; branch += 2)
 135676                        AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.AxisPair, a, b, branch, 
 77                }
 78            }
 23879            else if (candidate.Family == ConeSurfaceFamily.SegmentInterval)
 16080                AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.Interval, 0, 0, 0, parameter, lo
 7881            else if (candidate.Feature == ConeSurfaceFeature.Rim && candidate.Family == ConeSurfaceFamily.NormalCone)
 82            {
 83                // The generators and every linear-boundary intersection
 84                // contain the endpoints of every nonempty clipped interval.
 40085                for (int bound = -2; bound < constraints; bound++)
 18486                    AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.RimBound, bound, 0, 0, param
 87            }
 88            else
 89            {
 90                // Every nonempty proper closed subset of a circle cut by
 91                // halfplanes has a boundary root. Seams cover the full circle.
 61292                for (int seam = 0; seam < 4; seam++)
 24593                    AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.CircleSeam, seam, 0, 0, para
 83094                for (int line = 0; line < constraints; line++)
 212495                for (int branch = -1; branch <= 1; branch += 2)
 70896                    AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.CircleBoundary, line, 0, bra
 6197                if (candidate.Family == ConeSurfaceFamily.NormalCone)
 98                {
 99                    // A clipped disk also needs the center and polygon
 100                    // vertices: its entire feasible polygon may lie inside
 101                    // the circle, with no admissible circle boundary point.
 9102                    AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.DiskCenter, 0, 0, 0, paramet
 152103                    for (int a = 0; a < constraints; a++)
 630104                    for (int b = a + 1; b < constraints; b++)
 248105                        AddFamilyEvent(candidate, geometry, fan, new(ConeSurfaceFamilyEventKind.DiskPair, a, b, 0, param
 106                }
 107            }
 108        }
 179109        return before != selection.Count;
 110    }
 111
 112    private static void AddFamilyEvent(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry geometry,
 113        scoped ReadOnlySpan<WideAxis3> fan, ConeSurfaceFamilyEvent item, scoped ref ConeSurfaceFamilySelection selection
 114        in RationalSegmentInterval clip)
 115    {
 4272116        int FamilyWords = clip.HasWideBounds ? 3 * SegmentConeSurfaceCandidates.FamilyWords : geometry.FamilyWords;
 8544117        Span<ulong> data = stackalloc ulong[24 * FamilyWords], root = stackalloc ulong[FamilyWords];
 4272118        Span<int> signs = stackalloc int[24];
 4272119        var witness = new ConeSurfaceFamilyWitness(data, signs, root);
 5821120        if (!BuildFamilyEvent(candidate, geometry, fan, item, ref witness, clip)) return;
 3641121        if (witness[0].Sign(root) == 0 && witness[1].Sign(root) == 0 && witness[2].Sign(root) == 0) return;
 17374122        for (int index = 0; index < fan.Length + 4; index++)
 123        {
 8141124            FamilyConstraint(geometry, fan, item, witness, index, out Signed832 x, out Signed832 y, out Signed832 z);
 9400125            if (QuadraticNormalDotSign(witness.Values, witness.Signs, witness.Root, x, y, z, FamilyWords) > 0) return;
 126        }
 546127        selection.Add(item);
 545128    }
 129
 130    internal static bool TryGetFamilyWorldAnchors(in SegmentConeSurfaceCandidate candidate, scoped ReadOnlySpan<WideAxis
 131        ConeSurfaceFamilyEvent item, out Vector3d first, out Vector3d second, in RationalSegmentInterval clip = default)
 132    {
 188133        int FamilyWords = clip.HasWideBounds ? 3 * SegmentConeSurfaceCandidates.FamilyWords : candidate.Input.FamilyWord
 376134        Span<ulong> data = stackalloc ulong[24 * FamilyWords], root = stackalloc ulong[FamilyWords];
 188135        Span<int> signs = stackalloc int[24];
 188136        var witness = new ConeSurfaceFamilyWitness(data, signs, root);
 188137        first = second = default;
 191138        if (!BuildFamilyEvent(candidate, new SegmentConeSurfaceGeometry(candidate.Input), fan, item, ref witness, clip))
 185139        return QuadraticPointMaterialization.TryGetWorldPoint(candidate.Input.Center, candidate.Input.ConeRotation,
 185140                witness[3], witness[4], witness[5], witness[9], root, out first)
 185141            && QuadraticPointMaterialization.TryGetWorldPoint(candidate.Input.Center, candidate.Input.ConeRotation,
 185142                witness[6], witness[7], witness[8], witness[9], root, out second);
 143    }
 144
 145    internal static FixedContactAnchors GetFamilyContact(in SegmentConeSurfaceCandidate candidate, scoped ReadOnlySpan<W
 146        ConeSurfaceFamilyEvent item, in RationalSegmentInterval clip = default)
 147    {
 639148        int FamilyWords = clip.HasWideBounds ? 3 * SegmentConeSurfaceCandidates.FamilyWords : candidate.Input.FamilyWord
 1278149        Span<ulong> data = stackalloc ulong[24 * FamilyWords], root = stackalloc ulong[FamilyWords];
 639150        Span<int> signs = stackalloc int[24];
 639151        var witness = new ConeSurfaceFamilyWitness(data, signs, root);
 639152        var geometry = new SegmentConeSurfaceGeometry(candidate.Input);
 639153        if (!BuildFamilyEvent(candidate, geometry, fan, item, ref witness, clip))
 3154            throw new InvalidOperationException("The family certificate requires its original candidate and halfspaces."
 1272155        Vector3d first = RoundSourceSegmentPoint(geometry, witness[10], witness[11], root), second = default;
 5088156        for (int axis = 0; axis < 3; axis++)
 157        {
 1908158            second[axis] = RoundRatio(witness[6 + axis], witness[9], root);
 159        }
 160        // The original candidate and this exact displacement retain the
 161        // family's constant depth; neither normalized normals nor rounded
 162        // anchors participate in depth admission or comparison.
 636163        int squareWords = 2 * FamilyWords + WideArithmetic.GetActiveMagnitudeLength(root) + 3;
 1272164        Span<ulong> work = stackalloc ulong[14 * squareWords]; Span<int> workSigns = stackalloc int[14];
 1272165        ContactQuadratic delta = At(work, workSigns, 0, squareWords), square = At(work, workSigns, 1, squareWords);
 1272166        ContactQuadratic metric = At(work, workSigns, 2, squareWords), divisor = At(work, workSigns, 3, squareWords);
 636167        metric.Clear();
 5088168        for (int axis = 0; axis < 3; axis++)
 169        {
 3816170            witness[3 + axis].CopyTo(delta); delta.Add(witness[6 + axis], -1);
 3816171            Multiply(delta, delta, root, square); metric.Add(square);
 172        }
 636173        Multiply(witness[9], witness[9], root, divisor);
 636174        bool represented = TryRoundSquareRootRatio(metric, divisor, root, out Fixed64 depth);
 636175        Vector3d normal = FamilyWorldNormal(candidate.Input.ConeRotation, witness, work, workSigns, squareWords);
 636176        return new FixedContactAnchors(new FixedPointAnchor(candidate.Input.Origin, candidate.Input.Rotation, first),
 636177            new FixedPointAnchor(candidate.Input.Center, candidate.Input.ConeRotation, second), normal,
 636178            represented ? depth : Fixed64.MaxValue, !represented);
 179    }
 180
 181    private static Vector3d FamilyWorldNormal(FixedQuaternion rotation, scoped ConeSurfaceFamilyWitness witness,
 182        Span<ulong> work, Span<int> signs, int words)
 183    {
 636184        int FamilyWords = witness.FieldWords;
 636185        var basis = new WideRationalBasis3d(rotation);
 1272186        ContactQuadratic metric = At(work, signs, 0, words), product = At(work, signs, 1, words);
 1272187        ContactQuadratic term = At(work, signs, 2, words), square = At(work, signs, 3, words);
 636188        metric.Clear();
 5088189        for (int axis = 0; axis < 3; axis++)
 190        {
 1908191            ContactQuadratic normal = At(work, signs, 4 + axis, words);
 1908192            Scale(witness[0], ExtendFamily(axis == 0 ? basis.Xx : axis == 1 ? basis.Xy : basis.Xz), normal);
 3816193            Scale(witness[1], ExtendFamily(axis == 0 ? basis.Yx : axis == 1 ? basis.Yy : basis.Yz), term); normal.Add(te
 3816194            Scale(witness[2], ExtendFamily(axis == 0 ? basis.Zx : axis == 1 ? basis.Zy : basis.Zz), term); normal.Add(te
 3816195            Multiply(normal, normal, witness.Root, square); metric.Add(square);
 196        }
 636197        Vector3d result = default;
 636198        Signed832 rawSquared = Signed832.ExtendValue(WideArithmetic.MultiplySigned192(Signed192.Raw(Fixed64.One), Signed
 5088199        for (int axis = 0; axis < 3; axis++)
 200        {
 1908201            ContactQuadratic normal = At(work, signs, 4 + axis, words);
 3816202            Multiply(normal, normal, witness.Root, square); Scale(square, rawSquared, product);
 1908203            bool fits = TryRoundSquareRootRatio(product, metric, witness.Root, out Fixed64 coordinate);
 204            System.Diagnostics.Debug.Assert(fits);
 1908205            result[axis] = normal.Sign(witness.Root) < 0 ? -coordinate : coordinate;
 206        }
 636207        return result;
 208    }
 209
 21166210    private static Signed832 ExtendFamily(Signed192 value) => Signed832.ExtendValue(value);
 4351211    private static Signed832 ExtendFamily(Signed320 value) => Signed832.ExtendValue(value);
 212}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.FamilyNormalCones.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.FamilyNormalCones.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.ContactQuadratic;
 10
 11namespace FixedMathSharp.Geometry;
 12
 13/// <content>Rational rim normal intervals and finite-axis polyhedral normal cones.</content>
 14internal static partial class SegmentConeSurfaceCandidates
 15{
 16    private static bool BuildFamilyRimBound(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry geom
 17        scoped ReadOnlySpan<WideAxis3> fan, ConeSurfaceFamilyEvent item, scoped ref ConeSurfaceFamilyWitness witness)
 18    {
 24319        int FamilyWords = witness.FieldWords;
 48620        Span<ulong> work = stackalloc ulong[20 * FamilyWords]; Span<int> signs = stackalloc int[20];
 72921        ContactQuadratic sx = At(work, signs, 0, FamilyWords), sy = At(work, signs, 1, FamilyWords), sz = At(work, signs
 72922        ContactQuadratic cap = At(work, signs, 3, FamilyWords), n = At(work, signs, 4, FamilyWords), d = At(work, signs,
 24323        ContactQuadratic complement = At(work, signs, 7, FamilyWords);
 48624        ContactQuadratic product = At(work, signs, 8, FamilyWords), term = At(work, signs, 9, FamilyWords);
 25        // A zero-depth rim point p has rational coordinates and |p_rad|=R.
 26        // (-H*p.x,-R²,-H*p.z) and (0,R²,0) are exact generators;
 27        // no square root or rounded radial direction is needed here.
 24328        Signed832 height = ExtendFamily(Signed192.Raw(candidate.Input.Height));
 24329        Signed832 radiusSquared = Signed832.ExtendValue(WideArithmetic.MultiplySigned192(
 24330            Signed192.Raw(candidate.Input.Radius), Signed192.Raw(candidate.Input.Radius)));
 48631        Scale(witness[3], height, sx); sx.MultiplySign(-1);
 48632        Scale(witness[5], height, sz); sz.MultiplySign(-1);
 48633        Scale(witness[9], radiusSquared, cap); cap.CopyTo(sy, -1);
 24334        d.Set(ExtendFamily(Signed192.Signed(1)));
 24335        n.Set(ExtendFamily(Signed192.Signed(item.First == -1 ? 1 : 0)));
 24336        if (item.First >= 0)
 37        {
 19438            FamilyConstraint(geometry, fan, item, witness, item.First, out Signed832 x, out Signed832 y, out Signed832 z
 97039            Scale(sx, x, n); Scale(sy, y, term); n.Add(term); Scale(sz, z, term); n.Add(term);
 58240            Scale(cap, y, d); d.Add(n, -1); n.MultiplySign(-1);
 19441            int direction = d.Sign(witness.Root);
 29342            if (direction == 0) return false;
 19043            n.MultiplySign(direction); d.MultiplySign(direction);
 19044            d.CopyTo(complement); complement.Add(n, -1);
 9745            if (n.Sign(witness.Root) < 0 || complement.Sign(witness.Root) < 0) return false;
 46        }
 28447        d.CopyTo(complement); complement.Add(n, -1);
 14248        Multiply(sx, complement, witness.Root, witness[0]);
 14249        Multiply(sy, complement, witness.Root, witness[1]);
 28450        Multiply(cap, n, witness.Root, product); witness[1].Add(product);
 14251        Multiply(sz, complement, witness.Root, witness[2]);
 156252        for (int axis = 0; axis < 3; axis++) witness[3 + axis].CopyTo(witness[6 + axis]);
 14253        return true;
 54    }
 55
 56    private static bool BuildFamilyAxis(in SegmentConeSurfaceGeometry geometry, scoped ReadOnlySpan<WideAxis3> fan,
 57        ConeSurfaceFamilyEvent item, scoped ref ConeSurfaceFamilyWitness witness)
 58    {
 247259        int FamilyWords = witness.FieldWords;
 247260        if (item.Kind == ConeSurfaceFamilyEventKind.Axis)
 15861            witness[item.First].Set(ExtendFamily(Signed192.Signed(item.Branch)));
 62        else
 63        {
 231464            FamilyConstraint(geometry, fan, item, witness, item.First, out Signed832 ax, out Signed832 ay, out Signed832
 65            Signed832 bx, by, bz;
 231466            if (item.Kind == ConeSurfaceFamilyEventKind.AxisPlane)
 67            {
 104268                Signed832 unit = ExtendFamily(Signed192.Signed(1));
 312669                bx = item.Second == 0 ? unit : default; by = item.Second == 1 ? unit : default; bz = item.Second == 2 ? 
 70            }
 127271            else FamilyConstraint(geometry, fan, item, witness, item.Second, out bx, out by, out bz);
 462872            Span<ulong> work = stackalloc ulong[6 * FamilyWords]; Span<int> signs = stackalloc int[6];
 694273            ContactQuadratic left = At(work, signs, 0, FamilyWords), right = At(work, signs, 1, FamilyWords), product = 
 1851274            for (int axis = 0; axis < 3; axis++)
 75            {
 694276                left.Set(axis == 0 ? ay : axis == 1 ? az : ax);
 694277                right.Set(axis == 0 ? bz : axis == 1 ? bx : by);
 694278                Multiply(left, right, witness.Root, witness[axis]);
 694279                left.Set(axis == 0 ? az : axis == 1 ? ax : ay);
 694280                right.Set(axis == 0 ? by : axis == 1 ? bz : bx);
 2082681                Multiply(left, right, witness.Root, product); witness[axis].Add(product, -1); witness[axis].MultiplySign
 82            }
 83        }
 2719284        for (int axis = 0; axis < 3; axis++) witness[3 + axis].CopyTo(witness[6 + axis]);
 247285        return true;
 86    }
 87}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.FamilyParameters.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.FamilyParameters.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.ContactQuadratic;
 10using static FixedMathSharp.Geometry.CylinderContactAlgebra;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <content>Exact segment strata and intrinsic family normal constraints.</content>
 15internal static partial class SegmentConeSurfaceCandidates
 16{
 17    private static bool BuildFamilyEvent(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry geometr
 18        scoped ReadOnlySpan<WideAxis3> fan, ConeSurfaceFamilyEvent item, scoped ref ConeSurfaceFamilyWitness witness,
 19        in RationalSegmentInterval clip = default)
 20    {
 509921        int FamilyWords = witness.FieldWords;
 584722        if (!BuildFamilyParameter(candidate, geometry, item, ref witness, clip)) return false;
 870223        Span<ulong> work = stackalloc ulong[4 * FamilyWords]; Span<int> signs = stackalloc int[4];
 435124        ContactQuadratic term = At(work, signs, 0, FamilyWords);
 3480825        for (int axis = 0; axis < 3; axis++)
 26        {
 1305327            Scale(witness[11], Signed832.ExtendValue(Component(geometry.A, axis)), witness[3 + axis]);
 2610628            Scale(witness[10], Signed832.ExtendValue(Component(geometry.Edge, axis)), term); witness[3 + axis].Add(term)
 29        }
 435130        Scale(witness[11], ExtendFamily(geometry.RawScale), witness[9]);
 435131        if (item.Kind == ConeSurfaceFamilyEventKind.Interval)
 17232            return BuildFamilyInterval(candidate, geometry, ref witness);
 417933        if (item.Kind == ConeSurfaceFamilyEventKind.RimBound)
 24334            return BuildFamilyRimBound(candidate, geometry, fan, item, ref witness);
 393635        if (item.Kind >= ConeSurfaceFamilyEventKind.Axis)
 247236            return BuildFamilyAxis(geometry, fan, item, ref witness);
 146437        return BuildFamilyCircle(candidate, geometry, fan, item, ref witness);
 38    }
 39
 40    private static bool BuildFamilyParameter(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry geo
 41        ConeSurfaceFamilyEvent item, scoped ref ConeSurfaceFamilyWitness witness, in RationalSegmentInterval clip = defa
 42    {
 43
 509944        if (candidate.Family == ConeSurfaceFamily.SegmentInterval)
 204345            return BuildFamilyIntervalParameter(candidate, geometry, item, ref witness, clip);
 46        Signed832 numerator, denominator;
 305647        if (candidate.Feature == ConeSurfaceFeature.Apex)
 47048            TryGetApexParameter(geometry, candidate.RootOrdinal, out numerator, out denominator);
 258649        else if (candidate.Feature == ConeSurfaceFeature.Side && candidate.Input.Radius == Fixed64.Zero)
 134950            GetAxisParameter(geometry, out numerator, out denominator);
 123751        else if (candidate.Feature == ConeSurfaceFeature.Side)
 52        {
 65253            numerator = ExtendFamily(Signed192.Signed(candidate.RootOrdinal));
 65254            denominator = ExtendFamily(Signed192.Signed(1));
 55        }
 58556        else if (candidate.RootOrdinal <= -3)
 57        {
 58            // A zero-depth meridional rim point lies in the base plane.
 59            // Its nonhorizontal segment therefore has the rational parameter
 60            // -(A.y+cap)/E.y even when its original stationary chart used a root.
 13761            numerator = Signed832.ExtendValue(WideArithmetic.Negate(geometry.BaseOffset.Y));
 13762            denominator = Signed832.ExtendValue(geometry.Edge.Y);
 13763            if (denominator.Sign < 0)
 64            {
 4665                numerator = WideArithmetic.SubtractSigned832(default, numerator);
 4666                denominator = WideArithmetic.SubtractSigned832(default, denominator);
 67            }
 68        }
 69        else
 44870            TryGetRimPoint(geometry, candidate.RootOrdinal, out _, out _, out _, out numerator, out denominator);
 611271        witness[10].Set(numerator); witness[11].Set(denominator);
 305672        return (!clip.IsClipped || clip.Contains(witness[10], witness[11], witness.Root))
 305673            && FamilyParameterLocation(witness, clip) == item.PointLocation;
 74    }
 75
 76    private static bool BuildFamilyIntervalParameter(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeom
 77        ConeSurfaceFamilyEvent item, scoped ref ConeSurfaceFamilyWitness witness, in RationalSegmentInterval clip)
 78    {
 204379        int FamilyWords = witness.FieldWords;
 612980        Span<ulong> work = stackalloc ulong[12 * FamilyWords], lowerRoot = stackalloc ulong[FamilyWords], upperRoot = st
 204381        Span<int> signs = stackalloc int[12];
 408682        ContactQuadratic low = At(work, signs, 0, FamilyWords), lowD = At(work, signs, 1, FamilyWords);
 408683        ContactQuadratic high = At(work, signs, 2, FamilyWords), highD = At(work, signs, 3, FamilyWords);
 204384        ContactQuadratic product = At(work, signs, 4, FamilyWords);
 204385        GetFamilyIntervalBound(candidate, geometry, false, low, lowD, lowerRoot, clip);
 204386        GetFamilyIntervalBound(candidate, geometry, true, high, highD, upperRoot, clip);
 204687        if (clip.IsClipped && CompareRatios(low, lowD, lowerRoot, high, highD, upperRoot) > 0) return false;
 204088        (IsZero(lowerRoot) ? upperRoot : lowerRoot).CopyTo(witness.Root);
 408089        ContactQuadratic n = witness[10], d = witness[11];
 288490        if (item.Parameter == 0) { low.CopyTo(n); lowD.CopyTo(d); }
 236091        else if (item.Parameter == 2) { high.CopyTo(n); highD.CopyTo(d); }
 124792        else if (item.Parameter == 1)
 93        {
 94            // Both nonlinear section endpoints use the same discriminant;
 95            // axial/side clipping only replaces an endpoint by a rational.
 138396            Multiply(low, highD, witness.Root, n); Multiply(high, lowD, witness.Root, product); n.Add(product);
 92297            Multiply(lowD, highD, witness.Root, d); d.Add(d);
 98        }
 99        else
 100        {
 786101            if (clip.IsClipped)
 102            {
 4103                n.Set(item.Parameter == 3 ? clip.WideLowerNumerator : clip.WideUpperNumerator);
 4104                d.Set(item.Parameter == 3 ? clip.WideLowerDenominator : clip.WideUpperDenominator);
 105            }
 106            else
 107            {
 782108                n.Set(ExtendFamily(Signed192.Signed(item.Parameter == 3 ? 0 : 1)));
 782109                d.Set(ExtendFamily(Signed192.Signed(1)));
 110            }
 111        }
 2040112        if (CompareRatios(n, d, witness.Root, low, lowD, lowerRoot) < 0
 2040113            || CompareRatios(n, d, witness.Root, high, highD, upperRoot) > 0)
 381114            return false;
 1659115        return FamilyParameterLocation(witness, clip) == item.PointLocation;
 116    }
 117
 118    private static void GetFamilyIntervalBound(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry g
 119        bool upper, ContactQuadratic numerator, ContactQuadratic denominator, Span<ulong> root, in RationalSegmentInterv
 120    {
 4086121        int Words = geometry.Words;
 4086122        int FamilyWords = clip.HasWideBounds ? 3 * SegmentConeSurfaceCandidates.FamilyWords : geometry.FamilyWords;
 4086123        if (candidate.Feature != ConeSurfaceFeature.Side || candidate.Input.Radius == Fixed64.Zero)
 124        {
 3870125            bool exists = FiniteSectionPoint.TryGetSegmentParameter(candidate.Input.Segment, geometry.Finite, upper, num
 126            System.Diagnostics.Debug.Assert(exists);
 127        }
 128        else
 129        {
 648130            Span<ulong> work = stackalloc ulong[24 * Words], oldRoot = stackalloc ulong[Words]; Span<int> signs = stacka
 216131            BuildSideNormal(geometry, -1, candidate.Chart, work, signs, oldRoot);
 216132            TryBuildSideFoot(geometry, -1, work, signs, oldRoot, out _);
 216133            FiniteSectionPoint.TryGetSegmentParameter(candidate.Input.Segment, geometry.Finite, upper, At(work, signs, 5
 216134            ClipSideEndpoint(geometry, upper, work, signs, oldRoot);
 432135            At(work, signs, 5, Words).CopyTo(numerator); At(work, signs, 6, Words).CopyTo(denominator);
 432136            root.Clear(); oldRoot.CopyTo(root);
 137        }
 8106138        if (!clip.IsClipped) return;
 132139        Span<ulong> bounds = stackalloc ulong[4 * FamilyWords]; Span<int> boundSigns = stackalloc int[4];
 132140        ContactQuadratic bound = At(bounds, boundSigns, 0, FamilyWords), boundD = At(bounds, boundSigns, 1, FamilyWords)
 66141        bound.Set(upper ? clip.WideUpperNumerator : clip.WideLowerNumerator);
 66142        boundD.Set(upper ? clip.WideUpperDenominator : clip.WideLowerDenominator);
 66143        int comparison = CompareRatios(bound, boundD, ReadOnlySpan<ulong>.Empty, numerator, denominator, root);
 66144        if (upper ? comparison < 0 : comparison > 0)
 145        {
 189146            bound.CopyTo(numerator); boundD.CopyTo(denominator); root.Clear();
 147        }
 66148    }
 149
 150    private static ConeSurfacePointLocation FamilyParameterLocation(scoped ConeSurfaceFamilyWitness witness,
 151        in RationalSegmentInterval clip = default)
 152    {
 4671153        int FamilyWords = witness.FieldWords;
 4671154        if (clip.IsClipped)
 155        {
 602156            Span<ulong> bounds = stackalloc ulong[4 * FamilyWords]; Span<int> clipSigns = stackalloc int[4];
 602157            ContactQuadratic bound = At(bounds, clipSigns, 0, FamilyWords), boundD = At(bounds, clipSigns, 1, FamilyWord
 602158            bound.Set(clip.WideLowerNumerator); boundD.Set(clip.WideLowerDenominator);
 301159            if (CompareRatios(witness[10], witness[11], witness.Root, bound, boundD, ReadOnlySpan<ulong>.Empty) == 0)
 124160                return ConeSurfacePointLocation.Start;
 354161            bound.Set(clip.WideUpperNumerator); boundD.Set(clip.WideUpperDenominator);
 177162            if (CompareRatios(witness[10], witness[11], witness.Root, bound, boundD, ReadOnlySpan<ulong>.Empty) == 0)
 121163                return ConeSurfacePointLocation.End;
 164        }
 6269165        if (witness[10].Sign(witness.Root) == 0) return ConeSurfacePointLocation.Start;
 5166166        Span<ulong> data = stackalloc ulong[2 * FamilyWords]; Span<int> signs = stackalloc int[2];
 2583167        ContactQuadratic margin = At(data, signs, 0, FamilyWords);
 5166168        witness[11].CopyTo(margin); margin.Add(witness[10], -1);
 2583169        return margin.Sign(witness.Root) == 0 ? ConeSurfacePointLocation.End : ConeSurfacePointLocation.Interior;
 170    }
 171
 172    internal static bool IsInInterval(in SegmentConeSurfaceCandidate candidate, in RationalSegmentInterval clip, bool in
 173    {
 217174        int Words = candidate.Input.Words;
 217175        if (candidate.Family == ConeSurfaceFamily.SegmentInterval)
 2176            throw new ArgumentException("An interval family requires clipping before family event selection.", nameof(ca
 265177        if (!clip.IsClipped) return !interiorOnly || candidate.IsSegmentInterior;
 195178        if (candidate.PointLocation == ConeSurfacePointLocation.Start) return !interiorOnly && clip.WideLowerNumerator.I
 135179        if (candidate.PointLocation == ConeSurfacePointLocation.End)
 30180            return !interiorOnly && clip.WideUpperNumerator.Equals(clip.WideUpperDenominator);
 105181        var geometry = new SegmentConeSurfaceGeometry(candidate.Input);
 105182        if (candidate.Feature == ConeSurfaceFeature.Rim && candidate.Chart >= 0)
 14183            return IsRimParameterInInterval(geometry, candidate, clip, interiorOnly);
 182184        Span<ulong> values = stackalloc ulong[24 * Words], root = stackalloc ulong[Words];
 91185        Span<int> signs = stackalloc int[24];
 182186        ContactQuadratic n = At(values, signs, 5, Words), d = At(values, signs, 6, Words);
 91187        root.Clear();
 91188        if (candidate.Feature == ConeSurfaceFeature.Side && candidate.Input.Radius != Fixed64.Zero)
 189        {
 28190            bool normal = BuildSideNormal(geometry, candidate.RootOrdinal, candidate.Chart, values, signs, root);
 28191            bool foot = TryBuildSideFoot(geometry, candidate.RootOrdinal, values, signs, root, out _);
 192            System.Diagnostics.Debug.Assert(normal && foot);
 193        }
 63194        else if (candidate.Feature == ConeSurfaceFeature.Rim && candidate.RootOrdinal <= -3)
 195        {
 14196            bool admitted = BuildMeridionalRim(geometry, candidate.RootOrdinal, candidate.Chart == -2 ? 1 : -1, values, 
 197            System.Diagnostics.Debug.Assert(admitted);
 198        }
 199        else
 200        {
 201            Signed832 numerator, denominator;
 49202            if (candidate.Feature == ConeSurfaceFeature.Apex)
 14203                TryGetApexParameter(geometry, candidate.RootOrdinal, out numerator, out denominator);
 35204            else if (candidate.Feature == ConeSurfaceFeature.Side)
 7205                GetAxisParameter(geometry, out numerator, out denominator);
 206            else
 28207                TryGetRimPoint(geometry, candidate.RootOrdinal, out _, out _, out _, out numerator, out denominator);
 98208            n.Set(numerator); d.Set(denominator);
 209        }
 117210        if (!clip.Contains(n, d, root)) return false;
 91211        if (!interiorOnly) return true;
 78212        ContactQuadratic bound = At(values, signs, 0, Words), boundD = At(values, signs, 1, Words);
 78213        bound.Set(clip.WideLowerNumerator); boundD.Set(clip.WideLowerDenominator);
 52214        if (CompareRatios(n, d, root, bound, boundD, ReadOnlySpan<ulong>.Empty) == 0) return false;
 52215        bound.Set(clip.WideUpperNumerator); boundD.Set(clip.WideUpperDenominator);
 26216        return CompareRatios(n, d, root, bound, boundD, ReadOnlySpan<ulong>.Empty) != 0;
 217    }
 218
 219    private static void FamilyConstraint(in SegmentConeSurfaceGeometry geometry, scoped ReadOnlySpan<WideAxis3> fan,
 220        ConeSurfaceFamilyEvent item, scoped ConeSurfaceFamilyWitness witness, int index,
 221        out Signed832 x, out Signed832 y, out Signed832 z)
 222    {
 13297223        int FamilyWords = witness.FieldWords;
 13297224        x = y = z = default;
 13297225        if (index < fan.Length)
 226        {
 8011227            WideDirection3d covector = TransformNormalCovector(geometry, fan[index]);
 24033228            x = Signed832.ExtendValue(covector.X); y = Signed832.ExtendValue(covector.Y); z = Signed832.ExtendValue(cove
 8011229            return;
 230        }
 5286231        int intrinsic = index - fan.Length;
 5286232        if (intrinsic < 2)
 233        {
 3385234            if (intrinsic == 1 && item.PointLocation != ConeSurfacePointLocation.Interior) return;
 2253235            int sign = intrinsic == 1 || item.PointLocation == ConeSurfacePointLocation.End ? -1 : 1;
 2253236            x = Signed832.ExtendValue(sign < 0 ? WideArithmetic.Negate(geometry.Edge.X) : geometry.Edge.X);
 2253237            y = Signed832.ExtendValue(sign < 0 ? WideArithmetic.Negate(geometry.Edge.Y) : geometry.Edge.Y);
 2253238            z = Signed832.ExtendValue(sign < 0 ? WideArithmetic.Negate(geometry.Edge.Z) : geometry.Edge.Z);
 2253239            return;
 240        }
 3509241        if (geometry.Input.Radius != Fixed64.Zero || item.Kind < ConeSurfaceFamilyEventKind.Axis) return;
 2850242        Span<ulong> work = stackalloc ulong[4 * FamilyWords]; Span<int> signs = stackalloc int[4];
 2850243        ContactQuadratic twiceY = At(work, signs, 0, FamilyWords), cap = At(work, signs, 1, FamilyWords);
 2850244        witness[4].CopyTo(twiceY); twiceY.Add(twiceY);
 1425245        Scale(witness[9], ExtendFamily(Signed192.Raw(geometry.Input.Height)), cap);
 2850246        cap.Add(twiceY, -1); bool apex = cap.Sign(witness.Root) == 0;
 1425247        Scale(witness[9], ExtendFamily(Signed192.Raw(geometry.Input.Height)), cap);
 2850248        cap.Add(twiceY); bool bottom = cap.Sign(witness.Root) == 0;
 1603249        if (intrinsic == 3 && (apex || bottom)) return;
 1247250        y = ExtendFamily(Signed192.Signed(intrinsic == 3 || bottom ? -1 : 1));
 1247251    }
 252
 253    private static bool BuildFamilyInterval(in SegmentConeSurfaceCandidate candidate, in SegmentConeSurfaceGeometry geom
 254        scoped ref ConeSurfaceFamilyWitness witness)
 255    {
 172256        int Words = geometry.Words;
 172257        int FamilyWords = witness.FieldWords;
 172258        if (candidate.Feature == ConeSurfaceFeature.Base)
 259        {
 102260            witness[1].Set(ExtendFamily(Signed192.Signed(1)));
 204261            witness[3].CopyTo(witness[6]); witness[5].CopyTo(witness[8]);
 102262            Scale(witness[11], Signed832.ExtendValue(WideArithmetic.Negate(geometry.Cap)), witness[7]);
 102263            return true;
 264        }
 210265        Span<ulong> old = stackalloc ulong[24 * Words], oldRoot = stackalloc ulong[Words]; Span<int> oldSigns = stackall
 70266        BuildSideNormal(geometry, -1, candidate.Chart, old, oldSigns, oldRoot);
 70267        TryBuildSideFoot(geometry, -1, old, oldSigns, oldRoot, out _);
 140268        Span<ulong> work = stackalloc ulong[6 * FamilyWords]; Span<int> signs = stackalloc int[6];
 140269        ContactQuadratic product = At(work, signs, 0, FamilyWords), displacement = At(work, signs, 1, FamilyWords);
 70270        ContactQuadratic temporary = At(work, signs, 2, FamilyWords);
 560271        for (int axis = 0; axis < 3; axis++)
 272        {
 210273            At(old, oldSigns, axis, Words).CopyTo(witness[axis]);
 420274            Multiply(witness[3 + axis], At(old, oldSigns, 7, Words), witness.Root, product); product.CopyTo(witness[3 + 
 210275            Multiply(At(old, oldSigns, 8, Words), witness[axis], witness.Root, temporary);
 210276            Multiply(temporary, witness[11], witness.Root, displacement);
 420277            product.Add(displacement, -1); product.CopyTo(witness[6 + axis]);
 278        }
 140279        Multiply(witness[9], At(old, oldSigns, 7, Words), witness.Root, product); product.CopyTo(witness[9]);
 70280        return true;
 281    }
 282}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.MeridionalRim.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.MeridionalRim.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;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <content>The meridional rim's in-plane and axis-crossing stationary pairs.</content>
 15internal static partial class SegmentConeSurfaceCandidates
 16{
 17    private static bool IsMeridionalRim(in SegmentConeSurfaceGeometry geometry) =>
 32218        !geometry.Edge.Y.IsZero && (!geometry.Edge.X.IsZero || !geometry.Edge.Z.IsZero)
 32219        && WideArithmetic.SubtractSigned832(WideArithmetic.MultiplySigned576(geometry.A.X, geometry.Edge.Z),
 32220            WideArithmetic.MultiplySigned576(geometry.A.Z, geometry.Edge.X)).IsZero;
 21
 22    private static void AccumulateMeridionalRim(in SegmentConeSurfaceGeometry geometry, ref ConeSurfaceSelection selecti
 23    {
 17824        int Words = geometry.Words;
 17825        if (geometry.Radius.IsZero || !IsMeridionalRim(geometry))
 13826            return;
 4027        Span<ulong> values = stackalloc ulong[24 * Words];
 4028        Span<int> signs = stackalloc int[24];
 4029        Span<ulong> root = stackalloc ulong[Words];
 24030        for (int mode = -3; mode >= -4; mode--)
 46031        for (int branch = -1; branch <= 1; branch += 2)
 32        {
 15533            if (!BuildMeridionalRim(geometry, mode, branch, values, signs, root))
 34                continue;
 3035            ContactQuadratic margin = At(values, signs, 3, Words);
 6036            At(values, signs, 6, Words).CopyTo(margin); margin.Add(At(values, signs, 5, Words), -1);
 3037            ConeSurfacePointLocation location = At(values, signs, 5, Words).Sign(root) == 0 ? ConeSurfacePointLocation.S
 3038                : margin.Sign(root) == 0 ? ConeSurfacePointLocation.End : ConeSurfacePointLocation.Interior;
 3039            bool zero = At(values, signs, 0, Words).Sign(root) == 0 && At(values, signs, 1, Words).Sign(root) == 0 && At
 3040            if (zero && !HasRimTouchDomain(geometry, new WideDirection3d(geometry.Edge.X, default, geometry.Edge.Z), bra
 3041                    location == ConeSurfacePointLocation.Interior ? -1 : location == ConeSurfacePointLocation.Start ? 0 
 42                continue;
 2843            selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Rim,
 2844                zero ? ConeSurfaceFamily.NormalCone : ConeSurfaceFamily.None, branch > 0 ? -2 : -3, mode, location));
 2845            if (IsZero(root))
 46                break;
 47        }
 4048    }
 49
 50    // Slots 0..2 contain (p-q)*normalScale, 5..6 contain t, 7 normalScale.
 51    // In-plane normals have <995-bit coefficients and root <398 bits.
 52    // Axis-crossing root <1595 bits and normal coefficients <996 bits;
 53    // squaring their complete values needs <2000 coefficient bits.
 54    private static bool BuildMeridionalRim(in SegmentConeSurfaceGeometry geometry, int mode, int branch,
 55        Span<ulong> values, Span<int> signs, Span<ulong> root)
 56    {
 22257        int Words = geometry.Words;
 22258        Signed832 radialSquare = CircularRimContactAlgebra.RadialDot(geometry.Edge, geometry.Edge);
 22259        Signed832 metric = geometry.Edge.SquaredLength;
 66660        ContactQuadratic numerator = At(values, signs, 5, Words), denominator = At(values, signs, 6, Words), normalScale
 44461        ContactQuadratic product = At(values, signs, 3, Words), temporary = At(values, signs, 4, Words);
 22262        root.Clear();
 22263        if (mode == -3)
 64        {
 11365            Signed832 dot = WideDirection3d.Dot(geometry.BaseOffset, geometry.Edge);
 11366            numerator.Set(WideArithmetic.SubtractSigned832(default, dot));
 22667            Import(geometry.Radius, numerator.Radical); numerator.Signs[1] = branch;
 11368            denominator.Set(metric);
 11369            Import(radialSquare, root);
 90470            for (int axis = 0; axis < 3; axis++)
 71            {
 33972                ContactQuadratic normal = At(values, signs, axis, Words);
 33973                normal.Set(Signed832.ExtendValue(Component(geometry.BaseOffset, axis)));
 33974                Scale(normal, metric, product);
 33975                temporary.Set(Signed832.ExtendValue(Component(geometry.Edge, axis)));
 67876                Scale(temporary, dot, normal); product.Add(normal, -1);
 33977                Scale(product, radialSquare, normal);
 33978                product.Set(WideArithmetic.MultiplySigned576(geometry.Radius, Component(geometry.Edge, axis)));
 33979                Scale(product, axis == 1 ? radialSquare : WideArithmetic.SubtractSigned832(radialSquare, metric), tempor
 67880                temporary.Rational.CopyTo(normal.Radical); normal.Signs[1] = branch * temporary.Signs[0];
 81            }
 22682            product.Set(metric); Scale(product, radialSquare, normalScale);
 83        }
 84        else
 85        {
 10986            numerator.Set(WideArithmetic.SubtractSigned832(default, CircularRimContactAlgebra.RadialDot(geometry.A, geom
 10987            denominator.Set(radialSquare);
 21888            ContactQuadratic axial = At(values, signs, 8, Words), discriminant = At(values, signs, 9, Words);
 21889            axial.Set(Signed832.ExtendValue(geometry.BaseOffset.Y)); Scale(axial, radialSquare, product);
 32790            Scale(numerator, Signed832.ExtendValue(geometry.Edge.Y), temporary); product.Add(temporary); product.CopyTo(
 21891            product.Set(radialSquare); Scale(product, radialSquare, normalScale);
 10992            Scale(normalScale, radialSquare, product);
 10993            Scale(product, WideArithmetic.MultiplySigned576(geometry.Radius, geometry.Radius), discriminant);
 10994            Multiply(axial, axial, root, product);
 21895            Scale(product, WideArithmetic.MultiplySigned576(geometry.Edge.Y, geometry.Edge.Y), temporary); discriminant.
 10996            if (discriminant.Sign(root) < 0)
 3897                return false;
 7198            discriminant.Rational.CopyTo(root);
 56899            for (int axis = 0; axis < 3; axis++)
 100            {
 213101                ContactQuadratic normal = At(values, signs, axis, Words);
 213102                Scale(axial, axis == 1 ? radialSquare
 213103                    : WideArithmetic.MultiplySigned576(geometry.Edge.Y, Component(geometry.Edge, axis)), normal);
 213104                if (axis != 1)
 105                {
 142106                    normal.MultiplySign(-1);
 142107                    Signed576 cross = axis == 0 ? geometry.Edge.Z : WideArithmetic.Negate(geometry.Edge.X);
 284108                    Import(cross, normal.Radical); normal.Signs[1] = branch * cross.Sign;
 109                }
 110            }
 111        }
 368112        denominator.CopyTo(product); product.Add(numerator, -1);
 184113        return numerator.Sign(root) >= 0 && product.Sign(root) >= 0
 184114            && ContainsQuadraticParameter(geometry, numerator, denominator, root);
 115    }
 116
 117    private static FixedContactAnchors GetMeridionalRimContact(in SegmentConeSurfaceCandidate candidate)
 118    {
 23119        int Words = candidate.Input.Words;
 23120        var geometry = new SegmentConeSurfaceGeometry(candidate.Input);
 23121        Span<ulong> values = stackalloc ulong[24 * Words];
 23122        Span<int> signs = stackalloc int[24];
 23123        Span<ulong> root = stackalloc ulong[Words];
 23124        bool admitted = BuildMeridionalRim(geometry, candidate.RootOrdinal, candidate.Chart == -2 ? 1 : -1, values, sign
 125        System.Diagnostics.Debug.Assert(admitted);
 23126        return MaterializeMeridionalRim(geometry, candidate, values, signs, root);
 127    }
 128
 129    private static FixedContactAnchors MaterializeMeridionalRim(in SegmentConeSurfaceGeometry geometry,
 130        in SegmentConeSurfaceCandidate candidate, Span<ulong> normals, Span<int> normalSigns, ReadOnlySpan<ulong> root)
 131    {
 23132        int Words = geometry.Words;
 23133        Span<ulong> values = stackalloc ulong[8 * Words];
 23134        Span<int> signs = stackalloc int[8];
 92135        ContactQuadratic sum = At(values, signs, 0, Words), product = At(values, signs, 1, Words), scale = At(values, si
 23136        Scale(At(normals, normalSigns, 7, Words), Signed832.ExtendValue(geometry.RawScale), scale);
 137        Vector3d radial;
 23138        if (candidate.RootOrdinal == -3)
 12139            radial = MaterializeRadialDirection(new WideDirection3d(geometry.Edge.X, default, geometry.Edge.Z),
 12140                geometry.Input.Radius, candidate.Chart == -2 ? 1 : -1);
 141        else
 142        {
 22143            At(normals, normalSigns, 0, Words).CopyTo(product, -1); Fixed64 x = RoundRatio(product, scale, root);
 22144            At(normals, normalSigns, 2, Words).CopyTo(product, -1); Fixed64 z = RoundRatio(product, scale, root);
 11145            radial = new Vector3d(x, Fixed64.Zero, z);
 146        }
 23147        sum.Clear();
 184148        for (int axis = 0; axis < 3; axis++)
 149        {
 138150            Multiply(At(normals, normalSigns, axis, Words), At(normals, normalSigns, axis, Words), root, product); sum.A
 151        }
 23152        Multiply(scale, scale, root, divisor);
 23153        bool represented = TryRoundSquareRootRatio(sum, divisor, root, out Fixed64 depth);
 23154        return new FixedContactAnchors(new FixedPointAnchor(geometry.Input.Origin, geometry.Input.Rotation,
 23155                RoundSourceSegmentPoint(geometry, At(normals, normalSigns, 5, Words), At(normals, normalSigns, 6, Words)
 23156            TriangleCircularGeometry.GetSupport(geometry.Input.Center, geometry.Input.ConeRotation, Signed192.Raw(geomet
 23157            MaterializeQuadraticNormal(normals, normalSigns, root, geometry.Input.ConeRotation), represented ? depth : F
 158    }
 159
 160}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.NormalQueries.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.NormalQueries.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;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <content>Exact linear forms on retained normals, before normal rounding.</content>
 15internal static partial class SegmentConeSurfaceCandidates
 16{
 17    internal static bool TryGetNormalDotSign(in SegmentConeSurfaceCandidate candidate, WideAxis3 authoredCovector, out i
 18    {
 20519        int Words = candidate.Input.Words;
 20520        sign = 0;
 20521        if (candidate.Family != ConeSurfaceFamily.None && candidate.Family != ConeSurfaceFamily.SegmentInterval)
 2622            return false;
 17923        var geometry = new SegmentConeSurfaceGeometry(candidate.Input);
 17924        WideDirection3d transformed = TransformNormalCovector(geometry, authoredCovector);
 53725        Signed832 x = Signed832.ExtendValue(transformed.X), y = Signed832.ExtendValue(transformed.Y), z = Signed832.Exte
 17926        if (candidate.Feature == ConeSurfaceFeature.Base)
 27        {
 2028            sign = y.Sign;
 2029            return true;
 30        }
 15931        if (candidate.Feature == ConeSurfaceFeature.Apex)
 32        {
 7833            Span<ulong> data = stackalloc ulong[10 * Words]; Span<int> fieldSigns = stackalloc int[10];
 11734            ContactQuadratic nx = At(data, fieldSigns, 0, Words), ny = At(data, fieldSigns, 1, Words), nz = At(data, fie
 7835                sum = At(data, fieldSigns, 3, Words), term = At(data, fieldSigns, 4, Words);
 3936            bool admitted = TryBuildApex(geometry, candidate.RootOrdinal, out _, out _, nx, ny, nz);
 37            System.Diagnostics.Debug.Assert(admitted);
 19538            Scale(nx, x, sum); Scale(ny, y, term); sum.Add(term); Scale(nz, z, term); sum.Add(term);
 3939            sign = sum.Signs[0];
 3940            return true;
 41        }
 12042        if (candidate.Feature == ConeSurfaceFeature.Side && geometry.Radius.IsZero)
 143            return false;
 11944        if (candidate.Feature == ConeSurfaceFeature.Rim && candidate.Chart >= 0)
 45        {
 1546            sign = GetRimRootNormalDotSign(geometry, candidate, x, y, z);
 1547            return true;
 48        }
 10449        Span<ulong> values = stackalloc ulong[24 * Words];
 10450        Span<int> signs = stackalloc int[24];
 10451        Span<ulong> root = stackalloc ulong[Words];
 10452        if (candidate.Feature == ConeSurfaceFeature.Side)
 53        {
 7254            bool admitted = BuildSideNormal(geometry, candidate.RootOrdinal, candidate.Chart, values, signs, root);
 55            System.Diagnostics.Debug.Assert(admitted);
 56        }
 3257        else if (candidate.RootOrdinal <= -3)
 58        {
 259            bool admitted = BuildMeridionalRim(geometry, candidate.RootOrdinal, candidate.Chart == -2 ? 1 : -1, values, 
 60            System.Diagnostics.Debug.Assert(admitted);
 61        }
 62        else
 63        {
 3064            bool admitted = TryGetRimPoint(geometry, candidate.RootOrdinal, out WideDirection3d radial,
 3065                out Signed832 radialCoefficient, out Signed576 axial, out _, out _);
 66            System.Diagnostics.Debug.Assert(admitted);
 3067            Import(radial.SquaredLength, root);
 3068            BuildRimPointNormal(geometry, radial, radialCoefficient, axial, radial.SquaredLength,
 3069                candidate.Chart == -2 ? 1 : -1, values, signs);
 70        }
 10471        sign = QuadraticNormalDotSign(values, signs, root, x, y, z, Words);
 10472        return true;
 73    }
 74
 75    private static WideDirection3d TransformNormalCovector(in SegmentConeSurfaceGeometry geometry, in WideAxis3 covector
 819076        new WideDirection3d(covector).Transform(geometry.Input.HasSourceFrame
 819077            ? new WideRationalBasis3d(geometry.Input.ConeRotation.Conjugate()) : geometry.Finite.ShapeFrame.Basis);
 78
 79    private static int QuadraticNormalDotSign(Span<ulong> normals, Span<int> normalSigns, ReadOnlySpan<ulong> root,
 80        Signed832 x, Signed832 y, Signed832 z, int words = Words)
 81    {
 82        // Full Signed320 covectors transform to <452 bits. Isolated normal
 83        // coefficients <996 fit forty words; clipped-family coefficients
 84        // <2220 require the caller's sixty-four-word fields. Three complete
 85        // products and their signed sum fit those respective result widths.
 824586        Span<ulong> values = stackalloc ulong[4 * words];
 824587        Span<int> signs = stackalloc int[4];
 1649088        ContactQuadratic sum = At(values, signs, 0, words), product = At(values, signs, 1, words);
 824589        sum.Clear();
 6596090        for (int axis = 0; axis < 3; axis++)
 91        {
 2473592            Scale(At(normals, normalSigns, axis, words), axis == 0 ? x : axis == 1 ? y : z, product);
 2473593            sum.Add(product);
 94        }
 824595        return sum.Sign(root);
 96    }
 97
 98    private static int GetRimRootNormalDotSign(in SegmentConeSurfaceGeometry geometry, in SegmentConeSurfaceCandidate ca
 99        Signed832 x, Signed832 y, Signed832 z)
 100    {
 15101        int Words = geometry.Words;
 15102        GetRimBasis(geometry.Edge, candidate.Chart, out WideDirection3d first, out WideDirection3d second);
 15103        Span<ulong> data = stackalloc ulong[RimSlots * Words];
 15104        Span<sbyte> signs = stackalloc sbyte[RimSlots];
 15105        TriangleConeRimContacts.BuildConeParameter(geometry.BaseOffset, geometry.Radius, geometry.RawScale,
 15106            geometry.Input.Height, geometry.Input.Radius, first, second, data, signs);
 15107        Span<ulong> cell = stackalloc ulong[WideFiniteAxisIntersection.GetFiniteValueRootCellWords(data[..(5 * Words)], 
 15108        bool found = WideFiniteAxisIntersection.TryGetFiniteValueRoot(data[..(5 * Words)], signs[..5], candidate.RootOrd
 109        System.Diagnostics.Debug.Assert(found);
 15110        Span<ulong> query = stackalloc ulong[2 * Words];
 15111        Span<sbyte> querySigns = stackalloc sbyte[2];
 15112        query.Clear();
 30113        Span<ulong> fields = stackalloc ulong[6 * Words]; Span<int> fieldSigns = stackalloc int[6];
 45114        ContactQuadratic sum = At(fields, fieldSigns, 0, Words), term = At(fields, fieldSigns, 1, Words), scalar = At(fi
 90115        for (int power = 0; power < 2; power++)
 116        {
 30117            WideDirection3d n = power == 0 ? first : second;
 150118            scalar.Set(x); Scale(scalar, n.X, sum); scalar.Set(y); Scale(scalar, n.Y, term); sum.Add(term);
 90119            scalar.Set(z); Scale(scalar, n.Z, term); sum.Add(term);
 60120            sum.Rational.CopyTo(Slot(query, power, Words)); querySigns[power] = (sbyte)sum.Signs[0];
 121        }
 15122        return WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, query, querySigns);
 123    }
 124}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Rim.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.Rim.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 System.Runtime.CompilerServices;
 10using static FixedMathSharp.Geometry.CylinderContactAlgebra;
 11using static FixedMathSharp.Geometry.CircularRimContactAlgebra;
 12
 13namespace FixedMathSharp.Geometry;
 14
 15/// <content>All stationary rim roots with independent exact finite-segment admission.</content>
 16internal static partial class SegmentConeSurfaceCandidates
 17{
 18    private const int RimSlots = 31;
 19
 20    private static bool TryGetRimSquaredDepth(in SegmentConeSurfaceGeometry geometry,
 21        in SegmentConeSurfaceCandidate candidate, Span<ulong> values, Span<sbyte> valueSigns,
 22        Span<ulong> valueCell, out FiniteAxisValueRoot value)
 23    {
 2824        int Words = geometry.Words;
 2825        GetRimBasis(geometry.Edge, candidate.Chart, out WideDirection3d first, out WideDirection3d second);
 2826        Span<ulong> data = stackalloc ulong[RimSlots * Words];
 2827        Span<sbyte> signs = stackalloc sbyte[RimSlots];
 2828        TriangleConeRimContacts.BuildConeParameter(geometry.BaseOffset, geometry.Radius, geometry.RawScale,
 2829            geometry.Input.Height, geometry.Input.Radius, first, second, data, signs);
 2830        Span<ulong> cell = stackalloc ulong[WideFiniteAxisIntersection.GetFiniteValueRootCellWords(data[..(5 * Words)], 
 2831        bool found = WideFiniteAxisIntersection.TryGetFiniteValueRoot(data[..(5 * Words)], signs[..5], candidate.RootOrd
 32        System.Diagnostics.Debug.Assert(found);
 2833        value = default;
 2834        if (Sign(ref parameter, data, signs, 13, 3) == 0)
 835            return false;
 36        // The cone parameter already retains the unsquared admitted gap and
 37        // its squared rational expression. Reuse its existing value polynomial
 38        // and isolator; squaring cannot reverse these nonnegative depths.
 2039        BuildValues(geometry.Edge, geometry.BaseOffset, geometry.Radius, geometry.ValueShift, values, valueSigns);
 2040        scoped FiniteAxisValueRoot mapped = ConvexContactValueRoot.MapSquaredValue(geometry.RawScale, geometry.ValueShif
 2041            ref parameter, data.Slice(16 * Words, 5 * Words), signs.Slice(16, 5), data.Slice(21 * Words, 5 * Words), sig
 2042            values, valueSigns, valueCell);
 43        // Only the mapped polynomial and cell are retained. Rebuild the view
 44        // from caller storage explicitly; the local parameter chart cannot escape.
 2045        value = new FiniteAxisValueRoot
 2046        {
 2047            Coefficients = values[..mapped.Coefficients.Length], Signs = valueSigns[..mapped.Signs.Length],
 2048            LowerNumerator = valueCell, DenominatorShift = mapped.DenominatorShift,
 2049            Ordinal = mapped.Ordinal, IsRational = mapped.IsRational
 2050        };
 2051        return true;
 52    }
 53
 54    private static void AccumulateRimRoots(in SegmentConeSurfaceGeometry geometry, ref ConeSurfaceSelection selection)
 55    {
 56
 57        // Horizontal and axial segments use the principal meridional/circular
 58        // charts. The quartic chart's K!=0 admission deliberately excludes them.
 17859        if (geometry.Edge.Y.IsZero || geometry.Edge.X.IsZero && geometry.Edge.Z.IsZero || geometry.Radius.IsZero || IsMe
 14160            return;
 37061        for (int chart = 0; chart < 4; chart++)
 14862            AccumulateRimChart(geometry, chart, ref selection);
 3763    }
 64
 65    [MethodImpl(MethodImplOptions.NoInlining)]
 66    private static void AccumulateRimChart(in SegmentConeSurfaceGeometry geometry, int chart, ref ConeSurfaceSelection s
 67    {
 14868        int Words = geometry.Words;
 14869        GetRimBasis(geometry.Edge, chart, out WideDirection3d first, out WideDirection3d second);
 14870        Span<ulong> data = stackalloc ulong[RimSlots * Words];
 14871        Span<sbyte> signs = stackalloc sbyte[RimSlots];
 72        // C,R and the affine chart axes are <200 bits; scale<134.
 73        // M<403,P<402,Q<802,K<807,L<1207 give W<2421,N<2426,D<2288:
 74        // the shared forty-word cone parameter retains every coefficient.
 14875        TriangleConeRimContacts.BuildConeParameter(geometry.BaseOffset, geometry.Radius, geometry.RawScale,
 14876            geometry.Input.Height, geometry.Input.Radius, first, second, data, signs);
 14877        Span<ulong> batchCells = stackalloc ulong[64];
 14878        Span<int> batchShifts = stackalloc int[8];
 14879        FiniteAxisValueRoots roots = WideFiniteAxisIntersection.GetFiniteValueRoots(
 14880            data[..(5 * Words)], signs[..5], batchCells, batchShifts);
 14881        Span<ulong> cell = stackalloc ulong[WideFiniteAxisIntersection.GetFiniteValueRootCellWords(data[..(5 * Words)], 
 67282        for (int ordinal = 0; ordinal < roots.Count; ordinal++)
 83        {
 18884            FiniteAxisValueRoot root = FiniteAxisValueRoots.GetRoot(roots, ordinal, data[..(5 * Words)], signs[..5], cel
 18885            int kSign = Sign(ref root, data, signs, 8, 2);
 18886            if (kSign == 0 || Sign(ref root, data, signs, 10, 3) != -kSign)
 87                continue;
 9088            if (Sign(ref root, data, signs, 26, 2) < 0 && Sign(ref root, data, signs, 28, 3) <= 0)
 89                continue;
 90            // n.E=0 and the preflight supplies an intersecting segment point.
 91            // Its projection is at least the finite cone support minimum.
 92#if DEBUG
 93            System.Diagnostics.Debug.Assert(Sign(ref root, data, signs, 13, 3) * kSign >= 0);
 94#endif
 6295            if (!AdmitRimParameter(geometry, first, second, ref root, out ConeSurfacePointLocation location))
 96                continue;
 3097            selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, chart, ordinal, location));
 98        }
 14899    }
 100
 101    private static void GetRimBasis(WideDirection3d edge, int chart, out WideDirection3d first, out WideDirection3d seco
 102    {
 238103        GetBasis(edge, out first, out second);
 104        // Consecutive (+u,+v,-u,-v) quadrant endpoints. The isolator's (0,1]
 105        // domain includes each basis axis as the preceding quadrant's end.
 314106        if (chart == 1) (first, second) = (second, -first);
 200107        else if (chart == 2) (first, second) = (-first, -second);
 191108        else if (chart == 3) (first, second) = (-second, first);
 238109        second = new WideDirection3d(WideArithmetic.SubtractSigned576(second.X, first.X),
 238110            WideArithmetic.SubtractSigned576(second.Y, first.Y), WideArithmetic.SubtractSigned576(second.Z, first.Z));
 238111    }
 112
 113    private static void GetRimParameter(in SegmentConeSurfaceGeometry geometry, WideDirection3d first, WideDirection3d s
 114        out Signed832 a0, out Signed832 a1, out Signed832 b0, out Signed832 b1, out Signed832 d0, out Signed832 d1)
 115    {
 116
 109117        WideDirection3d tangent0 = new(WideArithmetic.Negate(first.Z), default, first.X);
 109118        WideDirection3d tangent1 = new(WideArithmetic.Negate(second.Z), default, second.X);
 218119        a0 = WideDirection3d.Dot(geometry.A, tangent0); a1 = WideDirection3d.Dot(geometry.A, tangent1);
 218120        b0 = WideDirection3d.Dot(geometry.B, tangent0); b1 = WideDirection3d.Dot(geometry.B, tangent1);
 218121        d0 = WideArithmetic.SubtractSigned832(b0, a0); d1 = WideArithmetic.SubtractSigned832(b1, a1);
 109122    }
 123
 124    private static bool IsRimParameterInInterval(in SegmentConeSurfaceGeometry geometry,
 125        in SegmentConeSurfaceCandidate candidate, in RationalSegmentInterval clip, bool interiorOnly)
 126    {
 14127        int Words = geometry.Words;
 14128        GetRimBasis(geometry.Edge, candidate.Chart, out WideDirection3d first, out WideDirection3d second);
 28129        Span<ulong> data = stackalloc ulong[RimSlots * Words]; Span<sbyte> signs = stackalloc sbyte[RimSlots];
 14130        TriangleConeRimContacts.BuildConeParameter(geometry.BaseOffset, geometry.Radius, geometry.RawScale,
 14131            geometry.Input.Height, geometry.Input.Radius, first, second, data, signs);
 14132        Span<ulong> cell = stackalloc ulong[WideFiniteAxisIntersection.GetFiniteValueRootCellWords(data[..(5 * Words)], 
 14133        bool found = WideFiniteAxisIntersection.TryGetFiniteValueRoot(data[..(5 * Words)], signs[..5], candidate.RootOrd
 134        System.Diagnostics.Debug.Assert(found);
 14135        GetRimParameter(geometry, first, second, out Signed832 a0, out Signed832 a1,
 14136            out _, out _, out Signed832 d0, out Signed832 d1);
 28137        Span<ulong> query = stackalloc ulong[2 * Words]; Span<sbyte> querySigns = stackalloc sbyte[2];
 14138        int denominatorSign = LinearSign(ref root, d0, d1, query, querySigns);
 60139        for (int bound = 0; bound < 2; bound++)
 140        {
 24141            Signed832 n = bound == 0 ? clip.WideLowerNumerator : clip.WideUpperNumerator;
 24142            Signed832 d = bound == 0 ? clip.WideLowerDenominator : clip.WideUpperDenominator;
 143            // t=-a(u)/d(u). Full clip weights add at most 319 bits to
 144            // the <432-bit affine coefficients; Signed832 retains both products.
 144145            for (int power = 0; power < 2; power++)
 146            {
 48147                Span<ulong> destination = Slot(query, power, Words);
 48148                CylinderContactAlgebra.DifferenceOfProducts(power == 0 ? a0 : a1, d,
 48149                    WideArithmetic.SubtractSigned832(default, power == 0 ? d0 : d1), n, destination, out int coefficient
 48150                querySigns[power] = (sbyte)-coefficientSign;
 151            }
 24152            int sign = denominatorSign * WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, query, q
 28153            if (bound == 0 ? sign < 0 : sign > 0) return false;
 24154            if (interiorOnly && sign == 0) return false;
 155        }
 6156        return true;
 157    }
 158
 159    private static bool AdmitRimParameter(in SegmentConeSurfaceGeometry geometry, WideDirection3d first, WideDirection3d
 160        ref FiniteAxisValueRoot root, out ConeSurfacePointLocation location)
 161    {
 62162        int Words = geometry.Words;
 62163        GetRimParameter(geometry, first, second, out Signed832 a0, out Signed832 a1,
 62164            out Signed832 b0, out Signed832 b1, out Signed832 d0, out Signed832 d1);
 62165        Span<ulong> query = stackalloc ulong[2 * Words];
 62166        Span<sbyte> querySigns = stackalloc sbyte[2];
 62167        int denominatorSign = LinearSign(ref root, d0, d1, query, querySigns);
 62168        location = ConeSurfacePointLocation.SegmentIntervalUnspecified;
 169        // The unsquared stationary equation makes p-q parallel to n.
 170        // Its radial tangent recovers the same finite foot directly; a
 171        // zero denominator would be a separately handled principal stratum.
 172        System.Diagnostics.Debug.Assert(denominatorSign != 0);
 62173        int lower = -denominatorSign * LinearSign(ref root, a0, a1, query, querySigns);
 62174        int upper = denominatorSign * LinearSign(ref root, b0, b1, query, querySigns);
 62175        if (lower < 0 || upper < 0)
 26176            return false;
 36177        location = lower == 0 ? ConeSurfacePointLocation.Start : upper == 0 ? ConeSurfacePointLocation.End : ConeSurface
 36178        return ContainsRimFoot(geometry, a0, a1, d0, d1, denominatorSign, ref root);
 179    }
 180
 181    private static int LinearSign(ref FiniteAxisValueRoot root, Signed832 first, Signed832 second,
 182        scoped Span<ulong> values, scoped Span<sbyte> signs)
 183    {
 466184        Write(values, signs, 0, first); Write(values, signs, 1, second);
 233185        return WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, values, signs);
 186    }
 187
 188    [MethodImpl(MethodImplOptions.NoInlining)]
 189    private static bool ContainsRimFoot(in SegmentConeSurfaceGeometry geometry, Signed832 a0, Signed832 a1,
 190        Signed832 d0, Signed832 d1, int denominatorSign, ref FiniteAxisValueRoot root)
 191    {
 36192        int Words = geometry.Words;
 193        // t=-a/d, where both a,d are affine in the retained quartic root.
 194        // Source coordinates <198 bits and a,d <432 give point numerators
 195        // <631. The cone query coefficients are <1390 bits; forty words
 196        // suffice without introducing a second algebraic root or rounding t.
 36197        Span<ulong> points = stackalloc ulong[8 * Words];
 36198        Span<sbyte> pointSigns = stackalloc sbyte[8];
 36199        WideDirection3d start = new(geometry.A.X, WideArithmetic.SubtractSigned576(geometry.Cap, geometry.A.Y), geometry
 36200        WideDirection3d delta = new(geometry.Edge.X, WideArithmetic.Negate(geometry.Edge.Y), geometry.Edge.Z);
 288201        for (int axis = 0; axis < 3; axis++)
 648202        for (int power = 0; power < 2; power++)
 203        {
 216204            Span<ulong> destination = Slot(points, 2 * axis + power, Words);
 216205            CylinderContactAlgebra.DifferenceOfProducts(power == 0 ? d0 : d1, Signed832.ExtendValue(Component(start, axi
 216206                power == 0 ? a0 : a1, Signed832.ExtendValue(Component(delta, axis)), destination, out int coefficientSig
 216207            pointSigns[2 * axis + power] = (sbyte)(denominatorSign * coefficientSign);
 208        }
 72209        Write(points, pointSigns, 6, d0); Write(points, pointSigns, 7, d1);
 72210        pointSigns[6] *= (sbyte)denominatorSign; pointSigns[7] *= (sbyte)denominatorSign;
 36211        if (WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, points.Slice(2 * Words, 2 * Words), p
 3212            return false;
 33213        Span<ulong> query = stackalloc ulong[3 * Words];
 33214        Span<sbyte> querySigns = stackalloc sbyte[3];
 33215        Span<ulong> product = stackalloc ulong[Words];
 33216        Span<ulong> scale = stackalloc ulong[Words];
 33217        Import(geometry.FullHeight, scale);
 198218        for (int power = 0; power < 2; power++)
 219        {
 66220            WideArithmetic.MultiplyMagnitudes(Slot(points, 6 + power, Words), scale, Slot(query, power, Words));
 66221            int sign = pointSigns[6 + power];
 66222            CylinderContactAlgebra.Add(Slot(points, 2 + power, Words), -pointSigns[2 + power], Slot(query, power, Words)
 66223            querySigns[power] = (sbyte)sign;
 224        }
 33225        if (WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, query[..(2 * Words)], querySigns[..2]
 3226            return false;
 60227        query.Clear(); querySigns.Clear();
 30228        Span<ulong> square = stackalloc ulong[3 * Words];
 30229        Span<sbyte> squareSigns = stackalloc sbyte[3];
 240230        for (int axis = 0; axis < 3; axis++)
 231        {
 90232            ReadOnlySpan<ulong> coordinate = points.Slice(2 * axis * Words, 2 * Words);
 90233            ReadOnlySpan<sbyte> coordinateSigns = pointSigns.Slice(2 * axis, 2);
 90234            WideFiniteAxisIntersection.MultiplyFiniteAxisPolynomials(coordinate, coordinateSigns,
 90235                coordinate, coordinateSigns, square, squareSigns, product);
 90236            Signed192 dimension = Signed192.Raw(axis == 1 ? geometry.Input.Radius : geometry.Input.Height);
 90237            Import(WideArithmetic.MultiplySigned192(dimension, dimension), scale);
 720238            for (int power = 0; power < 3; power++)
 239            {
 270240                WideArithmetic.MultiplyMagnitudes(Slot(square, power, Words), scale, product);
 270241                int sign = querySigns[power];
 270242                CylinderContactAlgebra.Add(product, squareSigns[power] * (axis == 1 ? -1 : 1), Slot(query, power, Words)
 270243                querySigns[power] = (sbyte)sign;
 244            }
 245        }
 30246        return WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, query, querySigns) <= 0;
 247    }
 248
 249    [MethodImpl(MethodImplOptions.NoInlining)]
 250    internal static FixedContactAnchors GetRimRootContact(in SegmentConeSurfaceCandidate candidate)
 251    {
 33252        int Words = candidate.Input.Words;
 33253        int ValueWords = candidate.Input.ValueWords;
 33254        int ValueCellWords = (16 * (ValueWords * 64 + 11) + 255) / 64;
 33255        var geometry = new SegmentConeSurfaceGeometry(candidate.Input);
 33256        GetRimBasis(geometry.Edge, candidate.Chart, out WideDirection3d first, out WideDirection3d second);
 33257        Span<ulong> data = stackalloc ulong[RimSlots * Words];
 33258        Span<sbyte> signs = stackalloc sbyte[RimSlots];
 33259        TriangleConeRimContacts.BuildConeParameter(geometry.BaseOffset, geometry.Radius, geometry.RawScale,
 33260            geometry.Input.Height, geometry.Input.Radius, first, second, data, signs);
 33261        Span<ulong> cell = stackalloc ulong[WideFiniteAxisIntersection.GetFiniteValueRootCellWords(data[..(5 * Words)], 
 33262        bool found = WideFiniteAxisIntersection.TryGetFiniteValueRoot(data[..(5 * Words)], signs[..5], candidate.RootOrd
 263        System.Diagnostics.Debug.Assert(found);
 33264        GetRimParameter(geometry, first, second, out Signed832 a0, out Signed832 a1,
 33265            out Signed832 b0, out Signed832 b1, out Signed832 d0, out Signed832 d1);
 33266        Span<ulong> query = stackalloc ulong[2 * Words];
 33267        Span<sbyte> querySigns = stackalloc sbyte[2];
 33268        int denominatorSign = LinearSign(ref root, d0, d1, query, querySigns);
 33269        FixedSegment segment = candidate.Input.Segment;
 33270        Vector3d point = default;
 264271        for (int axis = 0; axis < 3; axis++)
 99272            point[axis] = geometry.Input.IsAffine
 99273                ? TriangleCylinderRimWitnesses.RoundRootCoordinate(Component(geometry.A, axis), Component(geometry.B, ax
 99274                    geometry.RawScale, a0, a1, b0, b1, d0, d1, denominatorSign, ref root)
 99275                : TriangleCylinderRimWitnesses.RoundRootCoordinate(segment.Start[axis], segment.End[axis],
 99276                    a0, a1, b0, b1, d0, d1, denominatorSign, ref root);
 33277        Span<ulong> gradient = stackalloc ulong[54];
 33278        Span<sbyte> gradientSigns = stackalloc sbyte[6];
 33279        WriteGradient(first, second, gradient, gradientSigns);
 66280        gradient.Slice(18, 18).Clear(); gradientSigns.Slice(2, 2).Clear();
 33281        Vector3d radialPoint = ConvexContactValueRoot.GetScaledNormalizedDirection(ref root, gradient, gradientSigns, ca
 33282        var basis = new WideRationalBasis3d(candidate.Input.ConeRotation);
 33283        WriteGradient(Transform(basis, first), Transform(basis, second), gradient, gradientSigns);
 33284        Vector3d normal = ConvexContactValueRoot.GetNormalizedDirection(ref root, gradient, gradientSigns, 1);
 33285        Fixed64 depth = default;
 33286        bool clamped = false;
 33287        if (Sign(ref root, data, signs, 13, 3) != 0)
 288        {
 30289            Span<ulong> values = stackalloc ulong[5 * ValueWords];
 30290            Span<sbyte> valueSigns = stackalloc sbyte[5];
 30291            Span<ulong> valueCell = stackalloc ulong[ValueCellWords];
 30292            BuildValues(geometry.Edge, geometry.BaseOffset, geometry.Radius, geometry.ValueShift, values, valueSigns);
 30293            FiniteAxisValueRoot value = ConvexContactValueRoot.MapSquaredValue(geometry.RawScale, geometry.ValueShift,
 30294                ref root, data.Slice(16 * Words, 5 * Words), signs.Slice(16, 5), data.Slice(21 * Words, 5 * Words), sign
 30295                values, valueSigns, valueCell);
 30296            ConvexContactValueRoot.GetRoundedDepth(geometry.RawScale, geometry.ValueShift, ref value, out depth, out cla
 297        }
 33298        return new FixedContactAnchors(new FixedPointAnchor(candidate.Input.Origin, candidate.Input.Rotation, point),
 33299            TriangleCircularGeometry.GetSupport(candidate.Input.Center, candidate.Input.ConeRotation,
 33300                Signed192.Raw(candidate.Input.Height), radialPoint, 1), normal, depth, clamped);
 301    }
 302}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.RimPoints.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.RimPoints.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;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <content>Endpoint and axial-edge rim pairs, including exact rotational domains.</content>
 15internal static partial class SegmentConeSurfaceCandidates
 16{
 17    private static void AccumulateRimPoints(in SegmentConeSurfaceGeometry geometry, ref ConeSurfaceSelection selection)
 18    {
 17819        int Words = geometry.Words;
 17820        if (geometry.Radius.IsZero)
 1921            return;
 15922        int first = !geometry.Edge.IsZero && geometry.Edge.Y.IsZero || HasSlantedHorizontalRimFoot(geometry) ? -2
 15923            : geometry.Edge.X.IsZero && geometry.Edge.Z.IsZero && !geometry.Edge.Y.IsZero ? -1 : 0;
 15924        int last = geometry.Edge.IsZero ? 0 : 1;
 15925        Span<ulong> values = stackalloc ulong[10 * Words];
 15926        Span<int> signs = stackalloc int[10];
 15927        Span<ulong> root = stackalloc ulong[Words];
 103428        for (int endpoint = first; endpoint <= last; endpoint++)
 29        {
 35830            if (endpoint < 0 && endpoint != first)
 31                continue;
 32232            if (!TryGetRimPoint(geometry, endpoint, out WideDirection3d radialAxis, out Signed832 radialCoefficient,
 32233                    out Signed576 axialOffset, out _, out _))
 34                continue;
 23935            Signed832 radialSquare = radialAxis.SquaredLength;
 23936            if (radialSquare.IsZero)
 37            {
 6638                if (HasRimCircleDomain(geometry, axialOffset, endpoint, values, signs, root))
 6139                    selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Rim,
 6140                        ConeSurfaceFamily.RotationCircle, -2, endpoint, endpoint < 0 ? ConeSurfacePointLocation.Interior
 6141                            : endpoint == 0 ? ConeSurfacePointLocation.Start : ConeSurfacePointLocation.End));
 6142                continue;
 43            }
 17344            Import(radialSquare, root);
 103845            for (int branch = -1; branch <= 1; branch += 2)
 46            {
 34647                BuildRimPointNormal(geometry, radialAxis, radialCoefficient, axialOffset, radialSquare, branch, values, 
 34648                if (!AdmitsEndpointNormal(geometry.Edge, endpoint, values, signs, root))
 49                    continue;
 22450                bool zero = At(values, signs, 0, Words).Sign(root) == 0 && At(values, signs, 1, Words).Sign(root) == 0 &
 22451                if (zero && !HasRimTouchDomain(geometry, radialAxis, branch, endpoint))
 52                    continue;
 22253                selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Rim,
 22254                    zero ? ConeSurfaceFamily.NormalCone : ConeSurfaceFamily.None,
 22255                    branch > 0 ? -2 : -3, endpoint, endpoint < 0 ? ConeSurfacePointLocation.Interior
 22256                        : endpoint == 0 ? ConeSurfacePointLocation.Start : ConeSurfacePointLocation.End));
 57            }
 58        }
 15959    }
 60
 61    private static bool HasSlantedHorizontalRimFoot(in SegmentConeSurfaceGeometry geometry)
 62    {
 12763        int Words = geometry.Words;
 12764        if (geometry.Edge.Y.IsZero || IsMeridionalRim(geometry)
 12765            || geometry.Edge.X.IsZero && geometry.Edge.Z.IsZero)
 9066            return false;
 67        // At a horizontal stationary normal both unsquared chart factors
 68        // vanish. The radial affine foot must lie exactly in the base plane:
 69        // C_y|E_rad|²-(C_rad.E_rad)E_y=0. Products are <596 bits.
 3770        Span<ulong> difference = stackalloc ulong[Words];
 3771        CylinderContactAlgebra.DifferenceOfProducts(CircularRimContactAlgebra.RadialDot(geometry.Edge, geometry.Edge),
 3772            Signed832.ExtendValue(geometry.BaseOffset.Y), CircularRimContactAlgebra.RadialDot(geometry.BaseOffset, geome
 3773            Signed832.ExtendValue(geometry.Edge.Y), difference, out int sign);
 3774        return sign == 0;
 75    }
 76
 77    private static bool HasRimTouchDomain(in SegmentConeSurfaceGeometry geometry, WideDirection3d radialAxis, int branch
 78    {
 2679        int Words = geometry.Words;
 80        // The rim normal cone is generated by inward side and upward base
 81        // normals. A nonzero nonnegative combination satisfies the segment
 82        // tangent condition exactly when their scalar projections straddle
 83        // zero (interior), or one generator has the endpoint's required sign.
 2684        Span<ulong> values = stackalloc ulong[2 * Words];
 2685        Span<int> signs = stackalloc int[2];
 2686        Span<ulong> root = stackalloc ulong[Words];
 2687        ContactQuadratic side = At(values, signs, 0, Words);
 2688        side.Set(WideArithmetic.MultiplySigned832(CircularRimContactAlgebra.RadialDot(radialAxis, geometry.Edge), Signed
 2689        side.MultiplySign(-branch);
 2690        Signed832 vertical = Signed832.ExtendValue(WideArithmetic.MultiplySigned576(geometry.Edge.Y, Signed192.Raw(geome
 5291        Import(vertical, side.Radical); side.Signs[1] = -vertical.Sign;
 2692        Import(radialAxis.SquaredLength, root);
 5293        int sideSign = side.Sign(root), baseSign = geometry.Edge.Y.Sign;
 2694        return endpoint < 0 ? sideSign == 0 || sideSign != baseSign
 2695            : endpoint == 0 ? sideSign <= 0 || baseSign <= 0 : sideSign >= 0 || baseSign >= 0;
 96    }
 97
 98    private static bool TryGetRimPoint(in SegmentConeSurfaceGeometry geometry, int endpoint,
 99        out WideDirection3d radialAxis, out Signed832 radialCoefficient, out Signed576 axialOffset,
 100        out Signed832 numerator, out Signed832 denominator)
 101    {
 1418102        int Words = geometry.Words;
 1418103        denominator = Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(1)));
 1418104        numerator = endpoint == 1 ? denominator : default;
 1418105        WideDirection3d point = endpoint == 1 ? geometry.B : geometry.A;
 1418106        radialAxis = new WideDirection3d(point.X, default, point.Z);
 1418107        radialCoefficient = radialAxis.SquaredLength;
 1418108        axialOffset = WideArithmetic.AddSigned576(point.Y, geometry.Cap);
 1418109        if (endpoint >= 0)
 1181110            return geometry.Finite.ContainsTransformedPoint(geometry.Finite.Transform(endpoint == 0
 1181111                ? geometry.Input.Segment.Start : geometry.Input.Segment.End));
 237112        if (endpoint == -2)
 113        {
 144114            radialAxis = new WideDirection3d(WideArithmetic.Negate(geometry.Edge.Z), default, geometry.Edge.X);
 144115            denominator = radialAxis.SquaredLength;
 144116            numerator = WideArithmetic.SubtractSigned832(default, CircularRimContactAlgebra.RadialDot(geometry.A, geomet
 144117            radialCoefficient = WideDirection3d.Dot(geometry.A, radialAxis);
 144118            if (numerator.Sign <= 0 || WideArithmetic.SubtractSigned832(denominator, numerator).Sign <= 0)
 3119                return false;
 141120            Signed576 pointY = geometry.A.Y;
 141121            if (!geometry.Edge.Y.IsZero)
 122            {
 123                // HasSlantedHorizontalRimFoot established this exact height.
 44124                pointY = WideArithmetic.Negate(geometry.Cap);
 44125                axialOffset = default;
 126            }
 282127            Span<ulong> values = stackalloc ulong[8 * Words]; Span<int> signs = stackalloc int[8];
 564128            ContactQuadratic x = At(values, signs, 0, Words), y = At(values, signs, 1, Words), z = At(values, signs, 2, 
 423129            factor.Set(radialCoefficient); Scale(factor, radialAxis.X, x); Scale(factor, radialAxis.Z, z);
 282130            factor.Set(denominator); Scale(factor, pointY, y);
 141131            return ContainsCenteredRatio(geometry, x, y, z, denominator);
 132        }
 93133        numerator = WideArithmetic.SubtractSigned832(default, Signed832.ExtendValue(geometry.BaseOffset.Y));
 93134        denominator = Signed832.ExtendValue(geometry.Edge.Y);
 93135        if (denominator.Sign < 0)
 136        {
 2137            denominator = WideArithmetic.SubtractSigned832(default, denominator);
 2138            numerator = WideArithmetic.SubtractSigned832(default, numerator);
 139        }
 93140        if (numerator.Sign <= 0 || WideArithmetic.SubtractSigned832(denominator, numerator).Sign <= 0)
 6141            return false;
 87142        axialOffset = default;
 87143        return WideArithmetic.SubtractSigned832(radialCoefficient,
 87144            WideArithmetic.MultiplySigned576(geometry.Radius, geometry.Radius)).Sign <= 0;
 145    }
 146
 147    private static void BuildRimPointNormal(in SegmentConeSurfaceGeometry geometry, WideDirection3d radialAxis,
 148        Signed832 radialCoefficient, Signed576 axialOffset, Signed832 radialSquare, int branch, Span<ulong> values, Span
 149    {
 508150        int Words = geometry.Words;
 508151        ContactQuadratic component = At(values, signs, 3, Words);
 4064152        for (int axis = 0; axis < 3; axis++)
 153        {
 1524154            Signed576 coordinate = axis == 1 ? axialOffset : Component(radialAxis, axis);
 1524155            component.Set(Signed832.ExtendValue(coordinate));
 1524156            ContactQuadratic normal = At(values, signs, axis, Words);
 1524157            Scale(component, axis == 1 ? radialSquare : radialCoefficient, normal);
 1524158            if (axis == 1) continue;
 1016159            Signed832 radical = WideArithmetic.MultiplySigned576(geometry.Radius, coordinate);
 2032160            Import(radical, normal.Radical); normal.Signs[1] = -branch * radical.Sign;
 161        }
 508162    }
 163
 164    private static bool AdmitsEndpointNormal(WideDirection3d edge, int endpoint,
 165        Span<ulong> values, Span<int> signs, ReadOnlySpan<ulong> root)
 166    {
 851167        int Words = values.Length / signs.Length;
 1702168        ContactQuadratic sum = At(values, signs, 3, Words), product = At(values, signs, 4, Words);
 851169        sum.Clear();
 6808170        for (int axis = 0; axis < 3; axis++)
 171        {
 2553172            Scale(At(values, signs, axis, Words), Signed832.ExtendValue(Component(edge, axis)), product);
 2553173            sum.Add(product);
 174        }
 851175        int sign = sum.Sign(root);
 851176        return endpoint < 0 ? sign == 0 : endpoint == 0 ? sign <= 0 : sign >= 0;
 177    }
 178
 179    private static bool HasRimCircleDomain(in SegmentConeSurfaceGeometry geometry, Signed576 axialOffset, int endpoint,
 180        Span<ulong> values, Span<int> signs, Span<ulong> root)
 181    {
 66182        int Words = geometry.Words;
 66183        if (endpoint < 0)
 1184            return true;
 65185        ContactQuadratic bound = At(values, signs, 0, Words);
 65186        bound.Set(WideArithmetic.MultiplySigned576(axialOffset, geometry.Edge.Y));
 130187        Import(geometry.Radius, bound.Radical); bound.Signs[1] = endpoint == 0 ? -1 : 1;
 65188        Import(CircularRimContactAlgebra.RadialDot(geometry.Edge, geometry.Edge), root);
 65189        int sign = bound.Sign(root);
 65190        return endpoint == 0 ? sign <= 0 : sign >= 0;
 191    }
 192
 193    internal static FixedContactAnchors GetRimPointContact(in SegmentConeSurfaceCandidate candidate)
 194    {
 125195        int Words = candidate.Input.Words;
 125196        if (candidate.RootOrdinal <= -3)
 23197            return GetMeridionalRimContact(candidate);
 102198        var geometry = new SegmentConeSurfaceGeometry(candidate.Input);
 102199        bool admitted = TryGetRimPoint(geometry, candidate.RootOrdinal, out WideDirection3d radialAxis,
 102200            out Signed832 radialCoefficient, out Signed576 axialOffset, out Signed832 numerator, out Signed832 denominat
 201        System.Diagnostics.Debug.Assert(admitted);
 102202        Span<ulong> values = stackalloc ulong[10 * Words];
 102203        Span<int> signs = stackalloc int[10];
 102204        Span<ulong> root = stackalloc ulong[Words];
 102205        Signed832 radialSquare = radialAxis.SquaredLength;
 102206        Import(radialSquare, root);
 102207        int branch = candidate.Chart == -2 ? 1 : -1;
 102208        BuildRimPointNormal(geometry, radialAxis, radialCoefficient, axialOffset, radialSquare, branch, values, signs);
 102209        Vector3d radial = MaterializeRadialDirection(radialAxis, candidate.Input.Radius, branch);
 102210        return MaterializeRimPoint(geometry, numerator, denominator, values, signs, root, radial);
 211    }
 212
 213    private static FixedContactAnchors MaterializeRimPoint(in SegmentConeSurfaceGeometry geometry,
 214        Signed832 numerator, Signed832 denominator, Span<ulong> normals, Span<int> normalSigns,
 215        ReadOnlySpan<ulong> root, Vector3d radial)
 216    {
 102217        int Words = geometry.Words;
 102218        Vector3d normal = MaterializeQuadraticNormal(normals, normalSigns, root, geometry.Input.ConeRotation);
 102219        Span<ulong> values = stackalloc ulong[6 * Words];
 102220        Span<int> signs = stackalloc int[6];
 306221        ContactQuadratic square = At(values, signs, 0, Words), sum = At(values, signs, 1, Words), divisor = At(values, s
 102222        sum.Clear();
 816223        for (int axis = 0; axis < 3; axis++)
 224        {
 306225            Multiply(At(normals, normalSigns, axis, Words), At(normals, normalSigns, axis, Words), root, square);
 306226            sum.Add(square);
 227        }
 102228        divisor.Clear();
 102229        WideArithmetic.MultiplyMagnitudes(root, root, divisor.Rational);
 102230        divisor.Signs[0] = 1;
 204231        Span<ulong> scale = stackalloc ulong[Words], squaredScale = stackalloc ulong[Words];
 102232        Import(Signed576.ExtendValue(geometry.RawScale), scale);
 102233        WideArithmetic.MultiplyMagnitudes(scale, scale, squaredScale);
 102234        Scale(divisor, squaredScale, 1, square);
 102235        bool represented = TryRoundSquareRootRatio(sum, square, root, out Fixed64 depth);
 204236        square.Set(numerator); divisor.Set(denominator);
 102237        Vector3d point = RoundSourceSegmentPoint(geometry, square, divisor, ReadOnlySpan<ulong>.Empty);
 102238        return new FixedContactAnchors(new FixedPointAnchor(geometry.Input.Origin, geometry.Input.Rotation, point),
 102239            TriangleCircularGeometry.GetSupport(geometry.Input.Center, geometry.Input.ConeRotation, Signed192.Raw(geomet
 102240            normal, represented ? depth : Fixed64.MaxValue, !represented);
 241    }
 242
 243    private static Vector3d MaterializeRadialDirection(WideDirection3d direction, Fixed64 radius, int orientation)
 244    {
 114245        Span<ulong> values = stackalloc ulong[7 * Words];
 114246        Span<int> signs = stackalloc int[7];
 228247        values.Clear(); signs.Clear();
 912248        for (int axis = 0; axis < 3; axis++)
 249        {
 342250            Signed576 coordinate = Component(direction, axis);
 684251            Import(coordinate, Slot(values, axis, Words)); signs[axis] = orientation * coordinate.Sign;
 252        }
 114253        return WideConvexPrismRelations.GetConvexContactCandidateScaledNormal(new ConvexContactCandidate(values, signs, 
 254    }
 255
 256    private static Vector3d MaterializeQuadraticNormal(Span<ulong> normals, Span<int> normalSigns,
 257        ReadOnlySpan<ulong> root, FixedQuaternion rotation)
 258    {
 274259        int Words = normals.Length / normalSigns.Length;
 260        // Meridional coefficients <996 bits and root <1595; rotating adds
 261        // <65 bits. Complete metric coefficients remain below 2130 bits.
 548262        Span<ulong> local = stackalloc ulong[7 * Words], world = stackalloc ulong[7 * Words];
 548263        Span<int> localSigns = stackalloc int[7], worldSigns = stackalloc int[7];
 1096264        local.Clear(); world.Clear(); localSigns.Clear(); worldSigns.Clear();
 2192265        for (int axis = 0; axis < 3; axis++)
 266        {
 822267            ContactQuadratic n = At(normals, normalSigns, axis, Words);
 1644268            n.Rational.CopyTo(Slot(local, axis, Words)); n.Radical.CopyTo(Slot(local, axis + 3, Words));
 1644269            localSigns[axis] = n.Signs[0]; localSigns[axis + 3] = n.Signs[1];
 270        }
 274271        root.CopyTo(Slot(world, 6, Words));
 274272        var basis = new WideRationalBasis3d(rotation);
 274273        WriteWorldDirection(basis, local[..(3 * Words)], localSigns[..3], world[..(3 * Words)], worldSigns[..3]);
 274274        WriteWorldDirection(basis, local.Slice(3 * Words, 3 * Words), localSigns.Slice(3, 3), world.Slice(3 * Words, 3 *
 274275        return WideConvexPrismRelations.GetConvexContactCandidateNormal(new ConvexContactCandidate(world, worldSigns, 0,
 276    }
 277}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.Side.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.Side.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;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <content>Finite lateral-generator stationary points and parallel slices.</content>
 15internal static partial class SegmentConeSurfaceCandidates
 16{
 17    private static void AccumulateSide(in SegmentConeSurfaceGeometry geometry, ref ConeSurfaceSelection selection)
 18    {
 17819        int Words = geometry.Words;
 17820        if (geometry.Radius.IsZero)
 1921            return;
 15922        Span<ulong> values = stackalloc ulong[24 * Words];
 15923        Span<int> signs = stackalloc int[24];
 15924        Span<ulong> root = stackalloc ulong[Words];
 110825        for (int endpoint = geometry.Edge.IsZero ? 0 : -1; endpoint <= (geometry.Edge.IsZero ? 0 : 1); endpoint++)
 26        {
 39527            WideDirection3d point = endpoint == 1 ? geometry.B : geometry.A;
 39528            if (endpoint >= 0 && point.X.IsZero && point.Z.IsZero)
 29            {
 6730                Vector3d authoredPoint = endpoint == 0 ? geometry.Input.Segment.Start : geometry.Input.Segment.End;
 6731                if (geometry.Finite.ContainsTransformedPoint(geometry.Finite.Transform(authoredPoint))
 6732                    && HasSideCircleDomain(geometry, endpoint, values, signs, root))
 5933                    selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Side,
 5934                        ConeSurfaceFamily.RotationCircle, 1, endpoint, endpoint == 0 ? ConeSurfacePointLocation.Start : 
 5935                continue;
 36            }
 188837            for (int branch = -1; branch <= 1; branch += 2)
 38            {
 63639                if (!BuildSideNormal(geometry, endpoint, branch, values, signs, root))
 40                    continue;
 61241                if (!TryBuildSideFoot(geometry, endpoint, values, signs, root, out bool interval))
 42                    continue;
 26043                selection.Add(new SegmentConeSurfaceCandidate(geometry.Input, ConeSurfaceFeature.Side,
 26044                    interval ? ConeSurfaceFamily.SegmentInterval : ConeSurfaceFamily.None, branch, endpoint,
 26045                    interval ? ConeSurfacePointLocation.SegmentIntervalUnspecified : endpoint < 0 ? ConeSurfacePointLoca
 26046                        : endpoint == 0 ? ConeSurfacePointLocation.Start : ConeSurfacePointLocation.End));
 26047                if (IsZero(root))
 48                    break;
 49            }
 50        }
 15951    }
 52
 53    private static bool BuildSideNormal(in SegmentConeSurfaceGeometry geometry, int endpoint, int branch,
 54        Span<ulong> values, Span<int> signs, Span<ulong> root)
 55    {
 124956        int Words = geometry.Words;
 124957        WideDirection3d axis = endpoint < 0 ? geometry.Edge : endpoint == 0 ? geometry.A : geometry.B;
 124958        Signed832 radial = CircularRimContactAlgebra.RadialDot(axis, axis);
 124959        if (radial.IsZero)
 1860            return false;
 246261        Signed192 h = Signed192.Raw(geometry.Input.Height), r = Signed192.Raw(geometry.Input.Radius);
 369362        ContactQuadratic nx = At(values, signs, 0, Words), ny = At(values, signs, 1, Words), nz = At(values, signs, 2, W
 123163        if (endpoint >= 0)
 64        {
 56565            BuildSidePointNormal(geometry, axis, branch, values, signs, root);
 56566            return true;
 67        }
 66668        Span<ulong> scratch = stackalloc ulong[4 * Words];
 266469        Span<ulong> hSquared = Slot(scratch, 0, Words), rSquared = Slot(scratch, 1, Words), product = Slot(scratch, 2, W
 66670        Import(WideArithmetic.MultiplySigned192(h, h), hSquared);
 66671        Import(WideArithmetic.MultiplySigned192(r, r), rSquared);
 66672        Import(radial, square);
 66673        WideArithmetic.MultiplyMagnitudes(square, hSquared, root);
 66674        Import(WideArithmetic.MultiplySigned576(axis.Y, axis.Y), square);
 66675        WideArithmetic.MultiplyMagnitudes(square, rSquared, product);
 66676        int discriminantSign = 1;
 66677        CylinderContactAlgebra.Add(product, -1, root, ref discriminantSign);
 66678        if (discriminantSign < 0)
 679            return false;
 66080        if (IsZero(root))
 81        {
 82            // At tangency E is parallel to a generator. Cancel the extra
 83            // radial edge factor before constructing finite interval bounds:
 84            // n=(H² Ex sign(Ey),-R² |Ey|,H² Ez sign(Ey)). Components <325 bits.
 31885            ContactQuadratic component = At(values, signs, 3, Words);
 63686            component.Set(Signed832.ExtendValue(axis.X)); Scale(component, hSquared, axis.Y.Sign, nx);
 63687            component.Set(Signed832.ExtendValue(axis.Z)); Scale(component, hSquared, axis.Y.Sign, nz);
 63688            component.Set(Signed832.ExtendValue(axis.Y)); Scale(component, rSquared, -axis.Y.Sign, ny);
 31889            return true;
 90        }
 34291        nx.Set(WideArithmetic.MultiplySigned832(WideArithmetic.MultiplySigned576(axis.Y, axis.X), Signed192.Raw(geometry
 68492        ny.Set(WideArithmetic.MultiplySigned832(radial, Signed192.Raw(geometry.Input.Radius))); ny.MultiplySign(-1);
 34293        nz.Set(WideArithmetic.MultiplySigned832(WideArithmetic.MultiplySigned576(axis.Y, axis.Z), Signed192.Raw(geometry
 68494        Import(axis.Z, nx.Radical); nx.Signs[1] = -branch * axis.Z.Sign;
 68495        Import(axis.X, nz.Radical); nz.Signs[1] = branch * axis.X.Sign;
 34296        return true;
 97    }
 98
 99    private static void BuildSidePointNormal(in SegmentConeSurfaceGeometry geometry, WideDirection3d radialAxis, int bra
 100        Span<ulong> values, Span<int> signs, Span<ulong> root)
 101    {
 565102        int Words = geometry.Words;
 565103        Import(CircularRimContactAlgebra.RadialDot(radialAxis, radialAxis), root);
 1695104        ContactQuadratic nx = At(values, signs, 0, Words), ny = At(values, signs, 1, Words), nz = At(values, signs, 2, W
 1130105        Signed192 h = Signed192.Raw(geometry.Input.Height), r = Signed192.Raw(geometry.Input.Radius);
 1130106        nx.Set(WideArithmetic.MultiplySigned576(radialAxis.X, h)); nx.MultiplySign(-branch);
 1130107        nz.Set(WideArithmetic.MultiplySigned576(radialAxis.Z, h)); nz.MultiplySign(-branch);
 1695108        ny.Clear(); Import(Signed576.ExtendValue(r), ny.Radical); ny.Signs[1] = -1;
 565109    }
 110
 111    private static bool HasSideCircleDomain(in SegmentConeSurfaceGeometry geometry, int endpoint,
 112        Span<ulong> values, Span<int> signs, Span<ulong> root)
 113    {
 65114        int Words = geometry.Words;
 65115        ContactQuadratic limit = At(values, signs, 0, Words);
 65116        limit.Set(WideArithmetic.MultiplySigned576(geometry.Edge.Y, Signed192.Raw(geometry.Input.Radius)));
 65117        limit.MultiplySign(-1);
 65118        Import(Signed576.ExtendValue(Signed192.Raw(geometry.Input.Height)), limit.Radical);
 65119        limit.Signs[1] = endpoint == 0 ? -1 : 1;
 65120        Import(CircularRimContactAlgebra.RadialDot(geometry.Edge, geometry.Edge), root);
 65121        int sign = limit.Sign(root);
 65122        return endpoint == 0 ? sign <= 0 : sign >= 0;
 123    }
 124
 125    // Slots 0..2 are n, 5..6 are finite segment t numerator/denominator,
 126    // 7 is n² (rational), 8 is (A-V)·n, and 9 is qY's numerator over tD*n².
 127    private static void BuildSideMetric(in SegmentConeSurfaceGeometry geometry, int endpoint,
 128        Span<ulong> values, Span<int> signs, ReadOnlySpan<ulong> root)
 129    {
 1153130        int Words = geometry.Words;
 3459131        ContactQuadratic metric = At(values, signs, 7, Words), gap = At(values, signs, 8, Words), product = At(values, s
 2306132        metric.Clear(); gap.Clear();
 1153133        WideDirection3d point = endpoint == 1 ? geometry.B : geometry.A;
 1153134        WideDirection3d offset = new(point.X, WideArithmetic.SubtractSigned576(point.Y, geometry.Cap), point.Z);
 9224135        for (int axis = 0; axis < 3; axis++)
 136        {
 6918137            Multiply(At(values, signs, axis, Words), At(values, signs, axis, Words), root, product); metric.Add(product)
 6918138            Scale(At(values, signs, axis, Words), Signed832.ExtendValue(Component(offset, axis)), product); gap.Add(prod
 139        }
 1153140    }
 141
 142    private static bool TryBuildSideFoot(in SegmentConeSurfaceGeometry geometry, int endpoint,
 143        Span<ulong> values, Span<int> signs, ReadOnlySpan<ulong> root, out bool interval)
 144    {
 1075145        int Words = geometry.Words;
 1075146        interval = false;
 2150147        ContactQuadratic numerator = At(values, signs, 5, Words), denominator = At(values, signs, 6, Words);
 2150148        ContactQuadratic metric = At(values, signs, 7, Words), gap = At(values, signs, 8, Words);
 2150149        ContactQuadratic product = At(values, signs, 3, Words), temporary = At(values, signs, 4, Words);
 1075150        BuildSideMetric(geometry, endpoint, values, signs, root);
 1075151        if (endpoint >= 0)
 152        {
 505153            numerator.Set(Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(endpoint))));
 505154            denominator.Set(Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(1))));
 505155            if (!AdmitsEndpointNormal(geometry.Edge, endpoint, values, signs, root))
 181156                return false;
 157        }
 158        else
 159        {
 570160            Scale(At(values, signs, 2, Words), Signed832.ExtendValue(geometry.A.X), numerator);
 1710161            Scale(At(values, signs, 0, Words), Signed832.ExtendValue(geometry.A.Z), product); numerator.Add(product, -1)
 570162            Scale(At(values, signs, 2, Words), Signed832.ExtendValue(geometry.Edge.X), denominator);
 1140163            Scale(At(values, signs, 0, Words), Signed832.ExtendValue(geometry.Edge.Z), product); denominator.Add(product
 570164            int sign = denominator.Sign(root);
 570165            if (sign == 0)
 166            {
 310167                if (numerator.Sign(root) != 0)
 2168                    return false;
 169#if DEBUG
 170                System.Diagnostics.Debug.Assert(gap.Sign(root) >= 0);
 171#endif
 308172                interval = true;
 308173                return HasSideInterval(geometry, values, signs, root);
 174            }
 520175            numerator.MultiplySign(sign); denominator.MultiplySign(sign);
 520176            denominator.CopyTo(temporary); temporary.Add(numerator, -1);
 260177            if (numerator.Sign(root) <= 0 || temporary.Sign(root) <= 0)
 83178                return false;
 179        }
 180        // The preflight supplies an inside point s. Interior normals have
 181        // n.E=0; an admitted endpoint maximizes n's segment projection.
 182        // Therefore gap>=n.(s-V)>=0 for this inward supporting normal.
 183#if DEBUG
 184        System.Diagnostics.Debug.Assert(gap.Sign(root) >= 0);
 185#endif
 501186        return AdmitsSideParameter(geometry, values, signs, root);
 187    }
 188
 189    private static bool AdmitsSideParameter(in SegmentConeSurfaceGeometry geometry,
 190        Span<ulong> values, Span<int> signs, ReadOnlySpan<ulong> root)
 191    {
 501192        int Words = geometry.Words;
 501193        if (!ContainsQuadraticParameter(geometry, At(values, signs, 5, Words), At(values, signs, 6, Words), root))
 79194            return false;
 844195        ContactQuadratic product = At(values, signs, 3, Words), temporary = At(values, signs, 4, Words);
 1266196        ContactQuadratic qY = At(values, signs, 9, Words), common = At(values, signs, 10, Words), margin = At(values, si
 422197        Scale(At(values, signs, 6, Words), Signed832.ExtendValue(geometry.A.Y), product);
 844198        Scale(At(values, signs, 5, Words), Signed832.ExtendValue(geometry.Edge.Y), temporary); product.Add(temporary);
 422199        Multiply(product, At(values, signs, 7, Words), root, qY);
 422200        Multiply(At(values, signs, 8, Words), At(values, signs, 1, Words), root, product);
 844201        Multiply(product, At(values, signs, 6, Words), root, temporary); qY.Add(temporary, -1);
 422202        Multiply(At(values, signs, 6, Words), At(values, signs, 7, Words), root, common);
 422203        Scale(common, Signed832.ExtendValue(geometry.Cap), margin);
 204        // p is in the cone and gap>=0 with inward ny<0, hence qY>=pY>=-cap.
 205        // Only the upper generator endpoint needs an independent rejection.
 422206        margin.Add(qY, -1);
 422207        return margin.Sign(root) >= 0;
 208    }
 209
 210    private static bool ContainsQuadraticParameter(in SegmentConeSurfaceGeometry geometry,
 211        ContactQuadratic numerator, ContactQuadratic denominator, ReadOnlySpan<ulong> root)
 212    {
 943213        int Words = geometry.Words;
 214        // Isolated t coefficients <660 bits; a reduced parallel-family
 215        // bound has <849 bits. Coordinates then have <1048 bits; the cone
 216        // quadratic (including raw H²/R²) stays below 2225 bits.
 943217        Span<ulong> values = stackalloc ulong[14 * Words];
 943218        Span<int> signs = stackalloc int[14];
 2829219        ContactQuadratic coordinate = At(values, signs, 0, Words), temporary = At(values, signs, 1, Words), square = At(
 3772220        ContactQuadratic radial = At(values, signs, 3, Words), axial = At(values, signs, 4, Words), limit = At(values, s
 943221        radial.Clear();
 5658222        for (int axis = 0; axis < 3; axis += 2)
 223        {
 1886224            Scale(denominator, Signed832.ExtendValue(Component(geometry.A, axis)), coordinate);
 3772225            Scale(numerator, Signed832.ExtendValue(Component(geometry.Edge, axis)), temporary); coordinate.Add(temporary
 3772226            Multiply(coordinate, coordinate, root, square); radial.Add(square);
 227        }
 943228        Scale(denominator, Signed832.ExtendValue(WideArithmetic.SubtractSigned576(geometry.Cap, geometry.A.Y)), axial);
 1886229        Scale(numerator, Signed832.ExtendValue(geometry.Edge.Y), temporary); axial.Add(temporary, -1);
 943230        if (axial.Sign(root) < 0)
 2231            return false;
 1882232        Scale(denominator, Signed832.ExtendValue(geometry.FullHeight), limit); limit.Add(axial, -1);
 941233        if (limit.Sign(root) < 0)
 34234            return false;
 907235        Scale(radial, Signed832.ExtendValue(WideArithmetic.MultiplySigned192(Signed192.Raw(geometry.Input.Height), Signe
 907236        Multiply(axial, axial, root, square);
 907237        Scale(square, Signed832.ExtendValue(WideArithmetic.MultiplySigned192(Signed192.Raw(geometry.Input.Radius), Signe
 907238        result.Add(temporary, -1);
 907239        return result.Sign(root) <= 0;
 240    }
 241
 242    private static bool HasSideInterval(in SegmentConeSurfaceGeometry geometry,
 243        Span<ulong> normals, Span<int> normalSigns, ReadOnlySpan<ulong> root)
 244    {
 308245        int Words = geometry.Words;
 246        // The only dependent tangent case has zero discriminant, hence all
 247        // bounds are rational. Reducing n in BuildSideNormal keeps clipping
 248        // weights <849 bits and the subsequent cone query <2225 bits.
 308249        Span<ulong> values = stackalloc ulong[20 * Words];
 308250        Span<int> signs = stackalloc int[20];
 616251        ContactQuadratic low = At(values, signs, 0, Words), lowD = At(values, signs, 1, Words);
 616252        ContactQuadratic high = At(values, signs, 2, Words), highD = At(values, signs, 3, Words);
 616253        ContactQuadratic bound = At(values, signs, 4, Words), boundD = At(values, signs, 5, Words);
 616254        ContactQuadratic constant = At(values, signs, 6, Words), velocity = At(values, signs, 7, Words);
 616255        ContactQuadratic temporary = At(values, signs, 8, Words), unit = At(values, signs, 9, Words);
 308256        Signed832 one = Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(1)));
 1540257        low.Clear(); lowD.Set(one); high.Set(one); highD.Set(one); unit.Set(one);
 1848258        for (int domain = 0; domain < 2; domain++)
 259        {
 616260            ContactQuadratic divisor = domain == 0 ? At(normals, normalSigns, 7, Words) : unit;
 616261            Scale(divisor, Signed832.ExtendValue(geometry.A.Y), constant);
 616262            if (domain == 0)
 263            {
 308264                Multiply(At(normals, normalSigns, 8, Words), At(normals, normalSigns, 1, Words), root, temporary);
 308265                constant.Add(temporary, -1);
 266            }
 616267            Scale(divisor, Signed832.ExtendValue(geometry.Edge.Y), velocity);
 616268            int velocitySign = velocity.Sign(root);
 269            System.Diagnostics.Debug.Assert(velocitySign != 0);
 3696270            for (int side = -1; side <= 1; side += 2)
 271            {
 1232272                Scale(divisor, Signed832.ExtendValue(geometry.Cap), bound);
 2464273                bound.MultiplySign(side); bound.Add(constant, -1);
 2464274                bound.MultiplySign(velocitySign); velocity.CopyTo(boundD, velocitySign);
 1232275                bool lower = side * velocitySign < 0;
 2464276                ContactQuadratic current = lower ? low : high, currentD = lower ? lowD : highD;
 1232277                int comparison = CompareRatios(bound, boundD, root, current, currentD, root);
 1232278                if (lower ? comparison > 0 : comparison < 0)
 279                {
 124280                    bound.CopyTo(current); boundD.CopyTo(currentD);
 281                }
 282            }
 283        }
 308284        if (CompareRatios(low, lowD, root, high, highD, root) > 0)
 2285            return false;
 286        // E is generator-parallel, so H²|E_rad|²-R² E_y²=0.
 287        // The cone polynomial is linear and reaches its minimum at an end.
 306288        return ContainsQuadraticParameter(geometry, low, lowD, root)
 306289            || ContainsQuadraticParameter(geometry, high, highD, root);
 290    }
 291}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentConeSurfaceCandidates.SideWitnesses.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentConeSurfaceCandidates.SideWitnesses.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;
 11
 12namespace FixedMathSharp.Geometry;
 13
 14/// <content>Final materialization of admitted side points and exact family representatives.</content>
 15internal static partial class SegmentConeSurfaceCandidates
 16{
 17    internal static FixedContactAnchors GetSideContact(in SegmentConeSurfaceCandidate candidate)
 18    {
 14919        int Words = candidate.Input.Words;
 14920        var geometry = new SegmentConeSurfaceGeometry(candidate.Input);
 14921        Span<ulong> values = stackalloc ulong[24 * Words];
 14922        Span<int> signs = stackalloc int[24];
 14923        Span<ulong> root = stackalloc ulong[Words];
 14924        bool normal = BuildSideNormal(geometry, candidate.RootOrdinal, candidate.Chart, values, signs, root);
 14925        bool foot = TryBuildSideFoot(geometry, candidate.RootOrdinal, values, signs, root, out bool interval);
 26        System.Diagnostics.Debug.Assert(normal && foot && !interval);
 14927        return MaterializeSidePoint(geometry, values, signs, root);
 28    }
 29
 30    private static FixedContactAnchors MaterializeSidePoint(in SegmentConeSurfaceGeometry geometry,
 31        Span<ulong> values, Span<int> signs, ReadOnlySpan<ulong> root)
 32    {
 14933        int Words = geometry.Words;
 34        // Normal coefficients <462 bits, metric <925, t coefficients <662.
 35        // Complete q numerators stay <1790 bits, denominators <1720 after
 36        // the frame scale. Parallel slices use the reduced rational normal.
 14937        Span<ulong> work = stackalloc ulong[12 * Words];
 14938        Span<int> workSigns = stackalloc int[12];
 29839        ContactQuadratic point = At(work, workSigns, 0, Words), product = At(work, workSigns, 1, Words);
 29840        ContactQuadratic q = At(work, workSigns, 2, Words), temporary = At(work, workSigns, 3, Words);
 29841        ContactQuadratic common = At(work, workSigns, 4, Words), qDenominator = At(work, workSigns, 5, Words);
 29842        ContactQuadratic numerator = At(values, signs, 5, Words), denominator = At(values, signs, 6, Words);
 29843        ContactQuadratic metric = At(values, signs, 7, Words), gap = At(values, signs, 8, Words);
 14944        Multiply(denominator, metric, root, common);
 14945        Scale(common, Signed832.ExtendValue(geometry.RawScale), qDenominator);
 29846        Vector3d first = RoundSourceSegmentPoint(geometry, numerator, denominator, root), second = default;
 119247        for (int axis = 0; axis < 3; axis++)
 48        {
 44749            Scale(denominator, Signed832.ExtendValue(Component(geometry.A, axis)), point);
 89450            Scale(numerator, Signed832.ExtendValue(Component(geometry.Edge, axis)), product); point.Add(product);
 44751            Multiply(point, metric, root, q);
 44752            Multiply(gap, At(values, signs, axis, Words), root, product);
 89453            Multiply(product, denominator, root, temporary); q.Add(temporary, -1);
 44754            second[axis] = RoundRatio(q, qDenominator, root);
 55        }
 14956        Vector3d normal = MaterializeQuadraticNormal(values, signs, root, geometry.Input.ConeRotation);
 14957        Span<ulong> scale = stackalloc ulong[Words];
 14958        Import(Signed576.ExtendValue(geometry.RawScale), scale);
 59        System.Diagnostics.Debug.Assert(metric.Signs[1] == 0);
 14960        bool represented = TryRoundRootRatio(gap, metric, root, metric.Rational, scale, out Fixed64 depth);
 14961        return new FixedContactAnchors(new FixedPointAnchor(geometry.Input.Origin, geometry.Input.Rotation, first),
 14962            new FixedPointAnchor(geometry.Input.Center, geometry.Input.ConeRotation, second), normal,
 14963            represented ? depth : Fixed64.MaxValue, !represented);
 64    }
 65}

Methods/Properties

AccumulateApex(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceSelection&)
HasApexTouchDomain(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32)
TryGetApexParameter(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
TryBuildApex(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
ContainsCenteredRatio(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Signed832)
CompareWeightedSquares(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Fixed64)
GetApexContact(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&)
MaterializeRationalNormal(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.FixedQuaternion)
MaterializeRationalNormal(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.FixedQuaternion)
AccumulateAxis(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceSelection&)
GetAxisParameter(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
CompareDepths(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&)
CompareRimToAnalyticDepth(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&)
BuildAnalyticSquaredDepth(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,System.Span`1<System.UInt64>,System.Span`1<System.Int32>)
AccumulateSegmentConeSurfaceCandidates(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.ConeSurfaceSelection&)
AccumulateSegmentConeSurfaceCandidates(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.ConeSurfaceSelection&)
AccumulateSegmentConeSurfaceCandidates(FixedMathSharp.Geometry.SegmentConeSurfaceInput&,FixedMathSharp.Geometry.ConeSurfaceSelection&)
AccumulateBase(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceSelection&)
GetBaseContact(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&)
MaterializeBaseContact(FixedMathSharp.Geometry.SegmentConeSurfaceInput&,FixedMathSharp.Fixed64)
MaterializeBaseContact(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>)
RoundSourceSegmentPoint(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>)
RoundSegmentPoint(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>)
ClipSideEndpoint(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Boolean,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>)
BuildFamilyCircle(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness&)
FamilyCircleLine(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness,System.Int32,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
BuildFamilyCircleAnchors(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness&)
GetMaximumFamilyEventCount(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,System.Int32)
AccumulateFamilyEvents(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfacePointLocation,FixedMathSharp.Geometry.ConeSurfaceFamilySelection&,FixedMathSharp.Geometry.RationalSegmentInterval&)
AddFamilyEvent(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilySelection&,FixedMathSharp.Geometry.RationalSegmentInterval&)
TryGetFamilyWorldAnchors(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&,FixedMathSharp.Geometry.RationalSegmentInterval&)
GetFamilyContact(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.RationalSegmentInterval&)
FamilyWorldNormal(FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Int32)
ExtendFamily(FixedMathSharp.Signed192)
ExtendFamily(FixedMathSharp.Signed320)
BuildFamilyRimBound(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness&)
BuildFamilyAxis(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness&)
BuildFamilyEvent(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness&,FixedMathSharp.Geometry.RationalSegmentInterval&)
BuildFamilyParameter(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness&,FixedMathSharp.Geometry.RationalSegmentInterval&)
BuildFamilyIntervalParameter(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness&,FixedMathSharp.Geometry.RationalSegmentInterval&)
GetFamilyIntervalBound(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Boolean,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.Span`1<System.UInt64>,FixedMathSharp.Geometry.RationalSegmentInterval&)
FamilyParameterLocation(FixedMathSharp.Geometry.ConeSurfaceFamilyWitness,FixedMathSharp.Geometry.RationalSegmentInterval&)
IsInInterval(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.RationalSegmentInterval&,System.Boolean)
FamilyConstraint(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Geometry.ConeSurfaceFamilyEvent,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness,System.Int32,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
BuildFamilyInterval(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceFamilyWitness&)
IsMeridionalRim(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&)
AccumulateMeridionalRim(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceSelection&)
BuildMeridionalRim(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Span`1<System.UInt64>)
GetMeridionalRimContact(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&)
MaterializeMeridionalRim(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>)
TryGetNormalDotSign(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.WideAxis3,System.Int32&)
TransformNormalCovector(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.WideAxis3&)
QuadraticNormalDotSign(System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.Int32)
GetRimRootNormalDotSign(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832)
TryGetRimSquaredDepth(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,System.Span`1<System.UInt64>,System.Span`1<System.SByte>,System.Span`1<System.UInt64>,FixedMathSharp.Geometry.FiniteAxisValueRoot&)
AccumulateRimRoots(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceSelection&)
AccumulateRimChart(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,FixedMathSharp.Geometry.ConeSurfaceSelection&)
GetRimBasis(FixedMathSharp.Geometry.WideDirection3d,System.Int32,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.WideDirection3d&)
GetRimParameter(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
IsRimParameterInInterval(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&,FixedMathSharp.Geometry.RationalSegmentInterval&,System.Boolean)
AdmitRimParameter(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.FiniteAxisValueRoot&,FixedMathSharp.Geometry.ConeSurfacePointLocation&)
LinearSign(FixedMathSharp.Geometry.FiniteAxisValueRoot&,FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.Span`1<System.UInt64>,System.Span`1<System.SByte>)
ContainsRimFoot(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.Int32,FixedMathSharp.Geometry.FiniteAxisValueRoot&)
GetRimRootContact(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&)
AccumulateRimPoints(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceSelection&)
HasSlantedHorizontalRimFoot(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&)
HasRimTouchDomain(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.WideDirection3d,System.Int32,System.Int32)
TryGetRimPoint(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Signed832&,FixedMathSharp.Signed576&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
BuildRimPointNormal(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed832,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>)
AdmitsEndpointNormal(FixedMathSharp.Geometry.WideDirection3d,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>)
HasRimCircleDomain(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Signed576,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Span`1<System.UInt64>)
GetRimPointContact(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&)
MaterializeRimPoint(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Vector3d)
MaterializeRadialDirection(FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Fixed64,System.Int32)
MaterializeQuadraticNormal(System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.FixedQuaternion)
AccumulateSide(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ConeSurfaceSelection&)
BuildSideNormal(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Span`1<System.UInt64>)
BuildSidePointNormal(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.WideDirection3d,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Span`1<System.UInt64>)
HasSideCircleDomain(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Span`1<System.UInt64>)
BuildSideMetric(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>)
TryBuildSideFoot(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>,System.Boolean&)
AdmitsSideParameter(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>)
ContainsQuadraticParameter(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>)
HasSideInterval(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>)
GetSideContact(FixedMathSharp.Geometry.SegmentConeSurfaceCandidate&)
MaterializeSidePoint(FixedMathSharp.Geometry.SegmentConeSurfaceGeometry&,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.ReadOnlySpan`1<System.UInt64>)