< Summary

Information
Class: FixedMathSharp.Geometry.CapsulePlaneRayValue
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/CapsulePlaneRayValue.cs
Line coverage
100%
Covered lines: 287
Uncovered lines: 0
Coverable lines: 287
Total lines: 465
Line coverage: 100%
Branch coverage
100%
Covered branches: 84
Total branches: 84
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetStorageWords(...)100%11100%
get_Metadata()100%11100%
get_HasValue()100%11100%
.ctor(...)100%11100%
Restore(...)100%11100%
CopyFrom(...)100%22100%
TrySetUpperRoot(...)100%1414100%
Compare(...)100%11100%
Compare(...)100%11100%
CompareQuadratic(...)100%11100%
CompareSquaredQuadratic(...)100%11100%
SignLinear(...)100%11100%
LinearSign(...)100%11100%
TryGetPoint(...)100%66100%
TryRoundCoordinate(...)100%1818100%
GetCoordinateFloorBounds(...)100%66100%
CompareCoordinate(...)100%11100%
TryGetDepth(...)100%1414100%
GetDepthFloorBounds(...)100%44100%
CompareDepth(...)100%22100%
CellCapacity()100%22100%
GetRoot(...)100%22100%
SetCoefficient(...)100%11100%
BuildNorm(...)100%22100%
SignAtRoot(...)100%1212100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// CapsulePlaneRayValue.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9using System.Runtime.CompilerServices;
 10
 11namespace FixedMathSharp.Geometry;
 12
 13
 14
 15/// <summary>
 16/// One positive outward ray root of a quadratic over an independent quadratic
 17/// point field. The norm polynomial and selected ordinal borrow caller storage.
 18/// </summary>
 19internal ref struct CapsulePlaneRayValue
 20{
 21    // Opposite rays through edge-stationary quadratic witnesses have the largest
 22    // norm: coefficients <3190 bits, normalization adds <=402, and the point
 23    // radicand is <2256. Its complete degree-four norm stays <9600 bits.
 24    internal const int PolynomialWords = 160, SignCount = 5, CellWords = 8;
 25    internal const int StorageWords = SignCount * PolynomialWords + CellWords;
 906726    internal static int GetStorageWords(int polynomialWords) => SignCount * polynomialWords + CellWords;
 27    private readonly int _words;
 28    private readonly Span<ulong> _polynomial, _cell;
 29    private readonly Span<sbyte> _signs;
 30    private CapsulePlaneRayValueMetadata _metadata;
 28331    internal CapsulePlaneRayValueMetadata Metadata => _metadata;
 432    internal bool HasValue => _metadata.HasValue;
 33
 34    internal CapsulePlaneRayValue(Span<ulong> storage, Span<sbyte> signs, int polynomialWords = PolynomialWords)
 35    {
 181436        _words = polynomialWords;
 181437        _polynomial = storage[..(SignCount * polynomialWords)];
 181438        _cell = storage.Slice(SignCount * polynomialWords, CellWords);
 362839        _signs = signs[..SignCount]; _metadata = default;
 181440    }
 41
 68142    internal void Restore(CapsulePlaneRayValueMetadata metadata) => _metadata = metadata;
 43
 44    internal void CopyFrom(scoped CapsulePlaneRayValue other)
 45    {
 28246        _polynomial.Clear();
 338447        for (int index = 0; index < SignCount; index++)
 48        {
 141049            ReadOnlySpan<ulong> coefficient = other._polynomial.Slice(index * other._words, other._words);
 141050            coefficient[..WideArithmetic.GetActiveMagnitudeLength(coefficient)].CopyTo(_polynomial.Slice(index * _words,
 51        }
 56452        other._signs.CopyTo(_signs); other._cell.CopyTo(_cell);
 28253        _metadata = other._metadata;
 28254    }
 55
 56    /// <summary>Retains the positive root of a*t²+2*b*t+c with nonnegative outward derivative.</summary>
 57    internal bool TrySetUpperRoot(scoped ContactQuadratic a, scoped ContactQuadratic b, scoped ContactQuadratic c,
 58        scoped ReadOnlySpan<ulong> pointRoot, int valueShift)
 59    {
 54260        _metadata = default;
 54261        Span<ulong> rational = stackalloc ulong[3 * _words];
 54262        Span<ulong> radical = stackalloc ulong[3 * _words];
 108463        Span<sbyte> rationalSigns = stackalloc sbyte[3], radicalSigns = stackalloc sbyte[3];
 216864        rational.Clear(); radical.Clear(); rationalSigns.Clear(); radicalSigns.Clear();
 54265        SetCoefficient(c, rational, rationalSigns, radical, radicalSigns, 0, 0);
 54266        SetCoefficient(b, rational, rationalSigns, radical, radicalSigns, 1, valueShift + 1);
 54267        SetCoefficient(a, rational, rationalSigns, radical, radicalSigns, 2, 2 * valueShift);
 54268        bool rationalRay = ((byte)radicalSigns[0] | (byte)radicalSigns[1] | (byte)radicalSigns[2]) == 0
 54269            || WideArithmetic.GetActiveMagnitudeLength(pointRoot) == 0;
 54270        if (rationalRay)
 71        {
 72            // Rational ray coefficients need only their original quadratic.
 73            // Squaring it would duplicate every root and double its height.
 51874            _polynomial.Clear(); _signs.Clear();
 51875            rational.CopyTo(_polynomial); rationalSigns.CopyTo(_signs);
 76        }
 77        else
 28378            BuildNorm(rational, rationalSigns, radical, radicalSigns, pointRoot, _polynomial, _signs);
 54279        WideFiniteAxisIntersection.NormalizeFiniteAxisPolynomialPowerOfTwo(_polynomial, _signs);
 108480        Span<ulong> batchCells = stackalloc ulong[64]; Span<int> shifts = stackalloc int[8];
 54281        FiniteAxisValueRoots roots = WideFiniteAxisIntersection.GetFiniteValueRoots(_polynomial, _signs, batchCells, shi
 54282        Span<ulong> cell = stackalloc ulong[WideFiniteAxisIntersection.GetFiniteValueRootCellWords(_polynomial, _signs)]
 54283        Span<ulong> derivativeRational = stackalloc ulong[2 * _words];
 54284        Span<ulong> derivativeRadical = stackalloc ulong[2 * _words];
 108485        Span<sbyte> derivativeRationalSigns = stackalloc sbyte[2], derivativeRadicalSigns = stackalloc sbyte[2];
 54286        WideFiniteAxisIntersection.DifferentiateFiniteAxisPolynomial(rational, rationalSigns, derivativeRational, deriva
 54287        WideFiniteAxisIntersection.DifferentiateFiniteAxisPolynomial(radical, radicalSigns, derivativeRadical, derivativ
 144488        for (int ordinal = 0; ordinal < roots.Count; ordinal++)
 89        {
 55090            FiniteAxisValueRoot root = FiniteAxisValueRoots.GetRoot(roots, ordinal, _polynomial, _signs, cell);
 91            // The norm also contains the conjugate field's roots. Unsquared
 92            // admission and the outward derivative identify the intended exit.
 55093            if (!rationalRay && SignAtRoot(ref root, rational, rationalSigns, radical, radicalSigns, pointRoot, knownNor
 55094                || SignAtRoot(ref root, derivativeRational, derivativeRationalSigns,
 55095                    derivativeRadical, derivativeRadicalSigns, pointRoot) < 0)
 96                continue;
 37097            bool compact = root.DenominatorShift < CellWords * 64;
 37098            _cell.Clear();
 73999            if (compact) root.LowerNumerator[..WideArithmetic.GetActiveMagnitudeLength(root.LowerNumerator)].CopyTo(_cel
 370100            _metadata = new CapsulePlaneRayValueMetadata(valueShift, ordinal, roots.Count, root.Signs.Length,
 370101                root.DenominatorShift, root.IsRational, compact);
 370102            return true;
 103        }
 172104        return false;
 105    }
 106
 107    internal int Compare(scoped CapsulePlaneRayValue other)
 108    {
 89109        Span<ulong> firstCell = stackalloc ulong[CellCapacity()];
 89110        Span<ulong> secondCell = stackalloc ulong[other.CellCapacity()];
 89111        FiniteAxisValueRoot first = GetRoot(_polynomial, _signs, _cell, _metadata, firstCell),
 89112            second = GetRoot(other._polynomial, other._signs, other._cell, other._metadata, secondCell);
 89113        int shift = Math.Max(_metadata.ValueShift, other._metadata.ValueShift);
 89114        Span<ulong> firstPolynomial = stackalloc ulong[SignCount * _words];
 89115        Span<ulong> secondPolynomial = stackalloc ulong[SignCount * other._words];
 178116        first.Coefficients.CopyTo(firstPolynomial); second.Coefficients.CopyTo(secondPolynomial);
 178117        int firstScale = shift - _metadata.ValueShift, secondScale = shift - other._metadata.ValueShift;
 89118        first.Coefficients = firstPolynomial[..first.Coefficients.Length];
 89119        second.Coefficients = secondPolynomial[..second.Coefficients.Length];
 89120        WideFiniteAxisIntersection.ScaleFiniteAxisPolynomialVariable(firstPolynomial[..first.Coefficients.Length], first
 89121        WideFiniteAxisIntersection.ScaleFiniteAxisPolynomialVariable(secondPolynomial[..second.Coefficients.Length], sec
 178122        first.DenominatorShift += firstScale; second.DenominatorShift += secondScale;
 89123        return WideFiniteAxisIntersection.CompareFiniteValueRoots(first, second);
 124    }
 125
 126    internal int Compare(scoped CapsulePlaneRayValue other, Signed320 divisor, Signed320 otherDivisor)
 127    {
 128        System.Diagnostics.Debug.Assert(divisor.Sign > 0 && otherDivisor.Sign > 0);
 12129        Span<ulong> firstCell = stackalloc ulong[CellCapacity()];
 12130        Span<ulong> secondCell = stackalloc ulong[other.CellCapacity()];
 12131        FiniteAxisValueRoot first = GetRoot(_polynomial, _signs, _cell, _metadata, firstCell),
 12132            second = GetRoot(other._polynomial, other._signs, other._cell, other._metadata, secondCell);
 12133        int shift = Math.Max(_metadata.ValueShift, other._metadata.ValueShift);
 24134        int firstScale = shift - _metadata.ValueShift, secondScale = shift - other._metadata.ValueShift;
 12135        Span<ulong> firstDenominator = stackalloc ulong[5 + (firstScale + 63) / 64];
 12136        Span<ulong> secondDenominator = stackalloc ulong[5 + (secondScale + 63) / 64];
 12137        Span<ulong> magnitude = stackalloc ulong[5];
 24138        firstDenominator.Clear(); secondDenominator.Clear();
 12139        WideArithmetic.GetMagnitude(divisor, out magnitude[4], out magnitude[3], out magnitude[2], out magnitude[1], out
 12140        int sign = 0;
 12141        WideArithmetic.AddShiftedSignedMagnitude(magnitude, 1, firstScale, firstDenominator, ref sign);
 12142        WideArithmetic.GetMagnitude(otherDivisor, out magnitude[4], out magnitude[3], out magnitude[2], out magnitude[1]
 12143        sign = 0;
 12144        WideArithmetic.AddShiftedSignedMagnitude(magnitude, 1, secondScale, secondDenominator, ref sign);
 145        // t = alpha*2^ValueShift. A common binary factor cancels, leaving
 146        // original roots divided by D*2^(commonShift-ValueShift).
 12147        return WideFiniteAxisIntersection.CompareFiniteValueRoots(first, firstDenominator, second, secondDenominator);
 148    }
 149
 150    /// <summary>Compares this positive value with an exact quadratic ratio whose denominator is positive.</summary>
 151    internal int CompareQuadratic(scoped ContactQuadratic numerator, scoped ContactQuadratic denominator,
 152        scoped ReadOnlySpan<ulong> root)
 153    {
 448154        Span<ulong> values = stackalloc ulong[2 * numerator.FieldWords]; Span<int> signs = stackalloc int[2];
 448155        ContactQuadratic constant = new(values, signs); numerator.CopyTo(constant, -1);
 224156        return SignLinear(constant, denominator, root);
 157    }
 158
 159    /// <summary>Compares this nonnegative value squared with a nonnegative exact quadratic ratio.</summary>
 160    internal int CompareSquaredQuadratic(scoped ContactQuadratic numerator, scoped ContactQuadratic denominator,
 161        scoped ReadOnlySpan<ulong> root)
 162    {
 14163        Span<ulong> cell = stackalloc ulong[CellCapacity()];
 14164        FiniteAxisValueRoot parameter = GetRoot(_polynomial, _signs, _cell, _metadata, cell);
 14165        int words = Math.Max(parameter.Coefficients.Length / parameter.Signs.Length,
 14166            Math.Max(ContactQuadratic.ActiveWords(numerator), ContactQuadratic.ActiveWords(denominator))
 14167                + (2 * _metadata.ValueShift + 63) / 64) + 1;
 28168        Span<ulong> rational = stackalloc ulong[3 * words], radical = stackalloc ulong[3 * words];
 28169        Span<sbyte> rationalSigns = stackalloc sbyte[3], radicalSigns = stackalloc sbyte[3];
 56170        rational.Clear(); radical.Clear(); rationalSigns.Clear(); radicalSigns.Clear();
 14171        SetCoefficient(numerator, rational, rationalSigns, radical, radicalSigns, 0, 0);
 28172        rationalSigns[0] = (sbyte)-rationalSigns[0]; radicalSigns[0] = (sbyte)-radicalSigns[0];
 14173        SetCoefficient(denominator, rational, rationalSigns, radical, radicalSigns, 2, 2 * _metadata.ValueShift);
 14174        return SignAtRoot(ref parameter, rational, rationalSigns, radical, radicalSigns, root);
 175    }
 176
 177    /// <summary>Exact sign of constant+slope*t, including an independent quadratic coefficient field.</summary>
 178    internal int SignLinear(scoped ContactQuadratic constant, scoped ContactQuadratic slope,
 179        scoped ReadOnlySpan<ulong> root)
 180    {
 746181        Span<ulong> cell = stackalloc ulong[CellCapacity()];
 746182        FiniteAxisValueRoot parameter = GetRoot(_polynomial, _signs, _cell, _metadata, cell);
 746183        return LinearSign(ref parameter, constant, slope, root, _metadata.ValueShift);
 184    }
 185
 186    private static int LinearSign(scoped ref FiniteAxisValueRoot parameter, scoped ContactQuadratic constant,
 187        scoped ContactQuadratic slope, scoped ReadOnlySpan<ulong> root, int valueShift)
 188    {
 2464189        int _words = Math.Max(parameter.Coefficients.Length / parameter.Signs.Length, 2 * Math.Max(constant.FieldWords, 
 4928190        Span<ulong> rational = stackalloc ulong[2 * _words], radical = stackalloc ulong[2 * _words];
 4928191        Span<sbyte> rationalSigns = stackalloc sbyte[2], radicalSigns = stackalloc sbyte[2];
 9856192        rational.Clear(); radical.Clear(); rationalSigns.Clear(); radicalSigns.Clear();
 2464193        SetCoefficient(constant, rational, rationalSigns, radical, radicalSigns, 0, 0);
 2464194        SetCoefficient(slope, rational, rationalSigns, radical, radicalSigns, 1, valueShift);
 2464195        return SignAtRoot(ref parameter, rational, rationalSigns, radical, radicalSigns, root);
 196    }
 197
 198    /// <summary>Rounds capsule-local (q+t*direction)/coordinateScale once at the final coordinate lattice.</summary>
 199    internal bool TryGetPoint(scoped ContactQuadratic qx, scoped ContactQuadratic qy,
 200        scoped ContactQuadratic qz, scoped ContactQuadratic qd, scoped ReadOnlySpan<ulong> pointRoot,
 201        WideDirection3d direction, Signed320 coordinateScale, out Vector3d point)
 202    {
 212203        Span<ulong> values = stackalloc ulong[8 * _words]; Span<int> signs = stackalloc int[8];
 106204        ContactQuadratic denominator = ContactQuadratic.At(values, signs, 0, _words);
 106205        ContactQuadratic sx = ContactQuadratic.At(values, signs, 1, _words);
 106206        ContactQuadratic sy = ContactQuadratic.At(values, signs, 2, _words);
 106207        ContactQuadratic sz = ContactQuadratic.At(values, signs, 3, _words);
 106208        ContactQuadratic.Scale(qd, Signed576.ExtendValue(coordinateScale), denominator);
 106209        ContactQuadratic.Scale(qd, direction.X, sx);
 106210        ContactQuadratic.Scale(qd, direction.Y, sy);
 106211        ContactQuadratic.Scale(qd, direction.Z, sz);
 106212        Span<ulong> cell = stackalloc ulong[CellCapacity()];
 106213        FiniteAxisValueRoot parameter = GetRoot(_polynomial, _signs, _cell, _metadata, cell);
 106214        if (!TryRoundCoordinate(ref parameter, qx, sx, denominator, pointRoot, _metadata.ValueShift, out Fixed64 px)
 106215            || !TryRoundCoordinate(ref parameter, qy, sy, denominator, pointRoot, _metadata.ValueShift, out Fixed64 py)
 106216            || !TryRoundCoordinate(ref parameter, qz, sz, denominator, pointRoot, _metadata.ValueShift, out Fixed64 pz))
 217        {
 6218            point = default;
 6219            return false;
 220        }
 100221        point = new Vector3d(px, py, pz);
 100222        return true;
 223    }
 224
 225    private static bool TryRoundCoordinate(scoped ref FiniteAxisValueRoot parameter, scoped ContactQuadratic constant,
 226        scoped ContactQuadratic slope, scoped ContactQuadratic denominator, scoped ReadOnlySpan<ulong> root,
 227        int valueShift, out Fixed64 coordinate)
 228    {
 312229        coordinate = default;
 312230        int _words = Math.Max(constant.FieldWords, Math.Max(slope.FieldWords, denominator.FieldWords)) + 2;
 624231        Span<ulong> values = stackalloc ulong[6 * _words]; Span<int> signs = stackalloc int[6];
 312232        ContactQuadratic query = ContactQuadratic.At(values, signs, 0, _words);
 312233        ContactQuadratic term = ContactQuadratic.At(values, signs, 1, _words);
 312234        ContactQuadratic doubledSlope = ContactQuadratic.At(values, signs, 2, _words);
 624235        slope.CopyTo(doubledSlope); doubledSlope.Add(slope);
 312236        Signed192 upper = WideArithmetic.AddSigned192(WideArithmetic.AddSigned192(Signed192.Signed(long.MaxValue),
 312237            Signed192.Signed(long.MaxValue)), Signed192.Signed(1));
 312238        Signed192 lower = WideArithmetic.SubtractSigned192(WideArithmetic.AddSigned192(Signed192.Signed(long.MinValue),
 312239            Signed192.Signed(long.MinValue)), Signed192.Signed(1));
 312240        if (CompareCoordinate(ref parameter, constant, doubledSlope, denominator, root, upper, query, term, valueShift) 
 312241            || CompareCoordinate(ref parameter, constant, doubledSlope, denominator, root, lower, query, term, valueShif
 6242            return false;
 243        // A zero direction retains the original point field; its coordinate
 244        // needs no value-root search after the exact range checks above.
 306245        if ((slope.Signs[0] | slope.Signs[1]) == 0)
 246        {
 184247            coordinate = ContactQuadratic.RoundRatio(constant, denominator, root);
 184248            return true;
 249        }
 244250        long lowerFloor = long.MinValue, upperFloor = long.MaxValue;
 122251        if (parameter.DenominatorShift < CellWords * 64)
 119252            GetCoordinateFloorBounds(parameter, constant, slope, denominator, root, valueShift,
 119253                out lowerFloor, out upperFloor);
 122254        ulong low = unchecked((ulong)lowerFloor) ^ (1UL << 63);
 122255        ulong high = unchecked((ulong)upperFloor) ^ (1UL << 63);
 1097256        while (low < high)
 257        {
 975258            ulong middle = low + ((high - low) >> 1) + 1;
 975259            long raw = unchecked((long)(middle ^ (1UL << 63)));
 975260            Signed192 threshold = WideArithmetic.AddSigned192(Signed192.Signed(raw), Signed192.Signed(raw));
 1383261            if (CompareCoordinate(ref parameter, constant, doubledSlope, denominator, root, threshold, query, term, valu
 567262            else high = middle - 1;
 263        }
 122264        long floor = unchecked((long)(low ^ (1UL << 63)));
 122265        Signed192 half = WideArithmetic.AddSigned192(WideArithmetic.AddSigned192(Signed192.Signed(floor),
 122266            Signed192.Signed(floor)), Signed192.Signed(1));
 122267        int comparison = CompareCoordinate(ref parameter, constant, doubledSlope, denominator, root, half, query, term, 
 122268        coordinate = Fixed64.FromRaw(floor + (comparison > 0 || comparison == 0 && (floor & 1) != 0 ? 1L : 0L));
 122269        return true;
 270    }
 271
 272    [MethodImpl(MethodImplOptions.NoInlining)] // Return interval scratch before exact root signs.
 273    private static void GetCoordinateFloorBounds(scoped FiniteAxisValueRoot parameter,
 274        scoped ContactQuadratic constant, scoped ContactQuadratic slope, scoped ContactQuadratic denominator,
 275        scoped ReadOnlySpan<ulong> root, int valueShift, out long lower, out long upper)
 276    {
 277        // t=2^s*alpha and alpha is in [L,L+1]/2^h. With positive D the
 278        // affine quotient's extrema are its endpoints, even for negative slope.
 279        // Keep both point-field values exact; their independent CQ enclosures
 280        // only narrow the search. Cancellation and range uncertainty fall back.
 119281        int commonShift = Math.Max(0, parameter.DenominatorShift - valueShift);
 119282        int endpointShift = Math.Max(0, valueShift - parameter.DenominatorShift);
 119283        int endpointWords = WideArithmetic.GetActiveMagnitudeLength(parameter.LowerNumerator)
 119284            + 1 + (endpointShift + 63) / 64;
 119285        int commonWords = commonShift / 64 + 1;
 119286        int words = Math.Max(Math.Max(ContactQuadratic.ActiveWords(constant), ContactQuadratic.ActiveWords(denominator))
 119287            + commonWords, ContactQuadratic.ActiveWords(slope) + endpointWords) + 1;
 238288        Span<ulong> values = stackalloc ulong[6 * words]; Span<int> signs = stackalloc int[6];
 119289        ContactQuadratic numerator = ContactQuadratic.At(values, signs, 0, words);
 119290        ContactQuadratic divisor = ContactQuadratic.At(values, signs, 1, words);
 119291        ContactQuadratic term = ContactQuadratic.At(values, signs, 2, words);
 238292        Span<ulong> common = stackalloc ulong[commonWords], endpoint = stackalloc ulong[endpointWords];
 238293        common.Clear(); common[commonShift / 64] = 1UL << (commonShift & 63);
 119294        ContactQuadratic.Scale(denominator, common, 1, divisor);
 238295        lower = long.MaxValue; upper = long.MinValue;
 119296        Span<ulong> one = stackalloc ulong[1] { 1 };
 714297        for (int index = 0; index < 2; index++)
 298        {
 476299            endpoint.Clear(); int sign = 0;
 238300            WideArithmetic.AddShiftedSignedMagnitude(parameter.LowerNumerator, 1, endpointShift, endpoint, ref sign);
 238301            if (index != 0 && !parameter.IsRational)
 78302                WideArithmetic.AddShiftedSignedMagnitude(one, 1, endpointShift, endpoint, ref sign);
 238303            ContactQuadratic.Scale(constant, common, 1, numerator);
 476304            ContactQuadratic.Scale(slope, endpoint, 1, term); numerator.Add(term);
 476305            long endpointLower = long.MinValue, endpointUpper = long.MaxValue;
 238306            ContactQuadratic.RefineRoundRatioBounds(numerator, divisor, root, ref endpointLower, ref endpointUpper);
 476307            lower = Math.Min(lower, endpointLower); upper = Math.Max(upper, endpointUpper);
 308        }
 119309    }
 310
 311    private static int CompareCoordinate(scoped ref FiniteAxisValueRoot parameter, scoped ContactQuadratic constant,
 312        scoped ContactQuadratic doubledSlope, scoped ContactQuadratic denominator, scoped ReadOnlySpan<ulong> root,
 313        Signed192 twiceRaw, scoped ContactQuadratic query, scoped ContactQuadratic term, int valueShift)
 314    {
 3436315        constant.CopyTo(query); query.Add(constant);
 1718316        ContactQuadratic.Scale(denominator, Signed576.ExtendValue(Signed320.ExtendValue(twiceRaw)), term);
 1718317        query.Add(term, -1);
 1718318        return LinearSign(ref parameter, query, doubledSlope, root, valueShift);
 319    }
 320
 321    /// <summary>Rounds t*sqrt(metric)/scale to nonnegative raw depth; scale and metric are positive.</summary>
 322    internal bool TryGetDepth(Signed832 metric, Signed320 scale, out Fixed64 depth, out bool overflow)
 323    {
 274324        Span<ulong> cell = stackalloc ulong[CellCapacity()]; FiniteAxisValueRoot parameter = GetRoot(_polynomial, _signs
 274325        Span<ulong> metricWords = stackalloc ulong[13]; WideArithmetic.GetMagnitude(metric, metricWords);
 274326        Span<ulong> scaleWords = stackalloc ulong[5]; WideArithmetic.GetMagnitude(scale, out scaleWords[4], out scaleWor
 274327        Span<ulong> squaredScale = stackalloc ulong[10]; WideArithmetic.MultiplyMagnitudes(scaleWords, scaleWords, squar
 137328        int maximum = CompareDepth(ref parameter, metricWords, squaredScale, unchecked((ulong)long.MaxValue << 1), _meta
 143329        if (maximum >= 0) { depth = Fixed64.MaxValue; overflow = maximum > 0; return true; }
 270330        ulong lower = 0, upper = 1UL << 63;
 135331        if (_metadata.HasCompactCell)
 332        {
 134333            GetDepthFloorBounds(parameter, metricWords, squaredScale, _metadata.ValueShift, out lower, out upper);
 334            // The search finds the first inadmissible integer, then subtracts one.
 268335            lower++; upper++;
 336        }
 1554337        while (lower < upper)
 338        {
 1419339            ulong middle = lower + ((upper - lower) >> 1);
 1428340            if (CompareDepth(ref parameter, metricWords, squaredScale, middle << 1, _metadata.ValueShift) >= 0) lower = 
 1410341            else upper = middle;
 342        }
 135343        ulong floor = lower - 1;
 135344        int comparison = CompareDepth(ref parameter, metricWords, squaredScale, (floor << 1) | 1, _metadata.ValueShift);
 135345        depth = Fixed64.FromRaw((long)(floor + (comparison > 0 || comparison == 0 && (floor & 1) != 0 ? 1UL : 0)));
 270346        overflow = false; return true;
 347    }
 348
 349    private static void GetDepthFloorBounds(scoped FiniteAxisValueRoot parameter,
 350        scoped ReadOnlySpan<ulong> metric, scoped ReadOnlySpan<ulong> squaredScale, int valueShift,
 351        out ulong lower, out ulong upper)
 352    {
 353        // The retained dyadic cell encloses t. Squaring its nonnegative
 354        // endpoints bounds raw depth; exact signs still decide the final half.
 134355        int cellWords = WideArithmetic.GetActiveMagnitudeLength(parameter.LowerNumerator) + 1;
 134356        int shift = 2 * (parameter.DenominatorShift - valueShift);
 134357        int words = Math.Max(2 * cellWords + metric.Length, squaredScale.Length)
 134358            + (Math.Abs(shift) + 63) / 64 + 1;
 268359        Span<ulong> endpoint = stackalloc ulong[cellWords], square = stackalloc ulong[2 * cellWords];
 402360        Span<ulong> product = stackalloc ulong[words], numerator = stackalloc ulong[words], denominator = stackalloc ulo
 268361        endpoint.Clear(); parameter.LowerNumerator[..(cellWords - 1)].CopyTo(endpoint);
 134362        denominator.Clear();
 134363        int sign = 0;
 134364        WideArithmetic.AddShiftedSignedMagnitude(squaredScale, 1, Math.Max(0, shift), denominator, ref sign);
 134365        lower = upper = 0;
 134366        Span<ulong> one = stackalloc ulong[1] { 1 };
 804367        for (int index = 0; index < 2; index++)
 368        {
 268369            WideArithmetic.MultiplyMagnitudes(endpoint, endpoint, square);
 268370            WideArithmetic.MultiplyMagnitudes(square, metric, product);
 536371            numerator.Clear(); sign = 0;
 268372            WideArithmetic.AddShiftedSignedMagnitude(product, 1, Math.Max(0, -shift), numerator, ref sign);
 268373            ulong floor = WideArithmetic.GetRatioFloorSquareRoot(numerator, denominator, long.MaxValue);
 536374            if (index == 0) lower = floor; else upper = floor;
 268375            WideArithmetic.AddMagnitudeInto(one, endpoint);
 376        }
 134377    }
 378
 379    private static int CompareDepth(scoped ref FiniteAxisValueRoot parameter, scoped ReadOnlySpan<ulong> metric,
 380        scoped ReadOnlySpan<ulong> squaredScale, ulong twiceRaw, int valueShift)
 381    {
 1691382        int _words = Math.Max(PolynomialWords, parameter.Coefficients.Length / parameter.Signs.Length);
 3382383        Span<ulong> query = stackalloc ulong[3 * _words]; Span<sbyte> signs = stackalloc sbyte[3];
 3382384        query.Clear(); signs.Clear();
 1691385        int sign = 0;
 1691386        WideArithmetic.AddShiftedSignedMagnitude(metric, 1, 2 * valueShift + 2,
 3382387            query.Slice(2 * _words, _words), ref sign); signs[2] = (sbyte)sign;
 3382388        Span<ulong> threshold = stackalloc ulong[2]; Fixed64.Multiply64To128(twiceRaw, twiceRaw, out threshold[1], out t
 1691389        WideArithmetic.MultiplyMagnitudes(threshold, squaredScale, query[.._words]);
 1691390        signs[0] = WideArithmetic.GetActiveMagnitudeLength(query[.._words]) == 0 ? (sbyte)0 : (sbyte)-1;
 1691391        return WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref parameter, query, signs);
 392    }
 393
 1205394    private int CellCapacity() => _metadata.HasCompactCell ? CellWords
 1205395        : WideFiniteAxisIntersection.GetFiniteValueRootCellWords(_polynomial[..(_metadata.PolynomialCount * _words)], _s
 396
 397    private static FiniteAxisValueRoot GetRoot(ReadOnlySpan<ulong> polynomial, ReadOnlySpan<sbyte> polynomialSigns,
 398        ReadOnlySpan<ulong> retainedCell, CapsulePlaneRayValueMetadata metadata, Span<ulong> cell)
 399    {
 1205400        int _words = polynomial.Length / polynomialSigns.Length;
 1205401        ReadOnlySpan<ulong> coefficients = polynomial[..(metadata.PolynomialCount * _words)];
 1205402        ReadOnlySpan<sbyte> signs = polynomialSigns[..metadata.PolynomialCount];
 1205403        if (!metadata.HasCompactCell)
 4404            return WideFiniteAxisIntersection.GetKnownFiniteValueRoot(coefficients, signs, metadata.Ordinal, metadata.Ro
 1201405        retainedCell.CopyTo(cell);
 1201406        return new FiniteAxisValueRoot { Coefficients = coefficients, Signs = signs, LowerNumerator = cell,
 1201407            DenominatorShift = metadata.DenominatorShift, Ordinal = metadata.Ordinal, IsRational = metadata.IsRational }
 408    }
 409
 410    private static void SetCoefficient(scoped ContactQuadratic value, Span<ulong> rational, Span<sbyte> rationalSigns,
 411        Span<ulong> radical, Span<sbyte> radicalSigns, int index, int shift)
 412    {
 6582413        int _words = rational.Length / rationalSigns.Length;
 13164414        int rationalSign = 0, radicalSign = 0;
 6582415        WideArithmetic.AddShiftedSignedMagnitude(value.Rational, value.Signs[0], shift,
 6582416            rational.Slice(index * _words, _words), ref rationalSign);
 6582417        WideArithmetic.AddShiftedSignedMagnitude(value.Radical, value.Signs[1], shift,
 6582418            radical.Slice(index * _words, _words), ref radicalSign);
 13164419        rationalSigns[index] = (sbyte)rationalSign; radicalSigns[index] = (sbyte)radicalSign;
 6582420    }
 421
 422    private static void BuildNorm(scoped ReadOnlySpan<ulong> rational, scoped ReadOnlySpan<sbyte> rationalSigns,
 423        scoped ReadOnlySpan<ulong> radical, scoped ReadOnlySpan<sbyte> radicalSigns, scoped ReadOnlySpan<ulong> root,
 424        Span<ulong> polynomial, Span<sbyte> signs)
 425    {
 906426        int words = polynomial.Length / signs.Length;
 1812427        Span<ulong> product = stackalloc ulong[words], radicalSquared = stackalloc ulong[polynomial.Length];
 906428        Span<sbyte> radicalSquaredSigns = stackalloc sbyte[signs.Length];
 906429        WideFiniteAxisIntersection.MultiplyFiniteAxisPolynomials(rational, rationalSigns, rational, rationalSigns,
 906430            polynomial, signs, product);
 906431        WideFiniteAxisIntersection.MultiplyFiniteAxisPolynomials(radical, radicalSigns, radical, radicalSigns,
 906432            radicalSquared, radicalSquaredSigns, product);
 8436433        for (int index = 0; index < signs.Length; index++)
 434        {
 3312435            WideArithmetic.MultiplyMagnitudes(radicalSquared.Slice(index * words, words), root, product);
 3312436            int sign = signs[index];
 3312437            WideArithmetic.AddShiftedSignedMagnitude(product, -radicalSquaredSigns[index], 0,
 6624438                polynomial.Slice(index * words, words), ref sign); signs[index] = (sbyte)sign;
 439        }
 906440    }
 441
 442    private static int SignAtRoot(scoped ref FiniteAxisValueRoot parameter,
 443        scoped ReadOnlySpan<ulong> rational, scoped ReadOnlySpan<sbyte> rationalSigns,
 444        scoped ReadOnlySpan<ulong> radical, scoped ReadOnlySpan<sbyte> radicalSigns, scoped ReadOnlySpan<ulong> root,
 445        bool knownNormRoot = false)
 446    {
 3222447        int rationalSign = WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref parameter, rational, rationa
 3222448        int radicalSign = WideArithmetic.GetActiveMagnitudeLength(root) == 0 ? 0
 3222449            : WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref parameter, radical, radicalSigns);
 3316450        if (rationalSign == 0) return radicalSign;
 5440451        if (radicalSign == 0 || rationalSign == radicalSign) return rationalSign;
 452        // The defining norm already proves equal magnitudes. Opposite signs
 453        // admit its unsquared branch without proving that same norm zero again.
 1009454        if (knownNormRoot) return 0;
 623455        int count = 2 * rationalSigns.Length - 1;
 1246456        int inputWords = rational.Length / rationalSigns.Length, active = 0;
 3766457        for (int index = 0; index < rationalSigns.Length; index++)
 1260458            active = Math.Max(active, Math.Max(WideArithmetic.GetActiveMagnitudeLength(rational.Slice(index * inputWords
 1260459                WideArithmetic.GetActiveMagnitudeLength(radical.Slice(index * inputWords, inputWords))));
 623460        int words = 2 * active + WideArithmetic.GetActiveMagnitudeLength(root) + 1;
 1246461        Span<ulong> norm = stackalloc ulong[count * words]; Span<sbyte> signs = stackalloc sbyte[count];
 623462        BuildNorm(rational, rationalSigns, radical, radicalSigns, root, norm, signs);
 623463        return rationalSign * WideFiniteAxisIntersection.GetSignAtFiniteValueRootAndRefine(ref parameter, norm, signs);
 464    }
 465}

Methods/Properties

GetStorageWords(System.Int32)
get_Metadata()
get_HasValue()
.ctor(System.Span`1<System.UInt64>,System.Span`1<System.SByte>,System.Int32)
Restore(FixedMathSharp.Geometry.CapsulePlaneRayValueMetadata)
CopyFrom(FixedMathSharp.Geometry.CapsulePlaneRayValue)
TrySetUpperRoot(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>,System.Int32)
Compare(FixedMathSharp.Geometry.CapsulePlaneRayValue)
Compare(FixedMathSharp.Geometry.CapsulePlaneRayValue,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
CompareQuadratic(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>)
CompareSquaredQuadratic(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>)
SignLinear(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>)
LinearSign(FixedMathSharp.Geometry.FiniteAxisValueRoot&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>,System.Int32)
TryGetPoint(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Geometry.WideDirection3d,FixedMathSharp.Signed320,FixedMathSharp.Vector3d&)
TryRoundCoordinate(FixedMathSharp.Geometry.FiniteAxisValueRoot&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Fixed64&)
GetCoordinateFloorBounds(FixedMathSharp.Geometry.FiniteAxisValueRoot,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.Int64&,System.Int64&)
CompareCoordinate(FixedMathSharp.Geometry.FiniteAxisValueRoot&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed192,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.Int32)
TryGetDepth(FixedMathSharp.Signed832,FixedMathSharp.Signed320,FixedMathSharp.Fixed64&,System.Boolean&)
GetDepthFloorBounds(FixedMathSharp.Geometry.FiniteAxisValueRoot,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.UInt64&,System.UInt64&)
CompareDepth(FixedMathSharp.Geometry.FiniteAxisValueRoot&,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.UInt64,System.Int32)
CellCapacity()
GetRoot(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.SByte>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Geometry.CapsulePlaneRayValueMetadata,System.Span`1<System.UInt64>)
SetCoefficient(FixedMathSharp.Geometry.ContactQuadratic,System.Span`1<System.UInt64>,System.Span`1<System.SByte>,System.Span`1<System.UInt64>,System.Span`1<System.SByte>,System.Int32,System.Int32)
BuildNorm(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.SByte>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.SByte>,System.ReadOnlySpan`1<System.UInt64>,System.Span`1<System.UInt64>,System.Span`1<System.SByte>)
SignAtRoot(FixedMathSharp.Geometry.FiniteAxisValueRoot&,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.SByte>,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.SByte>,System.ReadOnlySpan`1<System.UInt64>,System.Boolean)