< Summary

Line coverage
100%
Covered lines: 1022
Uncovered lines: 0
Coverable lines: 1022
Total lines: 1573
Line coverage: 100%
Branch coverage
100%
Covered branches: 680
Total branches: 680
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: TryGetContact(...)100%11100%
File 1: TryGetContact(...)100%22100%
File 1: TryGetFeaturePenetration(...)100%11100%
File 1: TryGetContactCore(...)100%1212100%
File 1: TryGetContact(...)100%11100%
File 1: TryGetContact(...)100%22100%
File 1: TryGetFeaturePenetration(...)100%11100%
File 1: TryGetContactCore(...)100%1616100%
File 1: TryGetContactCore(...)100%88100%
File 1: get_Words()100%66100%
File 1: get_ValueWords()100%22100%
File 1: .ctor(...)100%22100%
File 1: .ctor(...)100%11100%
File 1: get_Words()100%11100%
File 1: Field(...)100%11100%
File 1: Point(...)100%11100%
File 1: Boundary(...)100%11100%
File 1: get_Parameter()100%11100%
File 1: get_ParameterDenominator()100%11100%
File 1: get_Denominator()100%11100%
File 1: Normal(...)100%11100%
File 1: Clear()100%11100%
File 1: CopyTo(...)100%11100%
File 1: .ctor(...)100%11100%
File 1: get_One()100%11100%
File 1: Extend(...)100%11100%
File 1: Extend(...)100%11100%
File 1: SetPoint(...)100%22100%
File 1: ScaleCoordinates(...)100%22100%
File 1: Keep(...)100%4242100%
File 1: Dot(...)100%22100%
File 1: CompareWitnesses(...)100%44100%
File 1: Contains(...)100%2020100%
File 1: Materialize(...)100%3434100%
File 2: AccumulateCurved(...)100%3838100%
File 2: AccumulateCurvedPoint(...)100%1010100%
File 2: SetCap(...)100%22100%
File 2: SetSectionParameter(...)100%2020100%
File 2: AccumulateArcFoot(...)100%2828100%
File 2: AdmitsArc(...)100%22100%
File 2: AccumulateRadialFamily(...)100%3838100%
File 2: SetFamilyNormal(...)100%44100%
File 2: AccumulateTouchNormals(...)100%1616100%
File 2: AccumulateMeridionalRims(...)100%1818100%
File 2: AccumulatePrincipalRims(...)100%3030100%
File 2: KeepRim(...)100%1616100%
File 3: AccumulatePrism(...)100%2626100%
File 3: PrismVertex(...)100%11100%
File 3: Axis(...)100%11100%
File 3: AccumulateStraight(...)100%1212100%
File 3: Seed(...)100%2424100%
File 3: AccumulatePlane(...)100%2424100%
File 3: AccumulateLine(...)100%3030100%
File 3: AccumulateVertex(...)100%88100%
File 3: KeepPlanar(...)100%2424100%
File 3: KeepPlanarNormal(...)100%44100%
File 3: TryImproveObliqueRims(...)100%2828100%
File 3: RimOffset(...)100%66100%
File 3: AccumulateObliqueChart(...)100%3434100%
File 3: RestoreObliqueValue(...)100%11100%
File 3: RimParameter(...)100%11100%
File 3: RootSign(...)100%11100%
File 3: AdmitObliqueFoot(...)100%3232100%
File 3: CompareObliqueParameter(...)100%66100%
File 3: WriteRootCoordinate(...)100%66100%
File 3: ContainsObliqueFoot(...)100%2020100%
File 3: MaterializeOblique(...)100%1818100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// SegmentSlabSurfaceContact.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using static FixedMathSharp.Geometry.CylinderContactAlgebra;
 10
 11namespace FixedMathSharp.Geometry;
 12
 13/// <summary>Exact matched finite segment/slab surface witnesses admitted by an authored normal fan.</summary>
 14/// <content>Finite caps, planar sides and rims share exact candidate admission before minimum-depth selection.</content
 15internal static partial class SegmentSlabSurfaceContact
 16{
 17    // Authored rigid coordinates are <198 bits. Rational edge/edge minors
 18    // are <800 bits; their point products and quadratic radial branches are
 19    // <1100. Squared separations and scaled denominators remain <2400 bits,
 20    // within the existing forty-word contact candidate owner. Exact source
 21    // frames retain <306-bit coordinates and <385-bit local fan directions;
 22    // clip ratios can occupy 832 bits. Each primitive input fits three times
 23    // the original bit bound, so the unchanged fixed-degree formulas use
 24    // three times the borrowed fields. Ordinary rigid inputs keep 40 words.
 25    private const int Fields = 12;
 26
 27    internal static bool TryGetContact(FixedSegment segment, Vector3d origin, FixedQuaternion rotation,
 28        Vector3d slabCenter, FixedQuaternion slabRotation, Fixed64 coreLength, Fixed64 radius,
 29        Fixed64 halfThickness, ReadOnlySpan<Vector2d> prismOffsets,
 30        ReadOnlySpan<WideAxis3> authoredHalfspaces, bool interiorOnly, out FixedContactAnchors contact, bool fullHeight 
 12731        => TryGetContactCore(segment, origin, rotation, slabCenter, slabRotation, coreLength, radius,
 12732            halfThickness, prismOffsets, authoredHalfspaces, interiorOnly, true, default, fullHeight, out contact);
 33
 34    /// <summary>Restricts witnesses to the original segment's exact retained interval before selection.</summary>
 35    internal static bool TryGetContact(FixedSegment segment, Vector3d origin, FixedQuaternion rotation,
 36        Vector3d slabCenter, FixedQuaternion slabRotation, Fixed64 coreLength, Fixed64 radius,
 37        Fixed64 halfThickness, ReadOnlySpan<Vector2d> prismOffsets,
 38        ReadOnlySpan<WideAxis3> authoredHalfspaces, bool interiorOnly,
 39        in RationalSegmentInterval clip, out FixedContactAnchors contact, bool fullHeight = false)
 40    {
 3441        if (!clip.IsClipped)
 242            return TryGetContact(segment, origin, rotation, slabCenter, slabRotation, coreLength, radius,
 243                halfThickness, prismOffsets, authoredHalfspaces, interiorOnly, out contact, fullHeight);
 3244        Span<RationalSegmentInterval> interval = stackalloc RationalSegmentInterval[1] { clip };
 3245        return TryGetContactCore(segment, origin, rotation, slabCenter, slabRotation, coreLength, radius,
 3246            halfThickness, prismOffsets, authoredHalfspaces, interiorOnly, true, interval, fullHeight, out contact);
 47    }
 48
 49    /// <summary>Returns a finite feature exit after the caller independently admits its owner's overlap.</summary>
 50    /// <remarks>The halfspaces must certify both the finite feature's normal fan and global support of its owner.
 51    /// The source witness may lie outside the original slab; its matched slab witness and outward cone remain exact.</r
 52    internal static bool TryGetFeaturePenetration(FixedSegment segment, Vector3d origin, FixedQuaternion rotation,
 53        Vector3d slabCenter, FixedQuaternion slabRotation, Fixed64 coreLength, Fixed64 radius,
 54        Fixed64 halfThickness, ReadOnlySpan<Vector2d> prismOffsets,
 55        ReadOnlySpan<WideAxis3> authoredHalfspaces, bool interiorOnly, out FixedContactAnchors contact, bool fullHeight 
 3956        => TryGetContactCore(segment, origin, rotation, slabCenter, slabRotation, coreLength, radius,
 3957            halfThickness, prismOffsets, authoredHalfspaces, interiorOnly, false, default, fullHeight, out contact);
 58
 59    private static bool TryGetContactCore(FixedSegment segment, Vector3d origin, FixedQuaternion rotation,
 60        Vector3d slabCenter, FixedQuaternion slabRotation, Fixed64 coreLength, Fixed64 radius,
 61        Fixed64 halfThickness, ReadOnlySpan<Vector2d> prismOffsets,
 62        ReadOnlySpan<WideAxis3> authoredHalfspaces, bool interiorOnly, bool requireSourceInside, ReadOnlySpan<RationalSe
 63    {
 19864        contact = default;
 19865        var frame = new FiniteSlabSectionFrame(origin, rotation, slabCenter, slabRotation,
 19866            coreLength, radius, halfThickness, fullHeight);
 20567        if (requireSourceInside && !frame.IntersectsSegment(segment, prismOffsets)) return false;
 19168        Span<WideDirection3d> fan = stackalloc WideDirection3d[authoredHalfspaces.Length + (interiorOnly ? 2 : 0)];
 171869        for (int index = 0; index < authoredHalfspaces.Length; index++)
 66870            fan[index] = new WideDirection3d(WideRigidProjection.TransformLocalAxis(frame.RadialFrame.ShapeFrame.Basis,
 66871                Signed192.NarrowProven(authoredHalfspaces[index].X),
 66872                Signed192.NarrowProven(authoredHalfspaces[index].Y),
 66873                Signed192.NarrowProven(authoredHalfspaces[index].Z)));
 38274        WideDirection3d first = new(frame.Transform(segment.Start)), second = new(frame.Transform(segment.End));
 19175        WideDirection3d edge = TriangleCircularGeometry.Subtract(second, first);
 19176        if (interiorOnly)
 77        {
 10478            if (edge.IsZero) return false;
 20479            fan[^2] = edge; fan[^1] = -edge;
 80        }
 19081        return TryGetContactCore(segment, origin, rotation, slabCenter, slabRotation, coreLength, radius,
 19082            halfThickness, prismOffsets, fan, interiorOnly, requireSourceInside, clip, fullHeight, frame, first, edge, o
 83    }
 84
 85    internal static bool TryGetContact(FixedSegment segment, in ScaledRigidFrame3d sourceFrame,
 86        Vector3d slabCenter, FixedQuaternion slabRotation, Fixed64 coreLength, Fixed64 radius,
 87        Fixed64 halfThickness, ReadOnlySpan<Vector2d> prismOffsets,
 88        ReadOnlySpan<WideAxis3> worldHalfspaces, bool interiorOnly, out FixedContactAnchors contact, bool fullHeight = f
 1789        TryGetContactCore(segment, sourceFrame, slabCenter, slabRotation, coreLength, radius, halfThickness,
 1790            prismOffsets, worldHalfspaces, interiorOnly, true, default, fullHeight, out contact);
 91
 92    internal static bool TryGetContact(FixedSegment segment, in ScaledRigidFrame3d sourceFrame,
 93        Vector3d slabCenter, FixedQuaternion slabRotation, Fixed64 coreLength, Fixed64 radius,
 94        Fixed64 halfThickness, ReadOnlySpan<Vector2d> prismOffsets, ReadOnlySpan<WideAxis3> worldHalfspaces,
 95        bool interiorOnly, in RationalSegmentInterval clip, out FixedContactAnchors contact, bool fullHeight = false)
 96    {
 1297        if (!clip.IsClipped)
 498            return TryGetContact(segment, sourceFrame, slabCenter, slabRotation, coreLength, radius,
 499                halfThickness, prismOffsets, worldHalfspaces, interiorOnly, out contact, fullHeight);
 8100        Span<RationalSegmentInterval> intervals = stackalloc RationalSegmentInterval[1] { clip };
 8101        return TryGetContactCore(segment, sourceFrame, slabCenter, slabRotation, coreLength, radius, halfThickness,
 8102            prismOffsets, worldHalfspaces, interiorOnly, true, intervals, fullHeight, out contact);
 103    }
 104
 105    internal static bool TryGetFeaturePenetration(FixedSegment segment, in ScaledRigidFrame3d sourceFrame,
 106        Vector3d slabCenter, FixedQuaternion slabRotation, Fixed64 coreLength, Fixed64 radius,
 107        Fixed64 halfThickness, ReadOnlySpan<Vector2d> prismOffsets,
 108        ReadOnlySpan<WideAxis3> worldHalfspaces, bool interiorOnly, out FixedContactAnchors contact, bool fullHeight = f
 4109        TryGetContactCore(segment, sourceFrame, slabCenter, slabRotation, coreLength, radius, halfThickness,
 4110            prismOffsets, worldHalfspaces, interiorOnly, false, default, fullHeight, out contact);
 111
 112    private static bool TryGetContactCore(FixedSegment segment, in ScaledRigidFrame3d sourceFrame,
 113        Vector3d center, FixedQuaternion rotation, Fixed64 length, Fixed64 radius, Fixed64 halfThickness,
 114        ReadOnlySpan<Vector2d> offsets, ReadOnlySpan<WideAxis3> worldHalfspaces, bool interiorOnly,
 115        bool requireSourceInside, ReadOnlySpan<RationalSegmentInterval> clip, bool fullHeight, out FixedContactAnchors c
 116    {
 29117        contact = default;
 29118        var frame = new FiniteSlabSectionFrame(sourceFrame, center, rotation, length, radius, halfThickness, fullHeight)
 33119        if (requireSourceInside && !frame.IntersectsSegment(segment, offsets)) return false;
 25120        Span<WideDirection3d> fan = stackalloc WideDirection3d[worldHalfspaces.Length + (interiorOnly ? 2 : 0)];
 25121        var inverse = new WideRationalBasis3d(rotation.Conjugate());
 260122        for (int index = 0; index < worldHalfspaces.Length; index++)
 105123            fan[index] = new WideDirection3d(worldHalfspaces[index]).Transform(inverse);
 50124        WideDirection3d first = new(frame.Transform(segment.Start)), edge = TriangleCircularGeometry.Subtract(new WideDi
 25125        if (interiorOnly)
 126        {
 23127            if (edge.IsZero) return false;
 30128            fan[^2] = edge; fan[^1] = -edge;
 129        }
 21130        return TryGetContactCore(segment, sourceFrame.IsRigid ? sourceFrame.RigidOrigin : center,
 21131            sourceFrame.IsRigid ? sourceFrame.Rotation : rotation, center, rotation, length, radius,
 21132            halfThickness, offsets, fan, interiorOnly, requireSourceInside, clip, fullHeight, frame, first, edge, out co
 133    }
 134
 135    private static bool TryGetContactCore(FixedSegment segment, Vector3d origin, FixedQuaternion rotation,
 136        Vector3d slabCenter, FixedQuaternion slabRotation, Fixed64 coreLength, Fixed64 radius,
 137        Fixed64 halfThickness, ReadOnlySpan<Vector2d> prismOffsets, ReadOnlySpan<WideDirection3d> fan,
 138        bool interiorOnly, bool requireSourceInside, ReadOnlySpan<RationalSegmentInterval> clip, bool fullHeight,
 139        in FiniteSlabSectionFrame frame, WideDirection3d first, WideDirection3d edge, out FixedContactAnchors contact)
 140    {
 211141        contact = default;
 211142        var input = new Input(segment, origin, rotation, slabCenter, slabRotation,
 211143            coreLength, radius, halfThickness, frame, first, edge, prismOffsets, fan, interiorOnly, requireSourceInside,
 211144        int Words = input.Words;
 211145        int StorageWords = Fields * 2 * Words;
 422146        Span<ulong> best = stackalloc ulong[StorageWords], bestRoot = stackalloc ulong[Words];
 211147        Span<int> bestSigns = stackalloc int[2 * Fields];
 211148        Span<ulong> bestMetric = stackalloc ulong[ConvexContactCandidate.Slots * Words];
 211149        Span<int> bestMetricSigns = stackalloc int[ConvexContactCandidate.Slots];
 211150        var selection = new Selection(new Candidate(best, bestSigns, bestRoot), bestMetric, bestMetricSigns);
 364151        if (prismOffsets.IsEmpty) AccumulateCurved(input, ref selection);
 58152        else AccumulatePrism(input, ref selection);
 358153        if (selection.HasValue) contact = Materialize(input, selection);
 211154        if (prismOffsets.IsEmpty && TryImproveObliqueRims(input, selection, out FixedContactAnchors oblique))
 76155        { contact = oblique; return true; }
 173156        return selection.HasValue;
 157    }
 158
 159    private readonly ref struct Input
 160    {
 161        internal readonly FixedSegment Segment;
 162        internal readonly Vector3d Origin, Center;
 163        internal readonly FixedQuaternion Rotation, SlabRotation;
 164        internal readonly Fixed64 Length, Radius, HalfThickness, FullHeight;
 165        internal readonly FiniteSlabSectionFrame Frame;
 166        internal readonly WideDirection3d First, Edge;
 167        internal readonly Signed320 Scale;
 168        internal readonly Signed576 Cap, Core, Radial;
 37263169        internal int Words => Frame.RadialFrame.ShapeFrame.HasExactScale || !Clip.IsEmpty && Clip[0].HasWideBounds ? 120
 1545170        internal int ValueWords => Words == CylinderContactAlgebra.Words ? CircularRimContactAlgebra.ValueWords : 3 * Ci
 171        internal readonly ReadOnlySpan<Vector2d> Offsets;
 172        internal readonly ReadOnlySpan<WideDirection3d> Fan;
 173        internal readonly ReadOnlySpan<RationalSegmentInterval> Clip;
 174        internal readonly bool InteriorOnly, RequireSourceInside;
 175
 176        internal Input(FixedSegment segment, Vector3d origin, FixedQuaternion rotation,
 177            Vector3d center, FixedQuaternion slabRotation, Fixed64 length, Fixed64 radius, Fixed64 halfThickness,
 178            FiniteSlabSectionFrame frame, WideDirection3d first, WideDirection3d edge,
 179            ReadOnlySpan<Vector2d> offsets, ReadOnlySpan<WideDirection3d> fan, bool interiorOnly, bool requireSourceInsi
 180            ReadOnlySpan<RationalSegmentInterval> clip, bool fullHeight)
 181        {
 844182            Segment = segment; Origin = origin; Rotation = rotation; Center = center;
 844183            SlabRotation = slabRotation; Length = length; Radius = radius; Frame = frame;
 422184            HalfThickness = halfThickness; FullHeight = fullHeight ? halfThickness : Fixed64.Zero;
 1055185            First = first; Edge = edge; Offsets = offsets; Fan = fan; InteriorOnly = interiorOnly;
 422186            RequireSourceInside = requireSourceInside; Clip = clip;
 211187            Scale = WideArithmetic.AddSigned320(frame.RadialFrame.ShapeFrame.CoordinateDenominator,
 211188                frame.RadialFrame.ShapeFrame.CoordinateDenominator);
 422189            Cap = Signed576.ExtendValue(frame.Cap); Core = Signed576.ExtendValue(frame.RadialFrame.ShapeFrame.Cap);
 211190            Radial = WideArithmetic.MultiplySigned320(frame.RadialFrame.ShapeFrame.CoordinateDenominator, frame.RadialFr
 211191        }
 192    }
 193
 194    private readonly ref struct Candidate
 195    {
 196        internal readonly Span<ulong> Values, Root;
 197        internal readonly Span<int> Signs;
 198        internal Candidate(Span<ulong> values, Span<int> signs, Span<ulong> root)
 12172199        { Values = values; Signs = signs; Root = root; }
 740162200        internal int Words => Values.Length / (Fields * 2);
 740162201        internal ContactQuadratic Field(int index) => ContactQuadratic.At(Values, Signs, index, Words);
 133152202        internal ContactQuadratic Point(int component) => Field(component);
 113375203        internal ContactQuadratic Boundary(int component) => Field(component + 3);
 50346204        internal ContactQuadratic Parameter => Field(6);
 59312205        internal ContactQuadratic ParameterDenominator => Field(7);
 117402206        internal ContactQuadratic Denominator => Field(8);
 177022207        internal ContactQuadratic Normal(int component) => Field(component + 9);
 208        internal void Clear()
 209        {
 23259210            Values.Clear(); Signs.Clear(); Root.Clear();
 15506211            ParameterDenominator.Set(One); Denominator.Set(One);
 7753212        }
 213        internal void CopyTo(scoped Candidate target)
 9036214        { Values.CopyTo(target.Values); Signs.CopyTo(target.Signs); Root.CopyTo(target.Root); }
 215    }
 216
 217    private ref struct Selection
 218    {
 219        internal Candidate Best;
 220        internal Span<ulong> Metric;
 221        internal Span<int> MetricSigns;
 222        internal bool HasValue;
 223        internal Selection(Candidate best, Span<ulong> metric, Span<int> metricSigns)
 1055224        { Best = best; Metric = metric; MetricSigns = metricSigns; HasValue = false; }
 225    }
 226
 227    // Homogeneous coefficients use integer unity, rather than Q32.32 raw unity.
 18500228    private static Signed832 One => Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(1)));
 257541229    private static Signed832 Extend(Signed576 value) => Signed832.ExtendValue(value);
 294230    private static Signed832 Extend(Signed320 value) => Signed832.ExtendValue(value);
 231
 232    private static void SetPoint(scoped Input input, scoped Candidate candidate)
 233    {
 8369234        int Words = input.Words;
 16738235        Span<ulong> values = stackalloc ulong[2 * Words]; Span<int> signs = stackalloc int[2];
 8369236        var term = new ContactQuadratic(values, signs);
 66952237        for (int axis = 0; axis < 3; axis++)
 238        {
 25107239            ContactQuadratic.Scale(candidate.ParameterDenominator, Extend(Component(input.First, axis)), candidate.Point
 25107240            ContactQuadratic.Scale(candidate.Parameter, Extend(Component(input.Edge, axis)), term);
 25107241            candidate.Point(axis).Add(term);
 25107242            candidate.Point(axis).CopyTo(candidate.Boundary(axis));
 243        }
 8369244        candidate.ParameterDenominator.CopyTo(candidate.Denominator);
 8369245    }
 246
 247    private static void ScaleCoordinates(scoped Candidate candidate, scoped ContactQuadratic multiplier)
 248    {
 77938249        for (int field = 0; field < 6; field++)
 33402250            ContactQuadratic.Multiply(candidate.Field(field), multiplier, candidate.Root, candidate.Field(field));
 5567251        ContactQuadratic.Multiply(candidate.Denominator, multiplier, candidate.Root, candidate.Denominator);
 5567252    }
 253
 254    private static bool Keep(scoped Input input, scoped Candidate candidate, scoped ref Selection selection)
 255    {
 7634256        int Words = input.Words;
 15268257        Span<ulong> values = stackalloc ulong[10 * Words]; Span<int> signs = stackalloc int[10];
 15268258        ContactQuadratic remainder = ContactQuadratic.At(values, signs, 0, Words), sum = ContactQuadratic.At(values, sig
 15268259            term = ContactQuadratic.At(values, signs, 2, Words), delta = ContactQuadratic.At(values, signs, 3, Words),
 7634260            divisor = ContactQuadratic.At(values, signs, 4, Words);
 261        int lower, upper;
 7634262        if (input.Clip.IsEmpty)
 263        {
 9716264            candidate.ParameterDenominator.CopyTo(remainder); remainder.Add(candidate.Parameter, -1);
 9716265            lower = candidate.Parameter.Sign(candidate.Root); upper = remainder.Sign(candidate.Root);
 266        }
 267        else
 268        {
 2776269            ref readonly RationalSegmentInterval clip = ref input.Clip[0];
 270            // Unit bounds add at most 319 coefficient bits; the unchanged
 271            // quadratic field remains within the forty-word candidate bank.
 2776272            ContactQuadratic.Scale(candidate.Parameter, clip.WideLowerDenominator, remainder);
 5552273            ContactQuadratic.Scale(candidate.ParameterDenominator, clip.WideLowerNumerator, term); remainder.Add(term, -
 2776274            lower = remainder.Sign(candidate.Root);
 2776275            ContactQuadratic.Scale(candidate.ParameterDenominator, clip.WideUpperNumerator, remainder);
 5552276            ContactQuadratic.Scale(candidate.Parameter, clip.WideUpperDenominator, term); remainder.Add(term, -1);
 2776277            upper = remainder.Sign(candidate.Root);
 278        }
 11063279        if (lower < 0 || upper < 0 || input.InteriorOnly && (lower == 0 || upper == 0)) return false;
 4205280        if (input.RequireSourceInside && !Contains(input, candidate, boundary: false)
 4582281            || !Contains(input, candidate, boundary: true)) return false;
 3828282        sum.Clear();
 3828283        bool nonzero = false;
 30624284        for (int axis = 0; axis < 3; axis++)
 285        {
 22968286            candidate.Boundary(axis).CopyTo(delta); delta.Add(candidate.Point(axis), -1);
 22968287            ContactQuadratic.Multiply(delta, delta, candidate.Root, term); sum.Add(term);
 11484288            nonzero |= delta.Sign(candidate.Root) != 0;
 289        }
 3828290        if (nonzero)
 28872291            for (int axis = 0; axis < 3; axis++)
 21654292            { candidate.Boundary(axis).CopyTo(candidate.Normal(axis)); candidate.Normal(axis).Add(candidate.Point(axis),
 219293        else if (candidate.Normal(0).Sign(candidate.Root) == 0 && candidate.Normal(1).Sign(candidate.Root) == 0
 275294            && candidate.Normal(2).Sign(candidate.Root) == 0) return false;
 21113295        foreach (WideDirection3d constraint in input.Fan)
 296        {
 8348297            Dot(candidate, constraint, remainder, term);
 11475298            if (remainder.Sign(candidate.Root) > 0) return false;
 299        }
 645300        Span<ulong> metric = stackalloc ulong[ConvexContactCandidate.Slots * Words];
 645301        Span<int> metricSigns = stackalloc int[ConvexContactCandidate.Slots];
 1290302        metric.Clear(); metricSigns.Clear();
 1290303        sum.Rational.CopyTo(Slot(metric, 7, Words)); sum.Radical.CopyTo(Slot(metric, 8, Words));
 1290304        metricSigns[7] = sum.Signs[0]; metricSigns[8] = sum.Signs[1];
 645305        candidate.Root.CopyTo(Slot(metric, 9, Words));
 645306        ContactQuadratic.Multiply(candidate.Denominator, candidate.Denominator, candidate.Root, divisor);
 645307        Signed832 scaleSquare = WideArithmetic.MultiplySigned576ToSigned832(Signed576.ExtendValue(input.Scale), Signed57
 645308        ContactQuadratic.Scale(divisor, scaleSquare, term);
 309        System.Diagnostics.Debug.Assert(term.Signs[1] == 0 && term.Signs[0] > 0);
 645310        term.Rational.CopyTo(Slot(metric, 10, Words));
 645311        int gapSign = nonzero ? 1 : 0;
 645312        var current = new ConvexContactCandidate(metric, metricSigns, gapSign, Words);
 645313        if (selection.HasValue)
 314        {
 498315            int comparison = WideConvexPrismRelations.CompareConvexContactCandidates(current,
 498316                new ConvexContactCandidate(selection.Metric, selection.MetricSigns,
 498317                    selection.MetricSigns[10], Words));
 973318            if (comparison > 0 || comparison == 0 && CompareWitnesses(candidate, selection.Best) >= 0) return false;
 319        }
 340320        metric.CopyTo(selection.Metric); metricSigns.CopyTo(selection.MetricSigns);
 170321        selection.MetricSigns[10] = gapSign;
 340322        candidate.CopyTo(selection.Best); selection.HasValue = true;
 170323        return true;
 324    }
 325
 326    private static void Dot(scoped Candidate candidate, WideDirection3d axis, scoped ContactQuadratic sum, scoped Contac
 327    {
 25456328        sum.Clear();
 203648329        for (int component = 0; component < 3; component++)
 152736330        { ContactQuadratic.Scale(candidate.Normal(component), Extend(Component(axis, component)), term); sum.Add(term); 
 25456331    }
 332
 333    private static int CompareWitnesses(scoped Candidate first, scoped Candidate second)
 334    {
 846335        for (int axis = 0; axis < 3; axis++)
 336        {
 344337            int comparison = ContactQuadratic.CompareRatios(first.Boundary(axis), first.Denominator, first.Root,
 344338                second.Boundary(axis), second.Denominator, second.Root);
 409339            if (comparison != 0) return comparison;
 340        }
 79341        return ContactQuadratic.CompareRatios(first.Parameter, first.ParameterDenominator, first.Root,
 79342            second.Parameter, second.ParameterDenominator, second.Root);
 343    }
 344
 345    private static bool Contains(scoped Input input, scoped Candidate candidate, bool boundary)
 346    {
 7781347        int Words = input.Words;
 15562348        Span<ulong> values = stackalloc ulong[12 * Words]; Span<int> signs = stackalloc int[12];
 15562349        ContactQuadratic bound = ContactQuadratic.At(values, signs, 0, Words), difference = ContactQuadratic.At(values, 
 15562350            x = ContactQuadratic.At(values, signs, 2, Words), z = ContactQuadratic.At(values, signs, 3, Words),
 15562351            square = ContactQuadratic.At(values, signs, 4, Words), term = ContactQuadratic.At(values, signs, 5, Words);
 7781352        ContactQuadratic y = candidate.Field(boundary ? 4 : 1);
 7781353        ContactQuadratic.Scale(candidate.Denominator, Extend(input.Cap), bound);
 15562354        bound.CopyTo(difference); difference.Add(y, -1);
 8019355        if (difference.Sign(candidate.Root) < 0) return false;
 15086356        bound.CopyTo(difference); difference.Add(y);
 7602357        if (difference.Sign(candidate.Root) < 0) return false;
 7484358        candidate.Field(boundary ? 3 : 0).CopyTo(x);
 7484359        candidate.Field(boundary ? 5 : 2).CopyTo(z);
 7484360        if (!input.Offsets.IsEmpty)
 361        {
 4095362            int winding = FiniteSlabSectionFrame.GetPrismWinding(input.Offsets);
 42042363            for (int edge = 0; edge < input.Offsets.Length; edge++)
 364            {
 33996365                Vector2d a = input.Offsets[edge], b = input.Offsets[(edge + 1) % input.Offsets.Length];
 16998366                Signed192 dx = WideArithmetic.SubtractSigned192(Signed192.Raw(b.X), Signed192.Raw(a.X));
 16998367                Signed192 dz = WideArithmetic.SubtractSigned192(Signed192.Raw(b.Y), Signed192.Raw(a.Y));
 16998368                ContactQuadratic.Scale(candidate.Denominator, Extend(WideArithmetic.MultiplySigned320(input.Scale, Signe
 33996369                x.CopyTo(difference); difference.Add(bound, -1);
 16998370                ContactQuadratic.Scale(difference, Signed832.ExtendValue(Signed576.ExtendValue(dz)), square);
 16998371                ContactQuadratic.Scale(candidate.Denominator, Extend(WideArithmetic.MultiplySigned320(input.Scale, Signe
 33996372                z.CopyTo(difference); difference.Add(bound, -1);
 33996373                ContactQuadratic.Scale(difference, Signed832.ExtendValue(Signed576.ExtendValue(dx)), term); term.Add(squ
 17070374                if (term.Sign(candidate.Root) * winding < 0) return false;
 375            }
 4023376            return true;
 377        }
 3389378        ContactQuadratic.Scale(candidate.Denominator, Extend(input.Core), bound);
 6778379        z.CopyTo(difference); difference.Add(bound, -1);
 6000380        if (difference.Sign(candidate.Root) >= 0) difference.CopyTo(z);
 381        else
 382        {
 778383            z.Add(bound);
 1122384            if (z.Sign(candidate.Root) > 0) z.Clear();
 385        }
 3389386        ContactQuadratic.Multiply(x, x, candidate.Root, square);
 6778387        ContactQuadratic.Multiply(z, z, candidate.Root, term); square.Add(term);
 3389388        ContactQuadratic.Scale(candidate.Denominator, Extend(input.Radial), bound);
 6778389        ContactQuadratic.Multiply(bound, bound, candidate.Root, term); term.Add(square, -1);
 3389390        return term.Sign(candidate.Root) >= 0;
 391    }
 392
 393    private static FixedContactAnchors Materialize(scoped Input input, scoped Selection selection)
 394    {
 147395        int Words = input.Words;
 147396        Candidate best = selection.Best;
 294397        Span<ulong> values = stackalloc ulong[8 * Words]; Span<int> signs = stackalloc int[8];
 294398        ContactQuadratic coordinate = ContactQuadratic.At(values, signs, 0, Words), term = ContactQuadratic.At(values, s
 294399            denominator = ContactQuadratic.At(values, signs, 2, Words), residual = ContactQuadratic.At(values, signs, 3,
 147400        Vector3d point = default;
 147401        ContactQuadratic.Scale(best.Denominator, Extend(input.Scale), denominator);
 1176402        for (int axis = 0; axis < 3; axis++)
 403        {
 441404            if (input.Frame.RadialFrame.ShapeFrame.HasExactScale)
 405            {
 33406                point[axis] = ContactQuadratic.RoundRatio(best.Point(axis), denominator, best.Root);
 33407                continue;
 408            }
 408409            ContactQuadratic.Scale(best.ParameterDenominator, Extend(Signed576.ExtendValue(Signed192.Raw(input.Segment.S
 408410            ContactQuadratic.Scale(best.Parameter, Extend(Signed576.ExtendValue(WideArithmetic.SubtractSigned192(
 408411                Signed192.Raw(input.Segment.End[axis]), Signed192.Raw(input.Segment.Start[axis])))), term);
 408412            coordinate.Add(term);
 408413            point[axis] = ContactQuadratic.RoundRatio(coordinate, best.ParameterDenominator, best.Root,
 408414                Math.Min(input.Segment.Start[axis].m_rawValue, input.Segment.End[axis].m_rawValue),
 408415                Math.Max(input.Segment.Start[axis].m_rawValue, input.Segment.End[axis].m_rawValue));
 416        }
 147417        ContactQuadratic.Scale(best.Denominator, Extend(input.Scale), denominator);
 147418        Vector3d core = default;
 147419        FixedPointAnchorTerm3d exactTerm = default;
 147420        if (input.Offsets.IsEmpty && input.Length != Fixed64.Zero)
 421        {
 16422            ContactQuadratic.Scale(best.Denominator, Extend(input.Core), term);
 32423            best.Boundary(2).CopyTo(coordinate); coordinate.Add(term, -1);
 16424            int region = coordinate.Sign(best.Root) > 0 ? 1 : 0;
 32425            best.Boundary(2).CopyTo(coordinate); coordinate.Add(term);
 21426            if (coordinate.Sign(best.Root) < 0) region = -1;
 16427            if (region != 0)
 10428                core = TriangleCapsuleSlabEndpointWitnesses.GetCore(Vector2d.Forward, input.Length, -region, out exactTe
 429        }
 147430        Vector3d local = default;
 1176431        for (int axis = 0; axis < 3; axis++)
 432        {
 441433            best.Boundary(axis).CopyTo(coordinate);
 441434            ContactQuadratic.Scale(denominator, Extend(Signed576.ExtendValue(Signed192.Raw(core[axis]))), term);
 441435            coordinate.Add(term, -1);
 436            // Retain an integral radial term with the exact odd half-core.
 437            // Otherwise round the complete sum once and absorb that residual.
 441438            if (axis == 2 && exactTerm.Z != 0)
 439            {
 5440                ContactQuadratic.Scale(best.Denominator, Extend(input.Core), term);
 5441                term.MultiplySign(core.Z.m_rawValue < 0 ? -1 : 1);
 10442                best.Boundary(axis).CopyTo(residual); residual.Add(term, -1);
 5443                Fixed64 rounded = ContactQuadratic.RoundRatio(residual, denominator, best.Root);
 5444                ContactQuadratic.Scale(denominator, Extend(Signed576.ExtendValue(Signed192.Raw(rounded))), term);
 5445                residual.Add(term, -1);
 5446                if (residual.Sign(best.Root) == 0)
 8447                { local[axis] = rounded; continue; }
 1448                exactTerm = default;
 449            }
 437450            local[axis] = ContactQuadratic.RoundRatio(coordinate, denominator, best.Root, parityOffset: core[axis].m_raw
 451        }
 147452        if ((input.FullHeight.m_rawValue & 1L) != 0)
 453        {
 454            // An exact odd full-height cap lies halfway between local raw
 455            // coordinates. Retain that half-raw after radial/core rounding.
 10456            ContactQuadratic.Scale(best.Denominator, Extend(input.Cap), term);
 20457            best.Boundary(1).CopyTo(residual); residual.Add(term, -1);
 10458            int cap = residual.Sign(best.Root) == 0 ? 1 : 0;
 10459            if (cap == 0)
 460            {
 10461                best.Boundary(1).CopyTo(residual); residual.Add(term);
 9462                if (residual.Sign(best.Root) == 0) cap = -1;
 463            }
 10464            if (cap != 0)
 9465                exactTerm = new(exactTerm.X, FixedPointAnchorTerm3d.GetResidual(Fixed64.One,
 9466                    cap < 0 ? -input.FullHeight : input.FullHeight, Fixed64.Zero, Fixed64.Zero,
 9467                    core.Y, local.Y), exactTerm.Z);
 468        }
 294469        Span<ulong> normals = stackalloc ulong[7 * Words]; Span<int> normalSigns = stackalloc int[7];
 294470        Span<ulong> source = stackalloc ulong[6 * Words]; Span<int> sourceSigns = stackalloc int[6];
 294471        normals.Clear(); normalSigns.Clear();
 1176472        for (int axis = 0; axis < 3; axis++)
 473        {
 441474            best.Normal(axis).Rational.CopyTo(Slot(source, axis, Words));
 441475            best.Normal(axis).Radical.CopyTo(Slot(source, axis + 3, Words));
 882476            sourceSigns[axis] = best.Normal(axis).Signs[0]; sourceSigns[axis + 3] = best.Normal(axis).Signs[1];
 477        }
 147478        var basis = new WideRationalBasis3d(input.SlabRotation);
 147479        WriteWorldDirection(basis, source[..(3 * Words)], sourceSigns[..3], normals[..(3 * Words)], normalSigns[..3], -1
 147480        WriteWorldDirection(basis, source[(3 * Words)..], sourceSigns[3..], normals.Slice(3 * Words, 3 * Words), normalS
 147481        best.Root.CopyTo(Slot(normals, 6, Words));
 147482        Vector3d normal = WideConvexPrismRelations.GetConvexContactCandidateNormal(new ConvexContactCandidate(normals, n
 147483        WideConvexPrismRelations.GetRoundedConvexContactCandidateDepth(new ConvexContactCandidate(selection.Metric,
 147484            selection.MetricSigns, selection.MetricSigns[10], Words), Fixed64.Zero, out Fixed64 depth, out bool clamped)
 147485        return new FixedContactAnchors(new FixedPointAnchor(input.Origin, input.Rotation, point),
 147486            new FixedPointAnchor(input.Center, input.SlabRotation, core, local, exactTerm), normal, depth, clamped);
 487    }
 488}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentSlabSurfaceContact.Curved.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentSlabSurfaceContact.Curved.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>Finite cap, radial-side and circular-rim witnesses, including clipped rotational families.</content>
 14internal static partial class SegmentSlabSurfaceContact
 15{
 16    private static void AccumulateCurved(scoped Input input, scoped ref Selection selection)
 17    {
 15318        int Words = input.Words;
 15319        int StorageWords = Fields * 2 * Words;
 30620        Span<ulong> values = stackalloc ulong[StorageWords], root = stackalloc ulong[Words];
 15321        Span<int> signs = stackalloc int[2 * Fields];
 15322        var candidate = new Candidate(values, signs, root);
 15323        if (!input.Clip.IsEmpty)
 24        {
 25            // Restriction changes a flat/parallel family's finite ends and
 26            // midpoint. Generate them before exact fan admission and ranking.
 20827            for (int seed = 0; seed < 3; seed++)
 28            {
 7829                Seed(input, candidate, seed);
 7830                AccumulateCurvedPoint(input, candidate, ref selection);
 31            }
 32        }
 12733        else if (!input.InteriorOnly)
 34        {
 8235            candidate.Clear(); SetPoint(input, candidate);
 4136            AccumulateCurvedPoint(input, candidate, ref selection);
 4137            if (!input.Edge.IsZero)
 38            {
 3639                candidate.Clear(); candidate.Parameter.Set(One); SetPoint(input, candidate);
 1240                AccumulateCurvedPoint(input, candidate, ref selection);
 41            }
 42        }
 15343        if (input.Edge.IsZero)
 44        {
 3745            if (input.Length != Fixed64.Zero) AccumulateStraight(input, ref selection);
 2946            return;
 47        }
 12448        if (input.Edge.Y.IsZero && SetSectionParameter(input, candidate, projected: true))
 9649            for (int cap = -1; cap <= 1; cap += 2)
 50            {
 3251                SetPoint(input, candidate);
 6152                if (SetCap(input, candidate, cap)) Keep(input, candidate, ref selection);
 53            }
 12454        int start = input.Length == Fixed64.Zero ? 0 : -1;
 54055        for (int region = start; region <= (input.Length == Fixed64.Zero ? 0 : 1); region += 2)
 56        {
 14657            Signed576 center = region < 0 ? WideArithmetic.Negate(input.Core) : region > 0 ? input.Core : default;
 14658            WideDirection3d offset = new(input.First.X, default, WideArithmetic.SubtractSigned576(input.First.Z, center)
 14659            WideDirection3d planarEdge = new(input.Edge.X, default, input.Edge.Z);
 14660            Signed832 square = planarEdge.SquaredLength;
 14661            if (!square.IsZero)
 62            {
 11463                candidate.Clear();
 11464                candidate.Parameter.Set(WideArithmetic.SubtractSigned832(default, WideDirection3d.Dot(offset, planarEdge
 22865                candidate.ParameterDenominator.Set(square); SetPoint(input, candidate);
 11466                AccumulateArcFoot(input, candidate, region, cap: 0, ref selection);
 11467                if (input.Edge.Y.IsZero)
 14468                    for (int cap = -1; cap <= 1; cap += 2)
 69                    {
 4870                        SetPoint(input, candidate);
 4871                        AccumulateArcFoot(input, candidate, region, cap, ref selection);
 72                    }
 73            }
 3274            else if (SetSectionParameter(input, candidate))
 75            {
 2776                SetPoint(input, candidate);
 2777                AccumulateArcFoot(input, candidate, region, cap: 0, ref selection);
 78            }
 79        }
 14680        if (input.Length != Fixed64.Zero) AccumulateStraight(input, ref selection);
 12481        AccumulateMeridionalRims(input, ref selection);
 12482        AccumulatePrincipalRims(input, ref selection);
 12483    }
 84
 85    private static void AccumulateCurvedPoint(scoped Input input, scoped Candidate candidate, scoped ref Selection selec
 86    {
 78687        for (int cap = -1; cap <= 1; cap += 2)
 77688        { SetPoint(input, candidate); if (SetCap(input, candidate, cap)) Keep(input, candidate, ref selection); }
 13189        int start = input.Length == Fixed64.Zero ? 0 : -1;
 54890        for (int region = start; region <= (input.Length == Fixed64.Zero ? 0 : 1); region += 2)
 114491            for (int cap = -1; cap <= 1; cap++)
 92            {
 42993                SetPoint(input, candidate);
 42994                AccumulateArcFoot(input, candidate, region, cap, ref selection);
 95            }
 13196    }
 97
 98    private static bool SetCap(scoped Input input, scoped Candidate candidate, int cap)
 99    {
 1438100        ContactQuadratic.Scale(candidate.Denominator, Extend(input.Cap), candidate.Boundary(1));
 1438101        candidate.Boundary(1).MultiplySign(cap);
 2876102        candidate.Boundary(1).CopyTo(candidate.Normal(1)); candidate.Normal(1).Add(candidate.Point(1), -1);
 1467103        if (candidate.Normal(1).Sign(candidate.Root) * cap < 0) return false;
 5636104        candidate.Normal(0).Clear(); candidate.Normal(1).Set(One); candidate.Normal(1).MultiplySign(cap); candidate.Norm
 1409105        return true;
 106    }
 107
 108    private static bool SetSectionParameter(scoped Input input, scoped Candidate candidate, bool projected = false)
 109    {
 52110        int Words = input.Words;
 52111        candidate.Clear();
 52112        if (!input.RequireSourceInside && !projected)
 113        {
 6114            if (!CapsuleFiniteSectionFrame.TryGetCenteredAxisInterval(Signed320.NarrowValue(input.First.Y),
 6115                Signed320.NarrowValue(input.Edge.Y), Signed320.NarrowValue(input.Cap),
 10116                out Signed320 ln, out Signed320 ld, out Signed320 un, out Signed320 ud)) return false;
 2117            candidate.Parameter.Set(WideArithmetic.AddSigned832(WideArithmetic.MultiplySigned576(Signed576.ExtendValue(l
 2118                WideArithmetic.MultiplySigned576(Signed576.ExtendValue(un), Signed576.ExtendValue(ld))));
 2119            Signed832 denominator = WideArithmetic.MultiplySigned576(Signed576.ExtendValue(ld), Signed576.ExtendValue(ud
 2120            candidate.ParameterDenominator.Set(WideArithmetic.AddSigned832(denominator, denominator));
 2121            return true;
 122        }
 46123        bool admitted = input.RequireSourceInside
 46124            ? input.Frame.TryGetFirstSegmentParameter(input.Segment, input.Offsets,
 46125                candidate.Parameter, candidate.ParameterDenominator, candidate.Root)
 46126            : input.Frame.TryGetFirstProjectedSegmentParameter(input.Segment, input.Offsets,
 46127                candidate.Parameter, candidate.ParameterDenominator, candidate.Root);
 50128        if (!admitted) return false;
 59129        if (!input.InteriorOnly || candidate.Parameter.Sign(candidate.Root) != 0) return true;
 25130        var reverse = new FixedSegment(input.Segment.End, input.Segment.Start);
 25131        admitted = input.RequireSourceInside
 25132            ? input.Frame.TryGetFirstSegmentParameter(reverse, input.Offsets,
 25133                candidate.Parameter, candidate.ParameterDenominator, candidate.Root)
 25134            : input.Frame.TryGetFirstProjectedSegmentParameter(reverse, input.Offsets,
 25135                candidate.Parameter, candidate.ParameterDenominator, candidate.Root);
 136        // Reversal preserves the same nonempty closed section interval.
 137        System.Diagnostics.Debug.Assert(admitted);
 50138        candidate.Parameter.MultiplySign(-1); candidate.Parameter.Add(candidate.ParameterDenominator);
 26139        if (candidate.Parameter.Sign(candidate.Root) == 0) return false;
 48140        Span<ulong> values = stackalloc ulong[2 * Words]; Span<int> signs = stackalloc int[2];
 24141        var remainder = new ContactQuadratic(values, signs);
 48142        candidate.ParameterDenominator.CopyTo(remainder); remainder.Add(candidate.Parameter, -1);
 24143        if (remainder.Sign(candidate.Root) == 0)
 144        {
 44145            candidate.Clear(); candidate.Parameter.Set(One);
 22146            candidate.ParameterDenominator.Set(Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(2))));
 147        }
 24148        return true;
 149    }
 150
 151    private static void AccumulateArcFoot(scoped Input input, scoped Candidate source, int region, int cap, scoped ref S
 152    {
 618153        int Words = input.Words;
 618154        int StorageWords = Fields * 2 * Words;
 1236155        Span<ulong> saved = stackalloc ulong[StorageWords], savedRoot = stackalloc ulong[Words];
 618156        Span<int> savedSigns = stackalloc int[2 * Fields];
 618157        var candidate = new Candidate(saved, savedSigns, savedRoot);
 1236158        Span<ulong> values = stackalloc ulong[14 * Words]; Span<int> signs = stackalloc int[14];
 1236159        ContactQuadratic x = ContactQuadratic.At(values, signs, 0, Words), z = ContactQuadratic.At(values, signs, 1, Wor
 1236160            center = ContactQuadratic.At(values, signs, 2, Words), square = ContactQuadratic.At(values, signs, 3, Words)
 1236161            term = ContactQuadratic.At(values, signs, 4, Words), coefficient = ContactQuadratic.At(values, signs, 5, Wor
 618162            remainder = ContactQuadratic.At(values, signs, 6, Words);
 1236163        source.Point(0).CopyTo(x); source.Point(2).CopyTo(z);
 1236164        ContactQuadratic.Scale(source.Denominator, Extend(input.Core), center); center.MultiplySign(region);
 618165        z.Add(center, -1);
 618166        ContactQuadratic.Multiply(x, x, source.Root, square);
 1236167        ContactQuadratic.Multiply(z, z, source.Root, term); square.Add(term);
 168        // These feet use a rational segment parameter. A cap interval's
 169        // quadratic boundary parameter is handled separately, never folded
 170        // into a second independent radical field.
 171        System.Diagnostics.Debug.Assert(square.Signs[1] == 0);
 618172        if (input.Radius == Fixed64.Zero || square.Signs[0] == 0)
 173        {
 121174            AccumulateRadialFamily(input, source, region, cap, ref selection);
 121175            return;
 176        }
 2982177        for (int branch = -1; branch <= 1; branch += 2)
 178        {
 994179            source.CopyTo(candidate);
 994180            square.Rational.CopyTo(candidate.Root);
 181            // Cancel the common sqrt(S) rather than retaining S in every
 182            // coordinate. A stationary rational foot can have 600-bit
 183            // numerators; this keeps its squared metric below 2400 bits.
 2982184            coefficient.Clear(); coefficient.Radical[0] = 1; coefficient.Signs[1] = 1;
 994185            ScaleCoordinates(candidate, coefficient);
 5964186            for (int axis = 0; axis < 3; axis += 2)
 187            {
 1988188                ContactQuadratic planar = axis == 0 ? x : z;
 1988189                ContactQuadratic.Scale(planar, Extend(input.Radial), term);
 1988190                ContactQuadratic.Multiply(term, source.Denominator, source.Root, coefficient);
 1988191                ContactQuadratic q = candidate.Boundary(axis);
 1988192                coefficient.CopyTo(q, branch);
 1988193                if (axis == 2)
 194                {
 2982195                    ContactQuadratic.Scale(candidate.Denominator, Extend(input.Core), term); term.MultiplySign(region); 
 196                }
 197            }
 994198            if (cap != 0 && !SetCap(input, candidate, cap)) continue;
 980199            if (!AdmitsArc(input, candidate, region, remainder, term)) continue;
 200            // The matched displacement must be in the curved side/rim's
 201            // normal cone, rather than point from an outer arc inward.
 1744202            candidate.Boundary(0).CopyTo(term); term.Add(candidate.Point(0), -1);
 872203            ContactQuadratic.Multiply(term, x, candidate.Root, remainder);
 1744204            candidate.Boundary(2).CopyTo(term); term.Add(candidate.Point(2), -1);
 1744205            ContactQuadratic.Multiply(term, z, candidate.Root, coefficient); remainder.Add(coefficient);
 872206            if (remainder.Sign(candidate.Root) * branch < 0) continue;
 6816207            for (int axis = 0; axis < 3; axis++)
 208            {
 5112209                candidate.Boundary(axis).CopyTo(candidate.Normal(axis)); candidate.Normal(axis).Add(candidate.Point(axis
 210            }
 852211            if (candidate.Normal(0).Sign(candidate.Root) == 0 && candidate.Normal(1).Sign(candidate.Root) == 0
 852212                && candidate.Normal(2).Sign(candidate.Root) == 0)
 7213                AccumulateTouchNormals(input, candidate, region, cap, ref selection);
 845214            else Keep(input, candidate, ref selection);
 215        }
 497216    }
 217
 218    private static bool AdmitsArc(scoped Input input, scoped Candidate candidate, int region, scoped ContactQuadratic re
 219    {
 6084220        if (region == 0) return true;
 1400221        ContactQuadratic.Scale(candidate.Denominator, Extend(input.Core), term); term.MultiplySign(region);
 1400222        candidate.Boundary(2).CopyTo(remainder); remainder.Add(term, -1);
 700223        return remainder.Sign(candidate.Root) * region >= 0;
 224    }
 225
 226    private static void AccumulateRadialFamily(scoped Input input, scoped Candidate source, int region, int cap, scoped 
 227    {
 121228        int Words = input.Words;
 121229        int StorageWords = Fields * 2 * Words;
 230        // At a planar axis point every radial orientation has equal distance.
 231        // A nonempty halfspace-clipped circle either includes a principal
 232        // axis or an exact intersection with one of its linear walls.
 242233        Span<ulong> values = stackalloc ulong[StorageWords], root = stackalloc ulong[Words];
 121234        Span<int> signs = stackalloc int[2 * Fields];
 121235        var candidate = new Candidate(values, signs, root);
 121236        if (input.Radius == Fixed64.Zero)
 237        {
 238            // A collapsed radial stratum has a normal plane or half-plane;
 239            // its zero displacement cannot stand in for that free normal.
 38240            source.CopyTo(candidate); candidate.Boundary(0).Clear();
 19241            ContactQuadratic.Scale(source.Denominator, Extend(input.Core), candidate.Boundary(2));
 19242            candidate.Boundary(2).MultiplySign(region);
 21243            if (cap != 0 && !SetCap(input, candidate, cap)) return;
 17244            Span<WideDirection3d> cone = stackalloc WideDirection3d[3];
 17245            int count = 0;
 17246            cone[count++] = Axis(0, cap == 0 ? 1 : -cap, 0);
 24247            if (cap == 0) cone[count++] = Axis(0, -1, 0);
 23248            if (region != 0) cone[count++] = Axis(0, 0, -region);
 17249            KeepPlanar(input, candidate, cone[..count], ref selection);
 17250            return;
 251        }
 204252        Span<ulong> work = stackalloc ulong[16 * Words]; Span<int> workSigns = stackalloc int[16];
 204253        ContactQuadratic a = ContactQuadratic.At(work, workSigns, 0, Words), b = ContactQuadratic.At(work, workSigns, 1,
 204254            c = ContactQuadratic.At(work, workSigns, 2, Words), metric = ContactQuadratic.At(work, workSigns, 3, Words),
 204255            discriminant = ContactQuadratic.At(work, workSigns, 4, Words), term = ContactQuadratic.At(work, workSigns, 5
 204256            radial = ContactQuadratic.At(work, workSigns, 6, Words), axial = ContactQuadratic.At(work, workSigns, 7, Wor
 102257        ContactQuadratic.Scale(source.Denominator, Extend(input.Radial), radial);
 102258        axial.Clear();
 102259        if (cap != 0)
 260        {
 116261            ContactQuadratic.Scale(source.Denominator, Extend(input.Cap), axial); axial.MultiplySign(cap);
 58262            axial.Add(source.Point(1), -1);
 62263            if (axial.Sign(source.Root) * cap < 0) return;
 264            // The positive metric scaling below preserves this cap-direction admission.
 265        }
 588266        for (int axis = 0; axis < 3; axis += 2)
 1176267            for (int branch = -1; branch <= 1; branch += 2)
 268            {
 392269                source.CopyTo(candidate);
 784270                candidate.Boundary(0).Clear(); candidate.Boundary(2).Clear();
 392271                radial.CopyTo(candidate.Boundary(axis), branch);
 1176272                ContactQuadratic.Scale(source.Denominator, Extend(input.Core), term); term.MultiplySign(region); candida
 608273                if (cap != 0) SetCap(input, candidate, cap);
 392274                SetFamilyNormal(candidate, axis, branch, cap);
 778275                if (AdmitsArc(input, candidate, region, c, term)) Keep(input, candidate, ref selection);
 276            }
 1140277        for (int wall = 0; wall < input.Fan.Length + (region == 0 ? 0 : 1); wall++)
 278        {
 472279            WideDirection3d constraint = wall < input.Fan.Length ? input.Fan[wall]
 472280                : new(default, default, Signed576.ExtendValue(Signed192.Signed(-region)));
 944281            a.Set(Extend(constraint.X)); b.Set(Extend(constraint.Z));
 472282            ContactQuadratic.Multiply(a, a, source.Root, metric);
 944283            ContactQuadratic.Multiply(b, b, source.Root, term); metric.Add(term);
 472284            if (metric.Signs[0] == 0) continue;
 688285            ContactQuadratic.Scale(axial, Extend(constraint.Y), c); c.MultiplySign(-1);
 344286            ContactQuadratic.Multiply(radial, radial, source.Root, discriminant);
 344287            ContactQuadratic.Multiply(discriminant, metric, source.Root, discriminant);
 688288            ContactQuadratic.Multiply(c, c, source.Root, term); discriminant.Add(term, -1);
 344289            if (discriminant.Signs[0] < 0) continue;
 2052290            for (int branch = -1; branch <= 1; branch += 2)
 291            {
 684292                source.CopyTo(candidate);
 684293                discriminant.Rational.CopyTo(candidate.Root);
 684294                ScaleCoordinates(candidate, metric);
 684295                ContactQuadratic.Multiply(c, a, source.Root, candidate.Boundary(0));
 1368296                b.Rational.CopyTo(candidate.Boundary(0).Radical); candidate.Boundary(0).Signs[1] = branch * b.Signs[0];
 684297                ContactQuadratic.Multiply(c, b, source.Root, candidate.Boundary(2));
 1368298                a.Rational.CopyTo(candidate.Boundary(2).Radical); candidate.Boundary(2).Signs[1] = -branch * a.Signs[0];
 2052299                ContactQuadratic.Scale(candidate.Denominator, Extend(input.Core), term); term.MultiplySign(region); cand
 1072300                if (cap != 0) SetCap(input, candidate, cap);
 684301                candidate.Boundary(0).CopyTo(candidate.Normal(0));
 684302                axial.CopyTo(candidate.Normal(1));
 684303                candidate.Boundary(2).CopyTo(candidate.Normal(2));
 1356304                if (AdmitsArc(input, candidate, region, c, term)) Keep(input, candidate, ref selection);
 305            }
 306        }
 98307    }
 308
 309    private static void SetFamilyNormal(scoped Candidate candidate, int axis, int branch, int cap)
 310    {
 4312311        for (int component = 0; component < 3; component++) candidate.Normal(component).Clear();
 784312        candidate.Normal(axis).Set(One); candidate.Normal(axis).MultiplySign(branch);
 608313        if (cap != 0) candidate.Normal(1).Set(Signed832.ExtendValue(Signed576.ExtendValue(Signed192.Signed(cap))));
 392314    }
 315
 316    private static void AccumulateTouchNormals(scoped Input input, scoped Candidate candidate, int region, int cap, scop
 317    {
 33318        int Words = input.Words;
 66319        Span<ulong> values = stackalloc ulong[8 * Words]; Span<int> signs = stackalloc int[8];
 66320        ContactQuadratic radial = ContactQuadratic.At(values, signs, 0, Words), up = ContactQuadratic.At(values, signs, 
 66321            term = ContactQuadratic.At(values, signs, 2, Words), projection = ContactQuadratic.At(values, signs, 3, Word
 66322        candidate.Boundary(0).CopyTo(candidate.Normal(0)); candidate.Normal(1).Clear();
 66323        ContactQuadratic.Scale(candidate.Denominator, Extend(input.Core), term); term.MultiplySign(region);
 66324        candidate.Boundary(2).CopyTo(candidate.Normal(2)); candidate.Normal(2).Add(term, -1);
 33325        Keep(input, candidate, ref selection);
 39326        if (cap == 0) return;
 292327        for (int wall = 0; wall <= input.Fan.Length; wall++)
 328        {
 329            // The normal cone is the nonnegative span of this radial normal
 330            // and the cap normal. Its clipped endpoints are generators or
 331            // one exact fan-wall crossing; no angular sampling is needed.
 119332            WideDirection3d constraint = wall < input.Fan.Length ? input.Fan[wall] : default;
 238333            candidate.Boundary(0).CopyTo(candidate.Normal(0)); candidate.Normal(1).Clear();
 238334            candidate.Boundary(2).CopyTo(candidate.Normal(2)); candidate.Normal(2).Add(term, -1);
 119335            Dot(candidate, constraint, radial, projection);
 238336            up.Set(Extend(constraint.Y)); up.MultiplySign(cap);
 119337            if (wall < input.Fan.Length && radial.Sign(candidate.Root) * up.Sign(candidate.Root) >= 0) continue;
 222338            for (int axis = 0; axis < 3; axis += 2)
 339            {
 128340                if (wall == input.Fan.Length) candidate.Normal(axis).Clear();
 341                else
 342                {
 20343                    up.MultiplySign(up.Sign(candidate.Root));
 40344                    ContactQuadratic.Multiply(candidate.Normal(axis), up, candidate.Root, projection); projection.CopyTo
 345                }
 346            }
 64347            if (wall == input.Fan.Length) candidate.Normal(1).Set(One);
 10348            else radial.CopyTo(candidate.Normal(1), radial.Sign(candidate.Root));
 37349            candidate.Normal(1).MultiplySign(cap);
 37350            Keep(input, candidate, ref selection);
 351        }
 27352    }
 353
 354    private static void AccumulateMeridionalRims(scoped Input input, scoped ref Selection selection)
 355    {
 124356        int Words = input.Words;
 124357        int StorageWords = Fields * 2 * Words;
 144358        if (input.Edge.Y.IsZero) return;
 104359        Signed832 radialSquare = CircularRimContactAlgebra.RadialDot(input.Edge, input.Edge);
 132360        if (radialSquare.IsZero) return;
 152361        Span<ulong> values = stackalloc ulong[StorageWords], root = stackalloc ulong[Words];
 152362        Span<int> signs = stackalloc int[2 * Fields]; var candidate = new Candidate(values, signs, root);
 152363        Span<ulong> work = stackalloc ulong[12 * Words]; Span<int> workSigns = stackalloc int[12];
 152364        ContactQuadratic qx = ContactQuadratic.At(work, workSigns, 0, Words), qy = ContactQuadratic.At(work, workSigns, 
 152365            qz = ContactQuadratic.At(work, workSigns, 2, Words), a = ContactQuadratic.At(work, workSigns, 3, Words),
 152366            b = ContactQuadratic.At(work, workSigns, 4, Words), term = ContactQuadratic.At(work, workSigns, 5, Words);
 76367        int firstRegion = input.Length == Fixed64.Zero ? 0 : -1;
 332368        for (int region = firstRegion; region <= (input.Length == Fixed64.Zero ? 0 : 1); region += 2)
 540369            for (int cap = -1; cap <= 1; cap += 2)
 1080370                for (int branch = -1; branch <= 1; branch += 2)
 371                {
 720372                    candidate.Clear(); Import(radialSquare, candidate.Root);
 1080373                    a.Set(Extend(input.Radial)); b.Set(Extend(input.Edge.X)); ContactQuadratic.Multiply(a, b, root, term
 1080374                    qx.Clear(); term.Rational.CopyTo(qx.Radical); qx.Signs[1] = branch * term.Signs[0];
 720375                    b.Set(Extend(input.Edge.Z)); ContactQuadratic.Multiply(a, b, root, term);
 1080376                    qz.Clear(); term.Rational.CopyTo(qz.Radical); qz.Signs[1] = branch * term.Signs[0];
 1440377                    a.Set(radialSquare); ContactQuadratic.Scale(a, Extend(input.Core), term); term.MultiplySign(region);
 720378                    ContactQuadratic.Scale(a, Extend(input.Cap), qy); qy.MultiplySign(cap);
 360379                    candidate.Parameter.Clear();
 2880380                    for (int axis = 0; axis < 3; axis++)
 381                    {
 1080382                        ContactQuadratic q = axis == 0 ? qx : axis == 1 ? qy : qz;
 1080383                        ContactQuadratic.Scale(a, Extend(Component(input.First, axis)), term);
 2160384                        q.CopyTo(b); b.Add(term, -1);
 2160385                        ContactQuadratic.Scale(b, Extend(Component(input.Edge, axis)), term); candidate.Parameter.Add(te
 386                    }
 360387                    ContactQuadratic.Scale(a, input.Edge.SquaredLength, candidate.ParameterDenominator);
 360388                    SetPoint(input, candidate);
 360389                    ContactQuadratic.Scale(qx, input.Edge.SquaredLength, candidate.Boundary(0));
 360390                    ContactQuadratic.Scale(qy, input.Edge.SquaredLength, candidate.Boundary(1));
 360391                    ContactQuadratic.Scale(qz, input.Edge.SquaredLength, candidate.Boundary(2));
 360392                    KeepRim(input, candidate, region, cap, ref selection);
 393                }
 76394    }
 395
 396    private static void AccumulatePrincipalRims(scoped Input input, scoped ref Selection selection)
 397    {
 124398        int Words = input.Words;
 124399        int StorageWords = Fields * 2 * Words;
 144400        if (input.Edge.Y.IsZero || input.Edge.IsZero) return;
 401        // The quartic charts isolate (0,1]; their exact principal-axis ends
 402        // are separate rational feet, rather than angular samples.
 208403        Span<ulong> values = stackalloc ulong[StorageWords], root = stackalloc ulong[Words];
 208404        Span<int> signs = stackalloc int[2 * Fields]; var candidate = new Candidate(values, signs, root);
 104405        int firstRegion = input.Length == Fixed64.Zero ? 0 : -1;
 452406        for (int region = firstRegion; region <= (input.Length == Fixed64.Zero ? 0 : 1); region += 2)
 732407            for (int cap = -1; cap <= 1; cap += 2)
 1464408                for (int axis = 0; axis < 3; axis += 2)
 2928409                    for (int branch = -1; branch <= 1; branch += 2)
 410                    {
 976411                        Signed576 x = axis == 0 ? branch < 0 ? WideArithmetic.Negate(input.Radial) : input.Radial : defa
 976412                        Signed576 z = region < 0 ? WideArithmetic.Negate(input.Core) : region > 0 ? input.Core : default
 1464413                        if (axis == 2) z = WideArithmetic.AddSigned576(z, branch < 0 ? WideArithmetic.Negate(input.Radia
 976414                        WideDirection3d q = new(x, cap < 0 ? WideArithmetic.Negate(input.Cap) : input.Cap, z);
 1952415                        candidate.Clear(); candidate.Parameter.Set(WideDirection3d.Dot(TriangleCircularGeometry.Subtract
 1952416                        candidate.ParameterDenominator.Set(input.Edge.SquaredLength); SetPoint(input, candidate);
 7808417                        for (int component = 0; component < 3; component++)
 2928418                            ContactQuadratic.Scale(candidate.Denominator, Extend(Component(q, component)), candidate.Bou
 976419                        KeepRim(input, candidate, region, cap, ref selection);
 420                    }
 104421    }
 422
 423    private static void KeepRim(scoped Input input, scoped Candidate candidate, int region, int cap, scoped ref Selectio
 424    {
 1336425        int Words = input.Words;
 2672426        Span<ulong> values = stackalloc ulong[10 * Words]; Span<int> signs = stackalloc int[10];
 2672427        ContactQuadratic radial = ContactQuadratic.At(values, signs, 0, Words), term = ContactQuadratic.At(values, signs
 2672428            cross = ContactQuadratic.At(values, signs, 2, Words), dot = ContactQuadratic.At(values, signs, 3, Words),
 1336429            remainder = ContactQuadratic.At(values, signs, 4, Words);
 1464430        if (!AdmitsArc(input, candidate, region, remainder, term)) return;
 9664431        for (int axis = 0; axis < 3; axis++)
 7248432        { candidate.Boundary(axis).CopyTo(candidate.Normal(axis)); candidate.Normal(axis).Add(candidate.Point(axis), -1)
 1604433        if (candidate.Normal(1).Sign(candidate.Root) * cap < 0) return;
 1624434        ContactQuadratic.Scale(candidate.Denominator, Extend(input.Core), term); term.MultiplySign(region);
 1624435        candidate.Boundary(2).CopyTo(radial); radial.Add(term, -1);
 812436        ContactQuadratic.Multiply(candidate.Normal(0), radial, candidate.Root, cross);
 1624437        ContactQuadratic.Multiply(candidate.Normal(2), candidate.Boundary(0), candidate.Root, term); cross.Add(term, -1)
 1392438        if (cross.Sign(candidate.Root) != 0) return;
 232439        ContactQuadratic.Multiply(candidate.Normal(0), candidate.Boundary(0), candidate.Root, dot);
 464440        ContactQuadratic.Multiply(candidate.Normal(2), radial, candidate.Root, term); dot.Add(term);
 248441        if (dot.Sign(candidate.Root) < 0) return;
 216442        if (candidate.Normal(0).Sign(candidate.Root) == 0 && candidate.Normal(1).Sign(candidate.Root) == 0
 216443            && candidate.Normal(2).Sign(candidate.Root) == 0)
 26444            AccumulateTouchNormals(input, candidate, region, cap, ref selection);
 190445        else Keep(input, candidate, ref selection);
 190446    }
 447}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/SegmentSlabSurfaceContact.Planar.cs

#LineLine coverage
 1//=======================================================================
 2// SegmentSlabSurfaceContact.Planar.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>Finite planar strata and exact oblique circular-rim root selection.</content>
 14internal static partial class SegmentSlabSurfaceContact
 15{
 16    private static void AccumulatePrism(scoped Input input, scoped ref Selection selection)
 17    {
 5818        int winding = FiniteSlabSectionFrame.GetPrismWinding(input.Offsets);
 34819        for (int cap = -1; cap <= 1; cap += 2)
 11620            AccumulatePlane(input, new(default, cap < 0 ? WideArithmetic.Negate(input.Cap) : input.Cap, default),
 11621                Axis(0, cap, 0), false, ref selection);
 5822        Span<WideDirection3d> cone = stackalloc WideDirection3d[5];
 63223        for (int index = 0; index < input.Offsets.Length; index++)
 24        {
 51625            WideDirection3d a = PrismVertex(input, index), b = PrismVertex(input, (index + 1) % input.Offsets.Length);
 25826            WideDirection3d edge = TriangleCircularGeometry.Subtract(b, a);
 25827            if (edge.IsZero) continue;
 23428            int previous = (index + input.Offsets.Length - 1) % input.Offsets.Length;
 23429            WideDirection3d inward = TriangleCircularGeometry.Subtract(PrismVertex(input, previous), a);
 25830            while (inward.IsZero)
 31            {
 2432                previous = (previous + input.Offsets.Length - 1) % input.Offsets.Length;
 2433                inward = TriangleCircularGeometry.Subtract(PrismVertex(input, previous), a);
 34            }
 23435            WideDirection3d outward = new(winding > 0 ? edge.Z : WideArithmetic.Negate(edge.Z), default,
 23436                winding > 0 ? WideArithmetic.Negate(edge.X) : edge.X);
 23437            bool straight = WideArithmetic.SubtractSigned832(WideArithmetic.MultiplySigned576(inward.X, edge.Z),
 23438                WideArithmetic.MultiplySigned576(inward.Z, edge.X)).IsZero;
 23439            AccumulatePlane(input, a, outward, false, ref selection);
 46840            cone[0] = inward; cone[1] = edge;
 46841            cone[2] = Axis(0, 1, 0); cone[3] = Axis(0, -1, 0);
 42            // Opposite incident rays at a redundant straight vertex also need the wall's outward orientation.
 23843            if (straight) cone[4] = -outward;
 23444            WideDirection3d bottom = new(a.X, WideArithmetic.Negate(input.Cap), a.Z);
 23445            WideDirection3d top = new(a.X, input.Cap, a.Z);
 23446            AccumulateLine(input, bottom, top, cone[..(straight ? 5 : 4)], ref selection);
 140447            for (int cap = -1; cap <= 1; cap += 2)
 48            {
 46849                WideDirection3d first = new(a.X, cap < 0 ? WideArithmetic.Negate(input.Cap) : input.Cap, a.Z);
 46850                WideDirection3d second = new(b.X, first.Y, b.Z);
 187251                cone[0] = -outward; cone[1] = Axis(0, -cap, 0); cone[2] = edge; cone[3] = -edge;
 46852                AccumulateLine(input, first, second, cone[..4], ref selection);
 140453                cone[0] = inward; cone[1] = edge; cone[2] = Axis(0, -cap, 0);
 47654                if (straight) cone[3] = -outward;
 46855                AccumulateVertex(input, first, cone[..(straight ? 4 : 3)], ref selection);
 56            }
 57        }
 5858    }
 59
 60    private static WideDirection3d PrismVertex(scoped Input input, int index)
 61    {
 77462        Vector2d vertex = input.Offsets[index];
 77463        Signed320 scale = input.Scale;
 77464        return new(WideArithmetic.MultiplySigned320(scale, Signed192.Raw(vertex.X)), default,
 77465            WideArithmetic.MultiplySigned320(scale, Signed192.Raw(vertex.Y)));
 66    }
 67
 215068    private static WideDirection3d Axis(long x, long y, long z) => new(
 215069        Signed576.ExtendValue(Signed192.Signed(x)), Signed576.ExtendValue(Signed192.Signed(y)),
 215070        Signed576.ExtendValue(Signed192.Signed(z)));
 71
 72    private static void AccumulateStraight(scoped Input input, scoped ref Selection selection)
 73    {
 3074        Span<WideDirection3d> cone = stackalloc WideDirection3d[4];
 18075        for (int cap = -1; cap <= 1; cap += 2)
 6076            AccumulatePlane(input, new(default, cap < 0 ? WideArithmetic.Negate(input.Cap) : input.Cap, default),
 6077                Axis(0, cap, 0), true, ref selection);
 18078        for (int side = -1; side <= 1; side += 2)
 79        {
 6080            Signed576 x = side < 0 ? WideArithmetic.Negate(input.Radial) : input.Radial;
 6081            AccumulatePlane(input, new(x, default, default), Axis(side, 0, 0), true, ref selection);
 36082            for (int cap = -1; cap <= 1; cap += 2)
 83            {
 12084                Signed576 y = cap < 0 ? WideArithmetic.Negate(input.Cap) : input.Cap;
 24085                cone[0] = Axis(-side, 0, 0); cone[1] = Axis(0, -cap, 0);
 24086                cone[2] = Axis(0, 0, 1); cone[3] = Axis(0, 0, -1);
 12087                AccumulateLine(input, new(x, y, WideArithmetic.Negate(input.Core)),
 12088                    new(x, y, input.Core), cone, ref selection);
 89            }
 90        }
 3091    }
 92
 93    private static bool Seed(scoped Input input, scoped Candidate candidate, int seed)
 94    {
 509495        candidate.Clear();
 509496        if (!input.Clip.IsEmpty && seed < 3)
 97        {
 117098            ref readonly RationalSegmentInterval clip = ref input.Clip[0];
 117099            if (seed < 2)
 100            {
 780101                candidate.Parameter.Set(seed == 0 ? clip.WideLowerNumerator : clip.WideUpperNumerator);
 780102                candidate.ParameterDenominator.Set(seed == 0 ? clip.WideLowerDenominator : clip.WideUpperDenominator);
 103            }
 104            else
 105            {
 106                // The mediant lies strictly inside distinct positive-denominator
 107                // bounds without the 640-bit denominator of their arithmetic mean.
 390108                candidate.Parameter.Set(WideArithmetic.AddSigned832(clip.WideLowerNumerator, clip.WideUpperNumerator));
 390109                candidate.ParameterDenominator.Set(WideArithmetic.AddSigned832(clip.WideLowerDenominator, clip.WideUpper
 110            }
 111        }
 4490112        else if (seed == 1) candidate.Parameter.Set(One);
 3358113        else if (seed == 2)
 1132114        { candidate.Parameter.Set(One); candidate.ParameterDenominator.Set(Extend(Signed576.ExtendValue(Signed192.Signed
 2792115        else if (seed >= 3)
 116        {
 1396117            FixedSegment segment = seed == 3 ? input.Segment : new(input.Segment.End, input.Segment.Start);
 1396118            bool admitted = input.RequireSourceInside
 1396119                ? input.Frame.TryGetFirstSegmentParameter(segment, input.Offsets,
 1396120                    candidate.Parameter, candidate.ParameterDenominator, candidate.Root)
 1396121                : input.Frame.TryGetFirstProjectedSegmentParameter(segment, input.Offsets,
 1396122                    candidate.Parameter, candidate.ParameterDenominator, candidate.Root);
 1504123            if (!admitted) return false;
 1288124            if (seed == 4)
 1288125            { candidate.Parameter.MultiplySign(-1); candidate.Parameter.Add(candidate.ParameterDenominator); }
 126        }
 9972127        SetPoint(input, candidate); return true;
 128    }
 129
 130    private static void AccumulatePlane(scoped Input input, WideDirection3d origin, WideDirection3d outward,
 131        bool central, scoped ref Selection selection)
 132    {
 470133        int Words = input.Words;
 470134        int StorageWords = Fields * 2 * Words;
 940135        Span<ulong> values = stackalloc ulong[StorageWords], root = stackalloc ulong[Words];
 470136        Span<int> signs = stackalloc int[2 * Fields];
 470137        var candidate = new Candidate(values, signs, root);
 940138        Span<ulong> work = stackalloc ulong[8 * Words]; Span<int> workSigns = stackalloc int[8];
 940139        ContactQuadratic offset = ContactQuadratic.At(work, workSigns, 0, Words), term = ContactQuadratic.At(work, workS
 940140            product = ContactQuadratic.At(work, workSigns, 2, Words), bound = ContactQuadratic.At(work, workSigns, 3, Wo
 470141        Signed832 square = outward.SquaredLength;
 142        // Point seeds coincide; keep the first tie and omit segment-only stationary candidates.
 470143        int seedCount = input.Edge.IsZero ? 1 : 6;
 4500144        for (int seed = 0; seed < seedCount; seed++)
 145        {
 1780146            if (seed == 5)
 147            {
 262148                Signed832 velocity = WideDirection3d.Dot(input.Edge, outward);
 262149                if (velocity.IsZero) continue;
 134150                candidate.Clear();
 134151                candidate.Parameter.Set(WideDirection3d.Dot(TriangleCircularGeometry.Subtract(origin, input.First), outw
 134152                candidate.ParameterDenominator.Set(velocity);
 134153                if (velocity.Sign < 0)
 134154                { candidate.Parameter.MultiplySign(-1); candidate.ParameterDenominator.MultiplySign(-1); }
 134155                SetPoint(input, candidate);
 156            }
 1518157            else if (!Seed(input, candidate, seed)) continue;
 1616158            offset.Clear();
 12928159            for (int axis = 0; axis < 3; axis++)
 160            {
 4848161                ContactQuadratic.Scale(candidate.Denominator, Extend(Component(origin, axis)), term);
 4848162                term.Add(candidate.Point(axis), -1);
 9696163                ContactQuadratic.Scale(term, Extend(Component(outward, axis)), product); offset.Add(product);
 164            }
 1616165            if (offset.Sign(candidate.Root) < 0) continue;
 3102166            term.Set(square); ScaleCoordinates(candidate, term);
 12408167            for (int axis = 0; axis < 3; axis++)
 168            {
 4653169                ContactQuadratic.Scale(offset, Extend(Component(outward, axis)), term);
 4653170                candidate.Boundary(axis).Add(term);
 4653171                candidate.Normal(axis).Set(Extend(Component(outward, axis)));
 172            }
 1551173            if (central)
 174            {
 532175                ContactQuadratic.Scale(candidate.Denominator, Extend(input.Core), bound);
 1064176                bound.CopyTo(term); term.Add(candidate.Boundary(2), -1);
 532177                if (term.Sign(candidate.Root) < 0) continue;
 670178                bound.CopyTo(term); term.Add(candidate.Boundary(2));
 335179                if (term.Sign(candidate.Root) < 0) continue;
 180            }
 1173181            Keep(input, candidate, ref selection);
 182        }
 470183    }
 184
 185    private static void AccumulateLine(scoped Input input, WideDirection3d first, WideDirection3d second,
 186        scoped ReadOnlySpan<WideDirection3d> cone, scoped ref Selection selection)
 187    {
 822188        int Words = input.Words;
 822189        int StorageWords = Fields * 2 * Words;
 822190        WideDirection3d axis = TriangleCircularGeometry.Subtract(second, first);
 191        // Positive thickness/core length and distinct prism edges keep every line finite and nonzero.
 192        System.Diagnostics.Debug.Assert(!axis.IsZero);
 822193        WideDirection3d offset = TriangleCircularGeometry.Subtract(input.First, first);
 1644194        Signed832 ee = input.Edge.SquaredLength, ff = axis.SquaredLength,
 2466195            ef = WideDirection3d.Dot(input.Edge, axis), ew = WideDirection3d.Dot(input.Edge, offset), fw = WideDirection
 1644196        Span<ulong> work = stackalloc ulong[16 * Words]; Span<int> workSigns = stackalloc int[16];
 1644197        ContactQuadratic a = ContactQuadratic.At(work, workSigns, 0, Words), b = ContactQuadratic.At(work, workSigns, 1,
 1644198            determinant = ContactQuadratic.At(work, workSigns, 2, Words), term = ContactQuadratic.At(work, workSigns, 3,
 822199            upper = ContactQuadratic.At(work, workSigns, 5, Words),
 1644200            projection = ContactQuadratic.At(work, workSigns, 6, Words), divisor = ContactQuadratic.At(work, workSigns, 
 2466201        a.Set(ee); b.Set(ff); ContactQuadratic.Multiply(a, b, ReadOnlySpan<ulong>.Empty, determinant);
 2466202        a.Set(ef); ContactQuadratic.Multiply(a, a, ReadOnlySpan<ulong>.Empty, term); determinant.Add(term, -1);
 1644203        Span<ulong> values = stackalloc ulong[StorageWords], root = stackalloc ulong[Words];
 1644204        Span<int> signs = stackalloc int[2 * Fields]; var candidate = new Candidate(values, signs, root);
 822205        int seedCount = input.Edge.IsZero ? 1 : 8;
 9392206        for (int seed = 0; seed < seedCount; seed++)
 207        {
 3874208            if (seed == 5)
 209            {
 436210                if (determinant.Signs[0] == 0) continue;
 1296211                candidate.Clear(); a.Set(ef); b.Set(fw); ContactQuadratic.Multiply(a, b, root, candidate.Parameter);
 1296212                a.Set(ff); b.Set(ew); ContactQuadratic.Multiply(a, b, root, term); candidate.Parameter.Add(term, -1);
 648213                determinant.CopyTo(candidate.ParameterDenominator); SetPoint(input, candidate);
 214            }
 3438215            else if (seed >= 6)
 216            {
 872217                if (ef.IsZero) continue;
 784218                candidate.Clear(); candidate.Parameter.Set(WideArithmetic.SubtractSigned832(seed == 6 ? default : ff, fw
 392219                candidate.ParameterDenominator.Set(ef);
 752220                if (ef.Sign < 0) { candidate.Parameter.MultiplySign(-1); candidate.ParameterDenominator.MultiplySign(-1)
 392221                SetPoint(input, candidate);
 222            }
 2566223            else if (!Seed(input, candidate, seed)) continue;
 3210224            if (seed == 5)
 225            {
 972226                a.Set(ee); b.Set(fw); ContactQuadratic.Multiply(a, b, root, projection);
 1296227                a.Set(ef); b.Set(ew); ContactQuadratic.Multiply(a, b, root, term); projection.Add(term, -1);
 324228                candidate.Denominator.CopyTo(divisor);
 229            }
 230            else
 231            {
 2886232                projection.Clear();
 23088233                for (int component = 0; component < 3; component++)
 234                {
 8658235                    ContactQuadratic.Scale(candidate.Denominator, Extend(Component(first, component)), term);
 17316236                    candidate.Point(component).CopyTo(a); a.Add(term, -1);
 17316237                    ContactQuadratic.Scale(a, Extend(Component(axis, component)), term); projection.Add(term);
 238                }
 2886239                ContactQuadratic.Scale(candidate.Denominator, ff, divisor);
 240            }
 6420241            divisor.CopyTo(upper); upper.Add(projection, -1);
 3210242            if (projection.Sign(candidate.Root) < 0 || upper.Sign(candidate.Root) < 0) continue;
 7270243            if (seed != 5) { a.Set(ff); ScaleCoordinates(candidate, a); }
 20752244            for (int component = 0; component < 3; component++)
 245            {
 7782246                ContactQuadratic.Scale(candidate.Denominator, Extend(Component(first, component)), candidate.Boundary(co
 15564247                ContactQuadratic.Scale(projection, Extend(Component(axis, component)), term); candidate.Boundary(compone
 248            }
 2594249            KeepPlanar(input, candidate, cone, ref selection);
 250        }
 822251    }
 252
 253    private static void AccumulateVertex(scoped Input input, WideDirection3d point,
 254        scoped ReadOnlySpan<WideDirection3d> cone, scoped ref Selection selection)
 255    {
 468256        int Words = input.Words;
 468257        int StorageWords = Fields * 2 * Words;
 936258        Span<ulong> values = stackalloc ulong[StorageWords], root = stackalloc ulong[Words];
 936259        Span<int> signs = stackalloc int[2 * Fields]; var candidate = new Candidate(values, signs, root);
 468260        int seedCount = input.Edge.IsZero ? 1 : 4;
 3264261        for (int seed = 0; seed < seedCount; seed++)
 262        {
 1164263            if (seed == 3)
 264            {
 464265                candidate.Clear(); candidate.Parameter.Set(WideDirection3d.Dot(
 232266                    TriangleCircularGeometry.Subtract(point, input.First), input.Edge));
 464267                candidate.ParameterDenominator.Set(input.Edge.SquaredLength); SetPoint(input, candidate);
 268            }
 932269            else Seed(input, candidate, seed);
 9312270            for (int axis = 0; axis < 3; axis++)
 3492271                ContactQuadratic.Scale(candidate.Denominator, Extend(Component(point, axis)), candidate.Boundary(axis));
 1164272            KeepPlanar(input, candidate, cone, ref selection);
 273        }
 468274    }
 275
 276    private static void KeepPlanar(scoped Input input, scoped Candidate candidate,
 277        scoped ReadOnlySpan<WideDirection3d> cone, scoped ref Selection selection)
 278    {
 3775279        int Words = input.Words;
 7550280        Span<ulong> values = stackalloc ulong[8 * Words]; Span<int> signs = stackalloc int[8];
 7550281        ContactQuadratic sum = ContactQuadratic.At(values, signs, 0, Words), term = ContactQuadratic.At(values, signs, 1
 7550282            a = ContactQuadratic.At(values, signs, 2, Words), b = ContactQuadratic.At(values, signs, 3, Words);
 3775283        bool nonzero = false;
 30200284        for (int axis = 0; axis < 3; axis++)
 285        {
 22650286            candidate.Boundary(axis).CopyTo(candidate.Normal(axis)); candidate.Normal(axis).Add(candidate.Point(axis), -
 11325287            nonzero |= candidate.Normal(axis).Sign(candidate.Root) != 0;
 288        }
 3775289        if (nonzero)
 290        {
 33096291            foreach (WideDirection3d wall in cone)
 26472292            { Dot(candidate, wall, sum, term); if (sum.Sign(candidate.Root) > 0) return; }
 6624293            Keep(input, candidate, ref selection); return;
 294        }
 25295        Span<WideDirection3d> walls = stackalloc WideDirection3d[input.Fan.Length + cone.Length];
 50296        input.Fan.CopyTo(walls); cone.CopyTo(walls[input.Fan.Length..]);
 297        // A nonempty pointed cone in three dimensions contains an axis or
 298        // an extreme ray at two wall planes. Degenerate lines keep both signs.
 200299        for (int axis = 0; axis < 3; axis++)
 450300            for (int branch = -1; branch <= 1; branch += 2)
 301            {
 1200302                for (int component = 0; component < 3; component++)
 450303                    candidate.Normal(component).Set(component == axis ? Extend(Signed576.ExtendValue(Signed192.Signed(br
 150304                KeepPlanarNormal(input, candidate, cone, ref selection);
 305            }
 432306        for (int first = 0; first < walls.Length; first++)
 1670307            for (int second = first + 1; second < walls.Length; second++)
 308            {
 5152309                for (int axis = 0; axis < 3; axis++)
 310                {
 3864311                    int next = (axis + 1) % 3, last = (axis + 2) % 3;
 3864312                    a.Set(Extend(Component(walls[first], next))); b.Set(Extend(Component(walls[second], last)));
 1932313                    ContactQuadratic.Multiply(a, b, candidate.Root, candidate.Normal(axis));
 3864314                    a.Set(Extend(Component(walls[first], last))); b.Set(Extend(Component(walls[second], next)));
 3864315                    ContactQuadratic.Multiply(a, b, candidate.Root, term); candidate.Normal(axis).Add(term, -1);
 316                }
 644317                KeepPlanarNormal(input, candidate, cone, ref selection);
 7084318                for (int axis = 0; axis < 3; axis++) candidate.Normal(axis).MultiplySign(-1);
 644319                KeepPlanarNormal(input, candidate, cone, ref selection);
 320            }
 25321    }
 322
 323    private static void KeepPlanarNormal(scoped Input input, scoped Candidate candidate,
 324        scoped ReadOnlySpan<WideDirection3d> cone, scoped ref Selection selection)
 325    {
 1438326        int Words = input.Words;
 2876327        Span<ulong> values = stackalloc ulong[4 * Words]; Span<int> signs = stackalloc int[4];
 2876328        var sum = ContactQuadratic.At(values, signs, 0, Words); var term = ContactQuadratic.At(values, signs, 1, Words);
 10087329        foreach (WideDirection3d wall in cone)
 8677330        { Dot(candidate, wall, sum, term); if (sum.Sign(candidate.Root) > 0) return; }
 705331        Keep(input, candidate, ref selection);
 705332    }
 333    private const int ObliqueValueCellWords = (16 * (CircularRimContactAlgebra.ValueWords * 64 + 11) + 255) / 64;
 334
 335    private struct ObliqueSelection
 336    {
 337        internal bool HasValue, IsZero, IsRational;
 338        internal WideDirection3d First, Second;
 339        internal int Cap, Region, ParameterOrdinal, ValueOrdinal, ValueShift;
 340    }
 341
 342    private static bool TryImproveObliqueRims(scoped Input input, scoped Selection analytic, out FixedContactAnchors con
 343    {
 153344        int ValueWords = input.ValueWords;
 153345        int ObliqueValueCellWords = (16 * (ValueWords * 64 + 11) + 255) / 64;
 153346        contact = default;
 153347        if (input.Edge.Y.IsZero || input.Edge.X.IsZero && input.Edge.Z.IsZero || input.Radius == Fixed64.Zero
 233348            || analytic.HasValue && analytic.MetricSigns[10] == 0) return false;
 73349        Span<ulong> bestValues = stackalloc ulong[5 * ValueWords];
 73350        Span<sbyte> bestSigns = stackalloc sbyte[5];
 73351        Span<ulong> bestCell = stackalloc ulong[ObliqueValueCellWords];
 73352        ObliqueSelection best = default;
 73353        CircularRimContactAlgebra.GetBasis(input.Edge, out WideDirection3d u, out WideDirection3d v);
 73354        int firstRegion = input.Length == Fixed64.Zero ? 0 : -1;
 73355        Span<Signed576> bounds = stackalloc Signed576[9]
 73356        { input.First.X, input.First.Y, input.First.Z, input.Edge.X, input.Edge.Y, input.Edge.Z, input.Cap, input.Core, 
 73357        int valueShift = TriangleCircularGeometry.GetValueShift(bounds, 5);
 320358        for (int region = firstRegion; region <= (input.Length == Fixed64.Zero ? 0 : 1); region += 2)
 522359            for (int cap = -1; cap <= 1; cap += 2)
 1044360                for (int firstSign = -1; firstSign <= 1; firstSign += 2)
 2088361                    for (int secondSign = -1; secondSign <= 1; secondSign += 2)
 362                    {
 1392363                        WideDirection3d first = firstSign < 0 ? -u : u, second = secondSign < 0 ? -v : v;
 696364                        AccumulateObliqueChart(input, analytic, first, second, region, cap, valueShift,
 696365                            bestValues, bestSigns, bestCell, ref best);
 696366                        AccumulateObliqueChart(input, analytic, second, first, region, cap, valueShift,
 696367                            bestValues, bestSigns, bestCell, ref best);
 368                    }
 108369        if (!best.HasValue) return false;
 38370        contact = MaterializeOblique(input, best, valueShift, bestValues, bestSigns, bestCell);
 38371        return true;
 372    }
 373
 1120374    private static WideDirection3d RimOffset(scoped Input input, int region, int cap) => new(input.First.X,
 1120375        WideArithmetic.SubtractSigned576(input.First.Y, cap < 0 ? WideArithmetic.Negate(input.Cap) : input.Cap),
 1120376        WideArithmetic.SubtractSigned576(input.First.Z, region < 0 ? WideArithmetic.Negate(input.Core) : region > 0 ? in
 377
 378    private static void AccumulateObliqueChart(scoped Input input, scoped Selection analytic,
 379        WideDirection3d first, WideDirection3d second, int region, int cap, int valueShift,
 380        scoped Span<ulong> bestValues, scoped Span<sbyte> bestSigns, scoped Span<ulong> bestCell, ref ObliqueSelection b
 381    {
 1392382        int Words = input.Words;
 1392383        int ValueWords = input.ValueWords;
 1392384        int ObliqueValueCellWords = (16 * (ValueWords * 64 + 11) + 255) / 64;
 385        // The cap generator and stadium hemisphere must agree with the exit
 386        // ray -n. Reject an entirely unpermitted chart before its quartic.
 1740387        if (first.Y.Sign * cap > 0 && WideArithmetic.AddSigned576(first.Y, second.Y).Sign * cap > 0) return;
 1044388        if (region != 0 && first.Z.Sign * region > 0
 1156389            && WideArithmetic.AddSigned576(first.Z, second.Z).Sign * region > 0) return;
 1864390        Span<ulong> data = stackalloc ulong[26 * Words]; Span<sbyte> signs = stackalloc sbyte[26];
 932391        WideDirection3d offset = RimOffset(input, region, cap);
 932392        CircularRimContactAlgebra.BuildParameter(offset, input.Radial, input.Scale,
 932393            first, second, data, signs);
 1864394        Span<ulong> batchCells = stackalloc ulong[64]; Span<int> batchShifts = stackalloc int[8];
 932395        FiniteAxisValueRoots roots = WideFiniteAxisIntersection.GetFiniteValueRoots(data[..(5 * Words)], signs[..5], bat
 932396        Span<ulong> cell = stackalloc ulong[WideFiniteAxisIntersection.GetFiniteValueRootCellWords(data[..(5 * Words)], 
 1864397        Span<ulong> values = stackalloc ulong[5 * ValueWords]; Span<sbyte> valueSigns = stackalloc sbyte[5];
 1864398        Span<ulong> valueCell = stackalloc ulong[ObliqueValueCellWords]; bool valuesReady = false;
 3100399        for (int ordinal = 0; ordinal < roots.Count; ordinal++)
 400        {
 618401            FiniteAxisValueRoot root = FiniteAxisValueRoots.GetRoot(roots, ordinal, data[..(5 * Words)], signs[..5], cel
 618402            int kSign = CircularRimContactAlgebra.Sign(ref root, data, signs, 8, 2);
 618403            if (kSign == 0 || CircularRimContactAlgebra.Sign(ref root, data, signs, 10, 3) != -kSign) continue;
 288404            int gapSign = CircularRimContactAlgebra.Sign(ref root, data, signs, 13, 3) * kSign;
 288405            if (gapSign < 0 || !AdmitObliqueFoot(input, first, second, region, cap, ref root)) continue;
 90406            var candidate = new ObliqueSelection
 90407            { HasValue = true, First = first, Second = second, Region = region, Cap = cap, ParameterOrdinal = ordinal };
 90408            if (gapSign == 0)
 74409            { if (!best.IsZero) { candidate.IsZero = true; best = candidate; } continue; }
 70410            if (best.IsZero) continue;
 64411            if (!valuesReady)
 124412            { CircularRimContactAlgebra.BuildValues(input.Edge, offset, input.Radial, valueShift, values, valueSigns); v
 64413            FiniteAxisValueRoot value = ConvexContactValueRoot.MapSquaredValue(input.Scale, valueShift,
 64414                ref root, data.Slice(16 * Words, 5 * Words), signs.Slice(16, 5), data.Slice(21 * Words, 5 * Words), sign
 64415                values, valueSigns, valueCell);
 64416            int comparison = best.HasValue ? WideFiniteAxisIntersection.CompareFiniteValueRoots(value,
 64417                RestoreObliqueValue(bestValues, bestSigns, bestCell, best)) : analytic.HasValue
 64418                    ? ConvexContactValueRoot.CompareRootSquared(input.Scale, valueShift, ref value,
 64419                        new ConvexContactCandidate(analytic.Metric, analytic.MetricSigns, analytic.MetricSigns[10], Word
 64420            if (comparison >= 0) continue;
 69421            values.CopyTo(bestValues); valueSigns.CopyTo(bestSigns); valueCell.CopyTo(bestCell);
 46422            candidate.ValueOrdinal = value.Ordinal; candidate.ValueShift = value.DenominatorShift;
 46423            candidate.IsRational = value.IsRational; best = candidate;
 424        }
 932425    }
 426
 427    private static FiniteAxisValueRoot RestoreObliqueValue(ReadOnlySpan<ulong> values, ReadOnlySpan<sbyte> signs,
 24428        Span<ulong> cell, ObliqueSelection selection) => new()
 24429    { Coefficients = values, Signs = signs, LowerNumerator = cell, Ordinal = selection.ValueOrdinal,
 24430        DenominatorShift = selection.ValueShift, IsRational = selection.IsRational };
 431
 432    private static void RimParameter(scoped Input input, WideDirection3d first, WideDirection3d second, int region,
 433        out Signed832 a0, out Signed832 a1, out Signed832 b0, out Signed832 b1, out Signed832 d0, out Signed832 d1)
 434    {
 150435        WideDirection3d offset = RimOffset(input, region, 1);
 150436        WideDirection3d end = new(WideArithmetic.AddSigned576(offset.X, input.Edge.X),
 150437            WideArithmetic.AddSigned576(offset.Y, input.Edge.Y), WideArithmetic.AddSigned576(offset.Z, input.Edge.Z));
 150438        WideDirection3d tangent0 = new(WideArithmetic.Negate(first.Z), default, first.X),
 150439            tangent1 = new(WideArithmetic.Negate(second.Z), default, second.X);
 300440        a0 = WideDirection3d.Dot(offset, tangent0); a1 = WideDirection3d.Dot(offset, tangent1);
 300441        b0 = WideDirection3d.Dot(end, tangent0); b1 = WideDirection3d.Dot(end, tangent1);
 300442        d0 = WideArithmetic.SubtractSigned832(b0, a0); d1 = WideArithmetic.SubtractSigned832(b1, a1);
 150443    }
 444
 445    private static int RootSign(scoped ref FiniteAxisValueRoot root, Signed832 first, Signed832 second)
 446    {
 2596447        Span<ulong> values = stackalloc ulong[26]; Span<sbyte> signs = stackalloc sbyte[2];
 2596448        WideArithmetic.GetMagnitude(first, values[..13]); WideArithmetic.GetMagnitude(second, values[13..]);
 2596449        signs[0] = (sbyte)first.Sign; signs[1] = (sbyte)second.Sign;
 1298450        return WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, values, signs);
 451    }
 452
 453    private static bool AdmitObliqueFoot(scoped Input input, WideDirection3d first, WideDirection3d second,
 454        int region, int cap, scoped ref FiniteAxisValueRoot root)
 455    {
 280456        int Words = input.Words;
 280457        if (RootSign(ref root, Extend(first.Y), Extend(second.Y)) * cap > 0
 318458            || region != 0 && RootSign(ref root, Extend(first.Z), Extend(second.Z)) * region > 0) return false;
 1622459        foreach (WideDirection3d wall in input.Fan)
 764460            if (RootSign(ref root, WideDirection3d.Dot(first, wall), WideDirection3d.Dot(second, wall)) < 0) return fals
 112461        RimParameter(input, first, second, region, out Signed832 a0, out Signed832 a1,
 112462            out Signed832 b0, out Signed832 b1, out Signed832 d0, out Signed832 d1);
 112463        int denominator = RootSign(ref root, d0, d1);
 464        // A zero tangent divisor is meridional: L=0 then W=0 forces K=0, rejected by chart admission.
 465        System.Diagnostics.Debug.Assert(denominator != 0);
 466        int start, end;
 112467        if (input.Clip.IsEmpty)
 468        {
 100469            start = -RootSign(ref root, a0, a1) * denominator;
 100470            end = RootSign(ref root, b0, b1) * denominator;
 471        }
 472        else
 473        {
 12474            ref readonly RationalSegmentInterval clip = ref input.Clip[0];
 12475            start = CompareObliqueParameter(ref root, a0, a1, d0, d1,
 12476                clip.WideLowerNumerator, clip.WideLowerDenominator) * denominator;
 12477            end = -CompareObliqueParameter(ref root, a0, a1, d0, d1,
 12478                clip.WideUpperNumerator, clip.WideUpperDenominator) * denominator;
 479        }
 120480        if (start < 0 || end < 0 || input.InteriorOnly && (start == 0 || end == 0)) return false;
 125481        if (!input.RequireSourceInside) return true;
 482        // The tangent-plane ratio is the matched finite foot. Check the full
 483        // slab before ranking its exact gap; outer opposite feet cannot hide
 484        // behind the preflight's unrelated intersecting segment parameter.
 166485        Span<ulong> coordinates = stackalloc ulong[8 * Words]; Span<sbyte> coordinateSigns = stackalloc sbyte[8];
 664486        for (int axis = 0; axis < 3; axis++)
 487        {
 249488            WriteRootCoordinate(input, axis, a0, a1, d0, d1, coordinates.Slice(axis * 2 * Words, 2 * Words),
 249489                coordinateSigns.Slice(axis * 2, 2));
 249490            if (denominator < 0)
 234491            { coordinateSigns[2 * axis] = (sbyte)-coordinateSigns[2 * axis]; coordinateSigns[2 * axis + 1] = (sbyte)-coo
 492        }
 83493        CircularRimContactAlgebra.Write(coordinates, coordinateSigns, 6, denominator < 0 ? WideArithmetic.SubtractSigned
 83494        CircularRimContactAlgebra.Write(coordinates, coordinateSigns, 7, denominator < 0 ? WideArithmetic.SubtractSigned
 83495        return ContainsObliqueFoot(input, coordinates, coordinateSigns, ref root);
 496    }
 497
 498    private static int CompareObliqueParameter(scoped ref FiniteAxisValueRoot root,
 499        Signed832 a0, Signed832 a1, Signed832 d0, Signed832 d1, Signed832 numerator, Signed832 denominator)
 500    {
 501        // The foot is -a(u)/d(u). A retained bound adds at most 319
 502        // bits to the <398-bit linear coefficients; do not narrow to Signed832.
 48503        Span<ulong> values = stackalloc ulong[2 * Words], factor = stackalloc ulong[13],
 48504            coefficient = stackalloc ulong[13], product = stackalloc ulong[Words];
 24505        Span<sbyte> signs = stackalloc sbyte[2];
 144506        for (int index = 0; index < 2; index++)
 507        {
 96508            Signed832 a = index == 0 ? a0 : a1, d = index == 0 ? d0 : d1;
 96509            Import(denominator, factor); Import(a, coefficient);
 48510            WideArithmetic.MultiplyMagnitudes(coefficient, factor, Slot(values, index, Words));
 48511            int sign = -a.Sign;
 96512            Import(numerator, factor); Import(d, coefficient);
 48513            WideArithmetic.MultiplyMagnitudes(coefficient, factor, product);
 96514            Add(product, -d.Sign * numerator.Sign, Slot(values, index, Words), ref sign); signs[index] = (sbyte)sign;
 515        }
 24516        return WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, values, signs);
 517    }
 518
 519    private static void WriteRootCoordinate(scoped Input input, int axis, Signed832 a0, Signed832 a1,
 520        Signed832 d0, Signed832 d1, Span<ulong> values, Span<sbyte> signs)
 521    {
 249522        int Words = input.Words;
 523        // Coordinate numerators need the complete 198+398-bit product; the
 524        // existing forty-word polynomial owner retains it without narrowing.
 996525        Span<ulong> factor = stackalloc ulong[13], first = stackalloc ulong[Words], second = stackalloc ulong[Words], pr
 249526        Import(Component(input.First, axis), factor);
 1494527        for (int index = 0; index < 2; index++)
 528        {
 996529            Signed832 d = index == 0 ? d0 : d1, a = index == 0 ? a0 : a1;
 996530            Import(d, first); WideArithmetic.MultiplyMagnitudes(first, factor, values.Slice(index * Words, Words));
 498531            int sign = d.Sign * Component(input.First, axis).Sign;
 996532            Import(a, second); Import(Component(input.Edge, axis), first);
 498533            WideArithmetic.MultiplyMagnitudes(first, second, product);
 498534            Add(product, -a.Sign * Component(input.Edge, axis).Sign, values.Slice(index * Words, Words), ref sign);
 498535            signs[index] = (sbyte)sign;
 536        }
 249537    }
 538
 539    private static bool ContainsObliqueFoot(scoped Input input, scoped ReadOnlySpan<ulong> coordinates,
 540        scoped ReadOnlySpan<sbyte> coordinateSigns, scoped ref FiniteAxisValueRoot root)
 541    {
 83542        int Words = input.Words;
 166543        Span<ulong> work = stackalloc ulong[13 * Words]; Span<sbyte> signs = stackalloc sbyte[13];
 166544        Span<ulong> query = work[..(2 * Words)], z = work.Slice(2 * Words, 2 * Words),
 166545            denominator = work.Slice(4 * Words, 2 * Words), square = work.Slice(6 * Words, 3 * Words),
 166546            term = work.Slice(9 * Words, 3 * Words), product = Slot(work, 12, Words);
 83547        Span<ulong> scalar = stackalloc ulong[13];
 166548        ReadOnlySpan<ulong> d = coordinates.Slice(6 * Words, 2 * Words); ReadOnlySpan<sbyte> dSigns = coordinateSigns.Sl
 83549        Import(input.Cap, scalar);
 456550        for (int cap = -1; cap <= 1; cap += 2)
 551        {
 954552            for (int index = 0; index < 2; index++)
 553            {
 636554                WideArithmetic.MultiplyMagnitudes(Slot(d, index, Words), scalar, Slot(query, index, Words)); int sign = 
 636555                Add(Slot(coordinates, index + 2, Words), cap * coordinateSigns[index + 2], Slot(query, index, Words), re
 556            }
 173557            if (WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, query, signs[..2]) < 0) return fa
 558        }
 138559        coordinates.Slice(4 * Words, 2 * Words).CopyTo(z); coordinateSigns.Slice(4, 2).CopyTo(signs.Slice(2, 2));
 69560        Import(input.Core, scalar);
 228561        for (int region = -1; region <= 1; region += 2)
 562        {
 660563            for (int index = 0; index < 2; index++)
 564            {
 440565                WideArithmetic.MultiplyMagnitudes(Slot(d, index, Words), scalar, Slot(query, index, Words)); int sign = 
 440566                Add(Slot(coordinates, index + 4, Words), coordinateSigns[index + 4], Slot(query, index, Words), ref sign
 567            }
 110568            int side = WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, query, signs[..2]);
 305569            if (side * region >= 0) { query.CopyTo(z); signs[..2].CopyTo(signs.Slice(2, 2)); break; }
 53570            if (region == 1) { z.Clear(); signs.Slice(2, 2).Clear(); }
 571        }
 69572        WideFiniteAxisIntersection.MultiplyFiniteAxisPolynomials(coordinates[..(2 * Words)], coordinateSigns[..2],
 69573            coordinates[..(2 * Words)], coordinateSigns[..2], square, signs.Slice(6, 3), product);
 69574        WideFiniteAxisIntersection.MultiplyFiniteAxisPolynomials(z, signs.Slice(2, 2), z, signs.Slice(2, 2), term, signs
 552575        for (int index = 0; index < 3; index++)
 621576        { int sign = signs[index + 6]; Add(Slot(term, index, Words), signs[index + 9], Slot(square, index, Words), ref s
 69577        Import(input.Radial, scalar);
 414578        for (int index = 0; index < 2; index++)
 276579        { WideArithmetic.MultiplyMagnitudes(Slot(d, index, Words), scalar, Slot(denominator, index, Words)); signs[index
 69580        WideFiniteAxisIntersection.MultiplyFiniteAxisPolynomials(denominator, signs.Slice(4, 2), denominator, signs.Slic
 552581        for (int index = 0; index < 3; index++)
 621582        { int sign = signs[index + 9]; Add(Slot(square, index, Words), -signs[index + 6], Slot(term, index, Words), ref 
 69583        return WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref root, term, signs.Slice(9, 3)) >= 0;
 584    }
 585
 586    private static FixedContactAnchors MaterializeOblique(scoped Input input, ObliqueSelection best, int valueShift,
 587        scoped ReadOnlySpan<ulong> bestValues, scoped ReadOnlySpan<sbyte> bestSigns, scoped Span<ulong> bestCell)
 588    {
 38589        int Words = input.Words;
 76590        Span<ulong> data = stackalloc ulong[26 * Words]; Span<sbyte> signs = stackalloc sbyte[26];
 38591        CircularRimContactAlgebra.BuildParameter(RimOffset(input, best.Region, best.Cap), input.Radial,
 38592            input.Scale, best.First, best.Second, data, signs);
 38593        Span<ulong> cell = stackalloc ulong[WideFiniteAxisIntersection.GetFiniteValueRootCellWords(data[..(5 * Words)], 
 38594        bool found = WideFiniteAxisIntersection.TryGetFiniteValueRoot(data[..(5 * Words)], signs[..5], best.ParameterOrd
 595        System.Diagnostics.Debug.Assert(found);
 38596        RimParameter(input, best.First, best.Second, best.Region, out Signed832 a0, out Signed832 a1,
 38597            out Signed832 b0, out Signed832 b1, out Signed832 d0, out Signed832 d1);
 76598        int denominator = RootSign(ref root, d0, d1); Vector3d point = default;
 304599        for (int axis = 0; axis < 3; axis++)
 114600            point[axis] = input.Frame.RadialFrame.ShapeFrame.HasExactScale
 114601                ? TriangleCylinderRimWitnesses.RoundRootCoordinate(Component(input.First, axis),
 114602                    WideArithmetic.AddSigned576(Component(input.First, axis), Component(input.Edge, axis)), input.Scale,
 114603                    a0, a1, b0, b1, d0, d1, denominator, ref root)
 114604                : TriangleCylinderRimWitnesses.RoundRootCoordinate(input.Segment.Start[axis], input.Segment.End[axis],
 114605                    a0, a1, b0, b1, d0, d1, denominator, ref root);
 76606        Span<ulong> gradient = stackalloc ulong[54]; Span<sbyte> gradientSigns = stackalloc sbyte[6];
 38607        CircularRimContactAlgebra.WriteGradient(best.First, best.Second, gradient, gradientSigns);
 76608        gradient.Slice(18, 18).Clear(); gradientSigns.Slice(2, 2).Clear();
 38609        Vector3d local = ConvexContactValueRoot.GetScaledNormalizedDirection(ref root, gradient, gradientSigns, input.Ra
 76610        Vector3d core = default; FixedPointAnchorTerm3d exactTerm = default;
 38611        if (best.Region != 0)
 612        {
 14613            core = TriangleCapsuleSlabEndpointWitnesses.GetCore(Vector2d.Forward, input.Length, -best.Region, out exactT
 14614            local = TriangleCapsuleSlabEndpointWitnesses.AdjustRoot(ref root, gradient, gradientSigns,
 14615                input.Radius, core, exactTerm, local, out int integralMask);
 14616            exactTerm = TriangleCapsuleSlabEndpointWitnesses.CreateTerm(Vector2d.Forward,
 14617                best.Region < 0 ? -input.Length : input.Length, core, integralMask);
 618        }
 38619        Fixed64 halfThickness = input.FullHeight == Fixed64.Zero ? input.HalfThickness : input.FullHeight * Fixed64.Half
 38620        local.Y = best.Cap < 0 ? -halfThickness : halfThickness;
 38621        if ((input.FullHeight.m_rawValue & 1L) != 0)
 2622            exactTerm = new(exactTerm.X, FixedPointAnchorTerm3d.GetResidual(Fixed64.One,
 2623                best.Cap < 0 ? -input.FullHeight : input.FullHeight, Fixed64.Zero, Fixed64.Zero,
 2624                core.Y, local.Y), exactTerm.Z);
 38625        var basis = new WideRationalBasis3d(input.SlabRotation);
 38626        CircularRimContactAlgebra.WriteGradient(CircularRimContactAlgebra.Transform(basis, best.First),
 38627            CircularRimContactAlgebra.Transform(basis, best.Second), gradient, gradientSigns);
 38628        Vector3d normal = ConvexContactValueRoot.GetNormalizedDirection(ref root, gradient, gradientSigns, 1);
 76629        Fixed64 depth = default; bool clamped = false;
 38630        if (!best.IsZero)
 631        {
 20632            FiniteAxisValueRoot value = RestoreObliqueValue(bestValues, bestSigns, bestCell, best);
 20633            ConvexContactValueRoot.GetRoundedDepth(input.Scale, valueShift, ref value, out depth, out clamped);
 634        }
 38635        return new(new FixedPointAnchor(input.Origin, input.Rotation, point),
 38636            new FixedPointAnchor(input.Center, input.SlabRotation, core, local, exactTerm), normal, depth, clamped);
 637    }
 638}

Methods/Properties

TryGetContact(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,System.Boolean,FixedMathSharp.Geometry.FixedContactAnchors&,System.Boolean)
TryGetContact(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,System.Boolean,FixedMathSharp.Geometry.RationalSegmentInterval&,FixedMathSharp.Geometry.FixedContactAnchors&,System.Boolean)
TryGetFeaturePenetration(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,System.Boolean,FixedMathSharp.Geometry.FixedContactAnchors&,System.Boolean)
TryGetContactCore(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,System.Boolean,System.Boolean,System.ReadOnlySpan`1<FixedMathSharp.Geometry.RationalSegmentInterval>,System.Boolean,FixedMathSharp.Geometry.FixedContactAnchors&)
TryGetContact(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,System.Boolean,FixedMathSharp.Geometry.FixedContactAnchors&,System.Boolean)
TryGetContact(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,System.Boolean,FixedMathSharp.Geometry.RationalSegmentInterval&,FixedMathSharp.Geometry.FixedContactAnchors&,System.Boolean)
TryGetFeaturePenetration(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,System.Boolean,FixedMathSharp.Geometry.FixedContactAnchors&,System.Boolean)
TryGetContactCore(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,System.Boolean,System.Boolean,System.ReadOnlySpan`1<FixedMathSharp.Geometry.RationalSegmentInterval>,System.Boolean,FixedMathSharp.Geometry.FixedContactAnchors&)
TryGetContactCore(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,System.Boolean,System.Boolean,System.ReadOnlySpan`1<FixedMathSharp.Geometry.RationalSegmentInterval>,System.Boolean,FixedMathSharp.Geometry.FiniteSlabSectionFrame&,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.FixedContactAnchors&)
get_Words()
get_ValueWords()
.ctor(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FiniteSlabSectionFrame,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,System.Boolean,System.Boolean,System.ReadOnlySpan`1<FixedMathSharp.Geometry.RationalSegmentInterval>,System.Boolean)
.ctor(System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Span`1<System.UInt64>)
get_Words()
Field(System.Int32)
Point(System.Int32)
Boundary(System.Int32)
get_Parameter()
get_ParameterDenominator()
get_Denominator()
Normal(System.Int32)
Clear()
CopyTo(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate)
.ctor(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Span`1<System.UInt64>,System.Span`1<System.Int32>)
get_One()
Extend(FixedMathSharp.Signed576)
Extend(FixedMathSharp.Signed320)
SetPoint(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate)
ScaleCoordinates(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,FixedMathSharp.Geometry.ContactQuadratic)
Keep(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
Dot(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
CompareWitnesses(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate)
Contains(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Boolean)
Materialize(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection)
AccumulateCurved(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
AccumulateCurvedPoint(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
SetCap(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Int32)
SetSectionParameter(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Boolean)
AccumulateArcFoot(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Int32,System.Int32,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
AdmitsArc(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Int32,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
AccumulateRadialFamily(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Int32,System.Int32,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
SetFamilyNormal(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Int32,System.Int32,System.Int32)
AccumulateTouchNormals(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Int32,System.Int32,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
AccumulateMeridionalRims(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
AccumulatePrincipalRims(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
KeepRim(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Int32,System.Int32,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
AccumulatePrism(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
PrismVertex(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,System.Int32)
Axis(System.Int64,System.Int64,System.Int64)
AccumulateStraight(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
Seed(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.Int32)
AccumulatePlane(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,System.Boolean,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
AccumulateLine(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
AccumulateVertex(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.WideDirection3d,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
KeepPlanar(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
KeepPlanarNormal(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Candidate,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection&)
TryImproveObliqueRims(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection,FixedMathSharp.Geometry.FixedContactAnchors&)
RimOffset(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,System.Int32,System.Int32)
AccumulateObliqueChart(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Selection,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,System.Int32,System.Int32,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.SByte>,System.Span`1<System.UInt64>,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/ObliqueSelection&)
RestoreObliqueValue(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.SByte>,System.Span`1<System.UInt64>,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/ObliqueSelection)
RimParameter(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,System.Int32,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
RootSign(FixedMathSharp.Geometry.FiniteAxisValueRoot&,FixedMathSharp.Signed832,FixedMathSharp.Signed832)
AdmitObliqueFoot(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Geometry.WideDirection3d,System.Int32,System.Int32,FixedMathSharp.Geometry.FiniteAxisValueRoot&)
CompareObliqueParameter(FixedMathSharp.Geometry.FiniteAxisValueRoot&,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832)
WriteRootCoordinate(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,System.Int32,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.Span`1<System.UInt64>,System.Span`1<System.SByte>)
ContainsObliqueFoot(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.SByte>,FixedMathSharp.Geometry.FiniteAxisValueRoot&)
MaterializeOblique(FixedMathSharp.Geometry.SegmentSlabSurfaceContact/Input,FixedMathSharp.Geometry.SegmentSlabSurfaceContact/ObliqueSelection,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.SByte>,System.Span`1<System.UInt64>)