< Summary

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

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%44100%
.ctor(...)100%88100%
.ctor(...)100%1212100%
Transform(...)100%11100%
ContainsPoint(...)100%11100%
ContainsTransformedPoint(...)100%66100%
IntersectsSegment(...)100%1010100%
IntersectsSegment(...)100%2020100%
IntersectsWideSegment(...)100%1616100%
TryGetPrimitiveWide(...)100%1010100%
TryGetFirstSegmentParameter(...)100%1414100%
TryGetFirstWideSegmentParameter(...)100%1616100%
TryGetPrimitive(...)100%88100%
TryGetCenteredAxisInterval(...)100%1414100%
IntersectsQuadratic(...)100%1212100%
IntersectsQuadratic(...)100%1212100%
IntersectsQuadratic(...)100%1212100%
IntersectsQuadratic(...)100%88100%
IntersectsQuadratic(...)100%1212100%
DotWide(...)100%11100%
Product(...)100%11100%
PolynomialSign(...)100%11100%
GetFirstQuadraticParameter(...)100%44100%
CompareProducts(...)100%11100%
Dot(...)100%11100%
Difference(...)100%11100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// CapsuleFiniteSectionFrame.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using System;
 9
 10namespace FixedMathSharp.Geometry;
 11
 12/// <summary>Exact closed finite-capsule admission in an authored rigid frame.</summary>
 13internal readonly struct CapsuleFiniteSectionFrame
 14{
 15    internal readonly CylinderPolytopeFrame ShapeFrame;
 16    internal readonly Fixed64 Length;
 17    private readonly Signed576 _radiusSquared;
 18    private readonly Signed832 _wideRadiusSquared;
 19
 20    /// <summary>Exact capsule-local coordinates supplied by a retained rational source chart.</summary>
 21    internal CapsuleFiniteSectionFrame(Fixed64 length, Fixed64 radius, Signed320 coordinateDenominator)
 22    {
 8723        Length = length;
 8724        ShapeFrame = new CylinderPolytopeFrame(length, radius, coordinateDenominator);
 8725        Signed320 scaledRadius = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(coordinateDenominator, Signed320
 8726        _wideRadiusSquared = ShapeFrame.HasExactScale ? Product(scaledRadius, scaledRadius) : default;
 8727        _radiusSquared = ShapeFrame.HasExactScale ? default : WideArithmetic.MultiplySigned320(scaledRadius, scaledRadiu
 8728    }
 29
 30    internal CapsuleFiniteSectionFrame(Vector3d origin, FixedQuaternion rotation,
 31        Vector3d center, FixedQuaternion capsuleRotation, Fixed64 length, Fixed64 radius)
 32    {
 73333        _wideRadiusSquared = default;
 73434        if (length < Fixed64.Zero) throw new ArgumentOutOfRangeException(nameof(length));
 73335        if (radius < Fixed64.Zero) throw new ArgumentOutOfRangeException(nameof(radius));
 73236        if (!rotation.IsNormalized()) throw new ArgumentException("The authored rotation must be normalized.", nameof(ro
 73137        if (!capsuleRotation.IsNormalized()) throw new ArgumentException("The capsule rotation must be normalized.", nam
 72938        Length = length;
 72939        ShapeFrame = new CylinderPolytopeFrame(center, capsuleRotation, length, radius, origin, rotation);
 72940        Signed320 scaledRadius = WideArithmetic.MultiplySigned192(ShapeFrame.Radius, ShapeFrame.Denominator);
 72941        _radiusSquared = WideArithmetic.MultiplySigned320(scaledRadius, scaledRadius);
 72942    }
 43
 44    internal CapsuleFiniteSectionFrame(in ScaledRigidFrame3d sourceFrame,
 45        Vector3d center, FixedQuaternion capsuleRotation, Fixed64 length, Fixed64 radius)
 46    {
 18647        if (sourceFrame.IsRigid)
 48        {
 649            this = new CapsuleFiniteSectionFrame(sourceFrame.RigidOrigin, sourceFrame.Rotation,
 650                center, capsuleRotation, length, radius);
 651            return;
 52        }
 18053        if (length < Fixed64.Zero || length > (Fixed64)8192)
 254            throw new ArgumentOutOfRangeException(nameof(length));
 17855        if (radius < Fixed64.Zero || radius > (Fixed64)4096)
 256            throw new ArgumentOutOfRangeException(nameof(radius));
 17657        if (!capsuleRotation.IsNormalized())
 158            throw new ArgumentException("The capsule rotation must be normalized.", nameof(capsuleRotation));
 17559        Length = length;
 17560        ShapeFrame = new CylinderPolytopeFrame(sourceFrame, center, capsuleRotation, Signed192.Raw(length), radius);
 17561        Signed320 scaledRadius = Signed320.NarrowValue(
 17562            WideArithmetic.MultiplySigned320(ShapeFrame.CoordinateDenominator, ShapeFrame.Radius));
 17563        _wideRadiusSquared = Product(scaledRadius, scaledRadius);
 17564        _radiusSquared = default;
 17565    }
 66
 2153067    internal WideAxis3 Transform(Vector3d point) => ShapeFrame.Transform(point);
 9768    internal bool ContainsPoint(Vector3d point) => ContainsTransformedPoint(Transform(point));
 69
 70    internal bool ContainsTransformedPoint(WideAxis3 point)
 71    {
 12272        Signed320 y = point.Y.Sign < 0 ? WideArithmetic.Negate(point.Y) : point.Y;
 12273        y = WideArithmetic.SubtractSigned320(y, ShapeFrame.Cap);
 17574        if (y.Sign < 0) y = default;
 12275        var offset = new WideAxis3(point.X, y, point.Z);
 12276        return ShapeFrame.HasExactScale
 12277            ? WideArithmetic.SubtractSigned832(DotWide(offset, offset), _wideRadiusSquared).Sign <= 0
 12278            : WideArithmetic.SubtractSigned576(Dot(offset, offset), _radiusSquared).Sign <= 0;
 79    }
 80
 81    internal bool IntersectsSegment(FixedSegment segment)
 82    {
 18283        WideAxis3 start = Transform(segment.Start), delta = Difference(Transform(segment.End), start);
 9184        if (ShapeFrame.HasExactScale)
 1385            return IntersectsWideSegment(start, delta, default);
 52286        for (int primitive = 0; primitive < (Length == Fixed64.Zero ? 1 : 3); primitive++)
 20487            if (TryGetPrimitive(start, delta, primitive, out Signed576 a, out Signed576 b, out Signed576 c,
 20488                    out Signed320 lowerN, out Signed320 lowerD, out Signed320 upperN, out Signed320 upperD)
 22589                && IntersectsQuadratic(a, b, c, lowerN, lowerD, upperN, upperD)) return true;
 5790        return false;
 91    }
 92
 93    /// <summary>Tests the retained exact subsegment, without rounding its endpoints.</summary>
 94    internal bool IntersectsSegment(FixedSegment segment, in RationalSegmentInterval clip)
 95    {
 20096        if (!clip.IsClipped) return IntersectsSegment(segment);
 36897        WideAxis3 start = Transform(segment.Start), delta = Difference(Transform(segment.End), start);
 18498        if (ShapeFrame.HasExactScale || clip.HasWideBounds)
 1299            return IntersectsWideSegment(start, delta, clip);
 502100        for (int primitive = 0; primitive < (Length == Fixed64.Zero ? 1 : 3); primitive++)
 101        {
 213102            if (!TryGetPrimitive(start, delta, primitive, out Signed576 a, out Signed576 b, out Signed576 c,
 213103                out Signed320 ln, out Signed320 ld, out Signed320 un, out Signed320 ud)) continue;
 213104            if (RationalSegmentInterval.CompareParameters(ln, ld, clip.LowerNumerator, clip.LowerDenominator) < 0)
 298105            { ln = clip.LowerNumerator; ld = clip.LowerDenominator; }
 213106            if (RationalSegmentInterval.CompareParameters(un, ud, clip.UpperNumerator, clip.UpperDenominator) > 0)
 312107            { un = clip.UpperNumerator; ud = clip.UpperDenominator; }
 213108            if (RationalSegmentInterval.CompareParameters(ln, ld, un, ud) <= 0
 347109                && IntersectsQuadratic(a, b, c, ln, ld, un, ud)) return true;
 110        }
 38111        return false;
 112    }
 113
 114    private bool IntersectsWideSegment(WideAxis3 start, WideAxis3 delta, in RationalSegmentInterval clip)
 115    {
 154116        for (int primitive = 0; primitive < (Length == Fixed64.Zero ? 1 : 3); primitive++)
 117        {
 57118            if (!TryGetPrimitiveWide(start, delta, primitive, out Signed832 a, out Signed832 b, out Signed832 c,
 57119                    out Signed320 ln, out Signed320 ld, out Signed320 un, out Signed320 ud))
 120                continue;
 51121            Signed832 lowerN = Signed832.ExtendValue(Signed576.ExtendValue(ln)),
 51122                lowerD = Signed832.ExtendValue(Signed576.ExtendValue(ld)),
 51123                upperN = Signed832.ExtendValue(Signed576.ExtendValue(un)),
 51124                upperD = Signed832.ExtendValue(Signed576.ExtendValue(ud));
 51125            if (clip.IsClipped)
 126            {
 20127                if (RationalSegmentInterval.CompareParameters(lowerN, lowerD, clip.WideLowerNumerator, clip.WideLowerDen
 24128                { lowerN = clip.WideLowerNumerator; lowerD = clip.WideLowerDenominator; }
 20129                if (RationalSegmentInterval.CompareParameters(upperN, upperD, clip.WideUpperNumerator, clip.WideUpperDen
 24130                { upperN = clip.WideUpperNumerator; upperD = clip.WideUpperDenominator; }
 131            }
 51132            if (RationalSegmentInterval.CompareParameters(lowerN, lowerD, upperN, upperD) <= 0
 51133                && IntersectsQuadratic(a, b, c, lowerN, lowerD, upperN, upperD))
 5134                return true;
 135        }
 20136        return false;
 137    }
 138
 139    internal bool TryGetPrimitiveWide(WideAxis3 start, WideAxis3 delta, int primitive,
 140        out Signed832 a, out Signed832 b, out Signed832 c,
 141        out Signed320 lowerN, out Signed320 lowerD, out Signed320 upperN, out Signed320 upperD)
 142    {
 11733143        if (!ShapeFrame.HasExactScale)
 144        {
 1702145            bool found = TryGetPrimitive(start, delta, primitive, out Signed576 sa, out Signed576 sb, out Signed576 sc,
 1702146                out lowerN, out lowerD, out upperN, out upperD);
 5106147            a = Signed832.ExtendValue(sa); b = Signed832.ExtendValue(sb); c = Signed832.ExtendValue(sc);
 1702148            return found;
 149        }
 10031150        lowerN = default;
 10031151        lowerD = upperN = upperD = Signed320.One;
 10031152        if (primitive == 0 && Length != Fixed64.Zero)
 153        {
 3412154            a = b = c = default;
 3412155            if (!TryGetCenteredAxisInterval(start.Y, delta.Y, ShapeFrame.Cap,
 3412156                    out lowerN, out lowerD, out upperN, out upperD))
 1002157                return false;
 2410158            start = new WideAxis3(start.X, default, start.Z);
 2410159            delta = new WideAxis3(delta.X, default, delta.Z);
 160        }
 161        else
 162        {
 6619163            Signed320 cap = primitive == 1 ? WideArithmetic.Negate(ShapeFrame.Cap) : ShapeFrame.Cap;
 6619164            start = new WideAxis3(start.X, WideArithmetic.SubtractSigned320(start.Y, cap), start.Z);
 165        }
 18058166        a = DotWide(delta, delta); b = DotWide(start, delta);
 9029167        c = WideArithmetic.SubtractSigned832(DotWide(start, start), _wideRadiusSquared);
 9029168        return true;
 169    }
 170
 171    /// <summary>Retains the first closed section parameter in the input segment's order.</summary>
 172    internal bool TryGetFirstSegmentParameter(FixedSegment segment,
 173        ContactQuadratic numerator, ContactQuadratic denominator, Span<ulong> root)
 174    {
 30175        if (ShapeFrame.HasExactScale)
 7176            return TryGetFirstWideSegmentParameter(segment, numerator, denominator, root);
 69177        numerator.Clear(); denominator.Clear(); root.Clear();
 46178        WideAxis3 start = Transform(segment.Start), delta = Difference(Transform(segment.End), start);
 23179        Span<ulong> values = stackalloc ulong[10 * FiniteSectionPoint.Words];
 23180        Span<int> signs = stackalloc int[10];
 23181        Span<ulong> candidateRoot = stackalloc ulong[FiniteSectionPoint.RootWords];
 23182        ContactQuadratic qa = ContactQuadratic.At(values, signs, 0, FiniteSectionPoint.Words);
 23183        ContactQuadratic qb = ContactQuadratic.At(values, signs, 1, FiniteSectionPoint.Words);
 23184        ContactQuadratic qc = ContactQuadratic.At(values, signs, 2, FiniteSectionPoint.Words);
 23185        ContactQuadratic n = ContactQuadratic.At(values, signs, 3, FiniteSectionPoint.Words);
 23186        ContactQuadratic d = ContactQuadratic.At(values, signs, 4, FiniteSectionPoint.Words);
 23187        bool found = false;
 168188        for (int primitive = 0; primitive < (Length == Fixed64.Zero ? 1 : 3); primitive++)
 189        {
 61190            if (!TryGetPrimitive(start, delta, primitive, out Signed576 a, out Signed576 b, out Signed576 c,
 61191                    out Signed320 lowerN, out Signed320 lowerD, out Signed320 upperN, out Signed320 upperD)
 61192                || !IntersectsQuadratic(a, b, c, lowerN, lowerD, upperN, upperD)) continue;
 63193            n.Clear(); d.Clear(); candidateRoot.Clear();
 21194            GetFirstQuadraticParameter(a, b, c, lowerN, lowerD, qa, qb, qc, n, d, candidateRoot);
 21195            if (!found || ContactQuadratic.CompareRatios(n, d, candidateRoot, numerator, denominator, root) < 0)
 196            {
 60197                n.CopyTo(numerator); d.CopyTo(denominator); candidateRoot.CopyTo(root); found = true;
 198            }
 199        }
 23200        return found;
 201    }
 202
 203    private bool TryGetFirstWideSegmentParameter(FixedSegment segment,
 204        ContactQuadratic numerator, ContactQuadratic denominator, Span<ulong> root)
 205    {
 21206        numerator.Clear(); denominator.Clear(); root.Clear();
 14207        WideAxis3 start = Transform(segment.Start), delta = Difference(Transform(segment.End), start);
 7208        int words = numerator.FieldWords;
 7209        Span<ulong> values = stackalloc ulong[10 * words];
 7210        Span<int> signs = stackalloc int[10];
 7211        Span<ulong> candidateRoot = stackalloc ulong[root.Length];
 7212        ContactQuadratic qa = ContactQuadratic.At(values, signs, 0, words);
 7213        ContactQuadratic qb = ContactQuadratic.At(values, signs, 1, words);
 7214        ContactQuadratic qc = ContactQuadratic.At(values, signs, 2, words);
 7215        ContactQuadratic n = ContactQuadratic.At(values, signs, 3, words);
 7216        ContactQuadratic d = ContactQuadratic.At(values, signs, 4, words);
 7217        bool found = false;
 44218        for (int primitive = 0; primitive < (Length == Fixed64.Zero ? 1 : 3); primitive++)
 219        {
 15220            if (!TryGetPrimitiveWide(start, delta, primitive, out Signed832 a, out Signed832 b, out Signed832 c,
 15221                    out Signed320 ln, out Signed320 ld, out Signed320 un, out Signed320 ud)
 15222                || !IntersectsQuadratic(a, b, c, ln, ld, un, ud))
 223                continue;
 21224            n.Clear(); d.Clear(); candidateRoot.Clear();
 7225            if (WideFiniteConeIntersection.GetPolynomialSignAtRationalParameter(a, b, c, ln, ld) <= 0)
 226            {
 8227                n.Set(Signed576.ExtendValue(ln)); d.Set(Signed576.ExtendValue(ld));
 228            }
 229            else
 230            {
 9231                qa.Set(a); qb.Set(b); qc.Set(c);
 3232                bool retained = ContactQuadratic.TryGetParameter(qa, qb, qc, -1, candidateRoot, n, d);
 5233                if (!retained) retained = ContactQuadratic.TryGetParameter(qa, qb, qc, 1, candidateRoot, n, d);
 234                System.Diagnostics.Debug.Assert(retained);
 235            }
 7236            if (!found || ContactQuadratic.CompareRatios(n, d, candidateRoot, numerator, denominator, root) < 0)
 237            {
 12238                n.CopyTo(numerator); d.CopyTo(denominator); candidateRoot.CopyTo(root); found = true;
 239            }
 240        }
 7241        return found;
 242    }
 243
 244    internal bool TryGetPrimitive(WideAxis3 start, WideAxis3 delta, int primitive,
 245        out Signed576 a, out Signed576 b, out Signed576 c,
 246        out Signed320 lowerN, out Signed320 lowerD, out Signed320 upperN, out Signed320 upperD)
 247    {
 2180248        lowerN = default;
 2180249        lowerD = upperN = upperD = Signed320.ExtendValue(Signed192.Signed(1));
 250        // The capsule is exactly a finite cylinder plus both full endpoint
 251        // balls. Full balls avoid hemisphere clipping without changing the
 252        // union, and the zero-core capsule needs only one ball.
 2180253        bool body = primitive == 0 && Length != Fixed64.Zero;
 2180254        if (body)
 255        {
 667256            a = b = c = default;
 1042257            if (!TryGetCenteredAxisInterval(start.Y, delta.Y, ShapeFrame.Cap, out lowerN, out lowerD, out upperN, out up
 292258            start = new WideAxis3(start.X, default, start.Z);
 292259            delta = new WideAxis3(delta.X, default, delta.Z);
 260        }
 261        else
 262        {
 1513263            Signed320 cap = primitive == 1 ? WideArithmetic.Negate(ShapeFrame.Cap) : ShapeFrame.Cap;
 1513264            start = new WideAxis3(start.X, WideArithmetic.SubtractSigned320(start.Y, cap), start.Z);
 265        }
 266        // Doubled rigid coordinates and differences are below 198 bits;
 267        // squared coefficients fit 400 bits and discriminants 801 bits.
 3610268        a = Dot(delta, delta); b = Dot(start, delta);
 1805269        c = WideArithmetic.SubtractSigned576(Dot(start, start), _radiusSquared);
 1805270        return true;
 271    }
 272
 273    internal static bool TryGetCenteredAxisInterval(Signed320 start, Signed320 velocity, Signed320 cap,
 274        out Signed320 lowerN, out Signed320 lowerD, out Signed320 upperN, out Signed320 upperD)
 275    {
 22586276        lowerN = default;
 22586277        lowerD = upperN = upperD = Signed320.ExtendValue(Signed192.Signed(1));
 22586278        if (velocity.IsZero)
 9693279            return WideArithmetic.AddSigned320(start, cap).Sign >= 0
 9693280                && WideArithmetic.SubtractSigned320(start, cap).Sign <= 0;
 12893281        Signed320 first = WideArithmetic.SubtractSigned320(WideArithmetic.Negate(cap), start);
 12893282        Signed320 second = WideArithmetic.SubtractSigned320(cap, start);
 12893283        Signed320 divisor = velocity;
 12893284        if (velocity.Sign < 0)
 285        {
 4833286            (first, second) = (WideArithmetic.Negate(second), WideArithmetic.Negate(first));
 4833287            divisor = WideArithmetic.Negate(divisor);
 288        }
 17985289        if (second.Sign < 0 || WideArithmetic.SubtractSigned320(first, divisor).Sign > 0) return false;
 14863290        if (first.Sign > 0) { lowerN = first; lowerD = divisor; }
 16473291        if (WideArithmetic.SubtractSigned320(second, divisor).Sign < 0) { upperN = second; upperD = divisor; }
 7801292        return true;
 293    }
 294
 295    internal static bool IntersectsQuadratic(Signed576 a, Signed576 b, Signed576 c,
 296        Signed320 lowerN, Signed320 lowerD, Signed320 upperN, Signed320 upperD)
 297    {
 2286298        if (PolynomialSign(a, b, c, lowerN, lowerD) <= 0 || PolynomialSign(a, b, c, upperN, upperD) <= 0) return true;
 2323299        if (a.Sign == 0 || b.Sign >= 0) return false;
 1605300        Signed576 vertex = WideArithmetic.SubtractSigned576(default, b);
 2859301        if (CompareProducts(vertex, lowerD, a, lowerN) < 0 || CompareProducts(vertex, upperD, a, upperN) > 0) return fal
 302        System.Diagnostics.Debug.Assert(c.Sign > 0);
 351303        return WideArithmetic.CompareNonNegativeProducts(Signed832.ExtendValue(b), Signed832.ExtendValue(b),
 351304            Signed832.ExtendValue(a), Signed832.ExtendValue(c)) >= 0;
 305    }
 306
 307    internal static bool IntersectsQuadratic(Signed832 a, Signed832 b, Signed832 c,
 308        Signed320 lowerN, Signed320 lowerD, Signed320 upperN, Signed320 upperD)
 309    {
 3843310        if (WideFiniteConeIntersection.GetPolynomialSignAtRationalParameter(a, b, c, lowerN, lowerD) <= 0
 3843311            || WideFiniteConeIntersection.GetPolynomialSignAtRationalParameter(a, b, c, upperN, upperD) <= 0)
 836312            return true;
 3007313        if (a.Sign <= 0 || b.Sign >= 0)
 1252314            return false;
 1755315        Signed832 numerator = WideArithmetic.SubtractSigned832(default, b);
 1755316        if (WideArithmetic.CompareNonNegativeProducts(numerator, Signed832.ExtendValue(Signed576.ExtendValue(lowerD)),
 1755317                a, Signed832.ExtendValue(Signed576.ExtendValue(lowerN))) < 0
 1755318            || WideArithmetic.CompareNonNegativeProducts(numerator, Signed832.ExtendValue(Signed576.ExtendValue(upperD))
 1755319                a, Signed832.ExtendValue(Signed576.ExtendValue(upperN))) > 0)
 1120320            return false;
 635321        return WideArithmetic.CompareNonNegativeProducts(b, b, a, c) >= 0;
 322    }
 323
 324    internal static bool IntersectsQuadratic(Signed832 a, Signed832 b, Signed832 c,
 325        Signed832 lowerN, Signed832 lowerD, Signed832 upperN, Signed832 upperD)
 326    {
 141327        if (WideFiniteConeIntersection.GetPolynomialSignAtRationalParameter(a, b, c, lowerN, lowerD) <= 0
 141328            || WideFiniteConeIntersection.GetPolynomialSignAtRationalParameter(a, b, c, upperN, upperD) <= 0)
 39329            return true;
 114330        if (a.Sign <= 0 || b.Sign >= 0) return false;
 90331        Signed832 numerator = WideArithmetic.SubtractSigned832(default, b);
 90332        if (WideArithmetic.CompareNonNegativeProducts(numerator, lowerD, a, lowerN) < 0
 90333            || WideArithmetic.CompareNonNegativeProducts(numerator, upperD, a, upperN) > 0)
 65334            return false;
 25335        return WideArithmetic.CompareNonNegativeProducts(b, b, a, c) >= 0;
 336    }
 337
 338    /// <summary>Intersects closed shape bounds with an exact source subsegment before quadratic admission.</summary>
 339    internal static bool IntersectsQuadratic(Signed832 a, Signed832 b, Signed832 c,
 340        Signed320 lowerN, Signed320 lowerD, Signed320 upperN, Signed320 upperD, in RationalSegmentInterval clip)
 341    {
 126342        if (!clip.IsClipped) return IntersectsQuadratic(a, b, c, lowerN, lowerD, upperN, upperD);
 168343        Signed832 ln = Signed832.ExtendValue(lowerN), ld = Signed832.ExtendValue(lowerD),
 168344            un = Signed832.ExtendValue(upperN), ud = Signed832.ExtendValue(upperD);
 84345        if (RationalSegmentInterval.CompareParameters(ln, ld, clip.WideLowerNumerator, clip.WideLowerDenominator) < 0)
 86346        { ln = clip.WideLowerNumerator; ld = clip.WideLowerDenominator; }
 84347        if (RationalSegmentInterval.CompareParameters(un, ud, clip.WideUpperNumerator, clip.WideUpperDenominator) > 0)
 130348        { un = clip.WideUpperNumerator; ud = clip.WideUpperDenominator; }
 84349        return RationalSegmentInterval.CompareParameters(ln, ld, un, ud) <= 0
 84350            && IntersectsQuadratic(a, b, c, ln, ld, un, ud);
 351    }
 352
 353    /// <summary>Tests a rational borrowed quadratic on a closed clipped segment.</summary>
 354    internal static bool IntersectsQuadratic(scoped ContactQuadratic a, scoped ContactQuadratic b,
 355        scoped ContactQuadratic c, Signed320 lowerN, Signed320 lowerD, Signed320 upperN, Signed320 upperD)
 356    {
 2636357        Signed832 ln = Signed832.ExtendValue(Signed576.ExtendValue(lowerN));
 2636358        Signed832 ld = Signed832.ExtendValue(Signed576.ExtendValue(lowerD));
 2636359        Signed832 un = Signed832.ExtendValue(Signed576.ExtendValue(upperN));
 2636360        Signed832 ud = Signed832.ExtendValue(Signed576.ExtendValue(upperD));
 2636361        if (WideFiniteConeIntersection.GetBorrowedPolynomialSignAtRationalParameter(a, b, c, ln, ld) <= 0
 2636362            || WideFiniteConeIntersection.GetBorrowedPolynomialSignAtRationalParameter(a, b, c, un, ud) <= 0)
 13363            return true;
 4582364        if (a.Signs[0] <= 0 || b.Signs[0] >= 0) return false;
 365
 366        // Positive endpoints leave only an interior convex minimum. Preserve
 367        // both complete products, including the discriminant's subtraction bit.
 664368        int coefficientWords = Math.Max(a.FieldWords, Math.Max(b.FieldWords, c.FieldWords));
 664369        int words = Math.Max(2 * coefficientWords, coefficientWords + 5) + 1;
 664370        Span<ulong> storage = stackalloc ulong[4 * words];
 664371        Span<int> signs = stackalloc int[4];
 664372        ContactQuadratic left = ContactQuadratic.At(storage, signs, 0, words);
 664373        ContactQuadratic right = ContactQuadratic.At(storage, signs, 1, words);
 1328374        ContactQuadratic.Scale(b, ld, left); left.MultiplySign(-1);
 1328375        ContactQuadratic.Scale(a, ln, right); left.Add(right, -1);
 665376        if (left.Signs[0] < 0) return false;
 1326377        ContactQuadratic.Scale(b, ud, left); left.MultiplySign(-1);
 1326378        ContactQuadratic.Scale(a, un, right); left.Add(right, -1);
 1223379        if (left.Signs[0] > 0) return false;
 103380        ContactQuadratic.Multiply(b, b, ReadOnlySpan<ulong>.Empty, left);
 206381        ContactQuadratic.Multiply(a, c, ReadOnlySpan<ulong>.Empty, right); left.Add(right, -1);
 103382        return left.Signs[0] >= 0;
 383    }
 384
 27113385    private static Signed832 DotWide(WideAxis3 left, WideAxis3 right) => WideArithmetic.AddSigned832(
 27113386        WideArithmetic.AddSigned832(Product(left.X, right.X), Product(left.Y, right.Y)), Product(left.Z, right.Z));
 387
 388    private static Signed832 Product(Signed320 first, Signed320 second) =>
 81519389        WideArithmetic.MultiplySigned576ToSigned832(Signed576.ExtendValue(first), second);
 390
 391    private static int PolynomialSign(Signed576 a, Signed576 b, Signed576 c, Signed320 n, Signed320 d) =>
 4154392        WideFiniteConeIntersection.GetPolynomialSignAtRationalParameter(Signed832.ExtendValue(a),
 4154393            Signed832.ExtendValue(b), Signed832.ExtendValue(c), n, d);
 394
 395    /// <summary>Retains the first point of an already admitted convex quadratic interval.</summary>
 396    internal static void GetFirstQuadraticParameter(Signed576 a, Signed576 b, Signed576 c,
 397        Signed320 lowerN, Signed320 lowerD, ContactQuadratic qa, ContactQuadratic qb, ContactQuadratic qc,
 398        ContactQuadratic numerator, ContactQuadratic denominator, Span<ulong> root)
 399    {
 21400        if (PolynomialSign(a, b, c, lowerN, lowerD) <= 0)
 401        {
 18402            numerator.Set(Signed576.ExtendValue(lowerN)); denominator.Set(Signed576.ExtendValue(lowerD));
 9403            return;
 404        }
 36405        qa.Set(a); qb.Set(b); qc.Set(c);
 406        // The lower root starts the admitted interval. Repeated roots use
 407        // the sole +1 branch and remain closed point intersections.
 12408        bool retained = ContactQuadratic.TryGetParameter(qa, qb, qc, -1, root, numerator, denominator);
 14409        if (!retained) retained = ContactQuadratic.TryGetParameter(qa, qb, qc, 1, root, numerator, denominator);
 410        System.Diagnostics.Debug.Assert(retained);
 12411    }
 412
 413    private static int CompareProducts(Signed576 left, Signed320 leftScale, Signed576 right, Signed320 rightScale) =>
 2849414        WideArithmetic.SubtractSigned832(WideArithmetic.MultiplySigned576ToSigned832(left, leftScale),
 2849415            WideArithmetic.MultiplySigned576ToSigned832(right, rightScale)).Sign;
 416
 417    private static Signed576 Dot(WideAxis3 left, WideAxis3 right) =>
 5511418        WideArithmetic.AddSigned576(WideArithmetic.AddSigned576(WideArithmetic.MultiplySigned320(left.X, right.X),
 5511419            WideArithmetic.MultiplySigned320(left.Y, right.Y)), WideArithmetic.MultiplySigned320(left.Z, right.Z));
 420
 421    private static WideAxis3 Difference(WideAxis3 end, WideAxis3 start) =>
 305422        new(WideArithmetic.SubtractSigned320(end.X, start.X), WideArithmetic.SubtractSigned320(end.Y, start.Y),
 305423            WideArithmetic.SubtractSigned320(end.Z, start.Z));
 424}

Methods/Properties

.ctor(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed320)
.ctor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
.ctor(FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
Transform(FixedMathSharp.Vector3d)
ContainsPoint(FixedMathSharp.Vector3d)
ContainsTransformedPoint(FixedMathSharp.Geometry.WideAxis3)
IntersectsSegment(FixedMathSharp.Geometry.FixedSegment)
IntersectsSegment(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.RationalSegmentInterval&)
IntersectsWideSegment(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.RationalSegmentInterval&)
TryGetPrimitiveWide(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3,System.Int32,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
TryGetFirstSegmentParameter(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.Span`1<System.UInt64>)
TryGetFirstWideSegmentParameter(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.Span`1<System.UInt64>)
TryGetPrimitive(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3,System.Int32,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
TryGetCenteredAxisInterval(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
IntersectsQuadratic(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
IntersectsQuadratic(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
IntersectsQuadratic(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832)
IntersectsQuadratic(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Geometry.RationalSegmentInterval&)
IntersectsQuadratic(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
DotWide(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3)
Product(FixedMathSharp.Signed320,FixedMathSharp.Signed320)
PolynomialSign(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetFirstQuadraticParameter(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.Span`1<System.UInt64>)
CompareProducts(FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed320)
Dot(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3)
Difference(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3)