< Summary

Information
Class: FixedMathSharp.Geometry.ConeFiniteSectionFrame
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/ConeFiniteSectionFrame.cs
Line coverage
100%
Covered lines: 97
Uncovered lines: 0
Coverable lines: 97
Total lines: 181
Line coverage: 100%
Branch coverage
100%
Covered branches: 62
Total branches: 62
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%11100%
.ctor(...)100%88100%
.ctor(...)100%1212100%
Transform(...)100%11100%
IntersectsTransformedSegment(...)100%1616100%
IntersectsTransformedSegment(...)100%44100%
ContainsTransformedPoint(...)100%66100%
QuadraticProductWide(...)100%22100%
IntersectsWideQuadratic(...)100%11100%
Product(...)100%11100%
QuadraticProduct(...)100%11100%
TryGetAxialInterval(...)100%1414100%
CompareProducts(...)100%11100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// ConeFiniteSectionFrame.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 finite-cone coordinates, closed admission, and rational segment clipping.</summary>
 13internal readonly struct ConeFiniteSectionFrame
 14{
 15    internal readonly CylinderPolytopeFrame ShapeFrame;
 16    internal readonly Fixed64 Height, Radius;
 17    internal readonly Signed320 FullHeight;
 18
 19    /// <summary>Exact cone-local identity chart supplied by a retained rational native source.</summary>
 20    internal ConeFiniteSectionFrame(Fixed64 height, Fixed64 radius, Signed320 coordinateDenominator)
 21    {
 6622        Height = height; Radius = radius;
 3323        ShapeFrame = new CylinderPolytopeFrame(height, radius, coordinateDenominator);
 3324        FullHeight = WideArithmetic.AddSigned320(ShapeFrame.Cap, ShapeFrame.Cap);
 3325    }
 26
 27    internal ConeFiniteSectionFrame(Vector3d origin, FixedQuaternion rotation,
 28        Vector3d coneCenter, FixedQuaternion coneRotation, Fixed64 height, Fixed64 radius)
 29    {
 282030        if (height <= Fixed64.Zero)
 231            throw new ArgumentOutOfRangeException(nameof(height));
 281832        if (radius < Fixed64.Zero)
 133            throw new ArgumentOutOfRangeException(nameof(radius));
 281734        if (!rotation.IsNormalized())
 135            throw new ArgumentException("The authored rotation must be normalized.", nameof(rotation));
 281636        if (!coneRotation.IsNormalized())
 137            throw new ArgumentException("The cone rotation must be normalized.", nameof(coneRotation));
 563038        Height = height; Radius = radius;
 281539        ShapeFrame = new CylinderPolytopeFrame(coneCenter, coneRotation, height, radius, origin, rotation);
 281540        FullHeight = WideArithmetic.AddSigned320(ShapeFrame.Cap, ShapeFrame.Cap);
 281541    }
 42
 43    internal ConeFiniteSectionFrame(in ScaledRigidFrame3d sourceFrame,
 44        Vector3d coneCenter, FixedQuaternion coneRotation, Fixed64 height, Fixed64 radius)
 45    {
 5646        if (sourceFrame.IsRigid)
 47        {
 448            this = new ConeFiniteSectionFrame(sourceFrame.RigidOrigin, sourceFrame.Rotation,
 449                coneCenter, coneRotation, height, radius);
 450            return;
 51        }
 5252        if (height <= Fixed64.Zero || height > (Fixed64)8192)
 253            throw new ArgumentOutOfRangeException(nameof(height));
 5054        if (radius < Fixed64.Zero || radius > (Fixed64)4096)
 255            throw new ArgumentOutOfRangeException(nameof(radius));
 4856        if (!coneRotation.IsNormalized())
 157            throw new ArgumentException("The cone rotation must be normalized.", nameof(coneRotation));
 9458        Height = height; Radius = radius;
 4759        ShapeFrame = new CylinderPolytopeFrame(sourceFrame, coneCenter, coneRotation,
 4760            Signed192.Raw(height), radius);
 4761        FullHeight = WideArithmetic.AddSigned320(ShapeFrame.Cap, ShapeFrame.Cap);
 4762    }
 63
 64    internal WideAxis3 Transform(Vector3d point)
 65    {
 5968566        WideAxis3 centered = ShapeFrame.Transform(point);
 5968567        return new WideAxis3(centered.X, WideArithmetic.SubtractSigned320(ShapeFrame.Cap, centered.Y), centered.Z);
 68    }
 69
 70    internal bool IntersectsTransformedSegment(WideAxis3 start, WideAxis3 end)
 71    {
 442972        WideAxis3 delta = new(WideArithmetic.SubtractSigned320(end.X, start.X),
 442973            WideArithmetic.SubtractSigned320(end.Y, start.Y), WideArithmetic.SubtractSigned320(end.Z, start.Z));
 442974        if (!TryGetAxialInterval(start.Y, delta.Y, out Signed320 lowerN, out Signed320 lowerD,
 442975                out Signed320 upperN, out Signed320 upperD))
 2376            return false;
 440677        if (ShapeFrame.HasExactScale)
 2678            return IntersectsWideQuadratic(start, delta, lowerN, lowerD, upperN, upperD);
 1314079        Signed576 a = QuadraticProduct(delta, delta), b = QuadraticProduct(start, delta), c = QuadraticProduct(start, st
 438080        if (WideFiniteConeIntersection.GetPolynomialSignAtRationalParameter(Signed832.ExtendValue(a), Signed832.ExtendVa
 438081            || WideFiniteConeIntersection.GetPolynomialSignAtRationalParameter(Signed832.ExtendValue(a), Signed832.Exten
 409082            return true;
 83        // A concave/linear quadratic attains its minimum at an endpoint.
 84        // The remaining convex quadratic has one stationary parameter -b/a.
 29085        if (a.Sign <= 0 || b.Sign >= 0)
 2086            return false;
 27087        Signed576 numerator = WideArithmetic.SubtractSigned576(default, b);
 27088        if (CompareProducts(numerator, lowerD, a, lowerN) < 0
 27089            || CompareProducts(numerator, upperD, a, upperN) > 0)
 2590            return false;
 91        // F decreases from t=0 to -b/a. The clipped lower endpoint lies
 92        // in that interval and has F>0, so F(0)=c must also be positive.
 93        System.Diagnostics.Debug.Assert(c.Sign > 0);
 24594        return WideArithmetic.CompareNonNegativeProducts(Signed832.ExtendValue(b), Signed832.ExtendValue(b),
 24595            Signed832.ExtendValue(a), Signed832.ExtendValue(c)) >= 0;
 96    }
 97
 98    /// <summary>Tests a pretransformed source subsegment, retaining its exact original parameter.</summary>
 99    internal bool IntersectsTransformedSegment(WideAxis3 start, WideAxis3 end, in RationalSegmentInterval clip)
 100    {
 36101        if (!clip.IsClipped) return IntersectsTransformedSegment(start, end);
 10102        WideAxis3 delta = new(WideArithmetic.SubtractSigned320(end.X, start.X),
 10103            WideArithmetic.SubtractSigned320(end.Y, start.Y), WideArithmetic.SubtractSigned320(end.Z, start.Z));
 10104        return TryGetAxialInterval(start.Y, delta.Y, out var ln, out var ld, out var un, out var ud)
 10105            && CapsuleFiniteSectionFrame.IntersectsQuadratic(QuadraticProductWide(delta, delta),
 10106                QuadraticProductWide(start, delta), QuadraticProductWide(start, start), ln, ld, un, ud, clip);
 107    }
 108
 1347109    internal bool ContainsTransformedPoint(WideAxis3 point) => point.Y.Sign >= 0
 1347110        && WideArithmetic.SubtractSigned320(point.Y, FullHeight).Sign <= 0
 1347111        && (ShapeFrame.HasExactScale ? QuadraticProductWide(point, point).Sign : QuadraticProduct(point, point).Sign) <=
 112
 113    internal Signed832 QuadraticProductWide(WideAxis3 left, WideAxis3 right)
 114    {
 12473115        if (!ShapeFrame.HasExactScale)
 12342116            return Signed832.ExtendValue(QuadraticProduct(left, right));
 117        // Admitted doubled coordinates are <306 bits and H/R raw <46.
 118        // Three squared terms and two extent factors stay below 707 bits.
 131119        Signed832 radial = WideArithmetic.AddSigned832(Product(left.X, right.X), Product(left.Z, right.Z));
 131120        Signed832 axial = Product(left.Y, right.Y);
 262121        Signed192 height = Signed192.Raw(Height), radius = Signed192.Raw(Radius);
 131122        return WideArithmetic.SubtractSigned832(
 131123            WideArithmetic.MultiplySigned832(WideArithmetic.MultiplySigned832(radial, height), height),
 131124            WideArithmetic.MultiplySigned832(WideArithmetic.MultiplySigned832(axial, radius), radius));
 125    }
 126
 127    private bool IntersectsWideQuadratic(WideAxis3 start, WideAxis3 delta,
 128        Signed320 lowerN, Signed320 lowerD, Signed320 upperN, Signed320 upperD)
 129    {
 52130        Signed832 a = QuadraticProductWide(delta, delta), b = QuadraticProductWide(start, delta),
 26131            c = QuadraticProductWide(start, start);
 26132        return CapsuleFiniteSectionFrame.IntersectsQuadratic(a, b, c, lowerN, lowerD, upperN, upperD);
 133    }
 134
 135    private static Signed832 Product(Signed320 first, Signed320 second) =>
 393136        WideArithmetic.MultiplySigned576ToSigned832(Signed576.ExtendValue(first), second);
 137
 138    internal Signed576 QuadraticProduct(WideAxis3 left, WideAxis3 right)
 139    {
 140        // Unreduced doubled rigid coordinates and axial differences <198
 141        // bits; raw H/R <63. Both products and their signed sum <528 bits.
 142        // Axial clipping excludes the opposite nappe before F<=0 admission.
 26758143        Signed576 radial = WideArithmetic.AddSigned576(WideArithmetic.MultiplySigned320(left.X, right.X),
 26758144            WideArithmetic.MultiplySigned320(left.Z, right.Z));
 26758145        Signed576 axial = WideArithmetic.MultiplySigned320(left.Y, right.Y);
 26758146        return WideArithmetic.SubtractSigned576(
 26758147            WideArithmetic.MultiplySigned576(radial, Signed192.Raw(Height), Signed192.Raw(Height)),
 26758148            WideArithmetic.MultiplySigned576(axial, Signed192.Raw(Radius), Signed192.Raw(Radius)));
 149    }
 150
 151    internal bool TryGetAxialInterval(Signed320 start, Signed320 velocity,
 152        out Signed320 lowerN, out Signed320 lowerD, out Signed320 upperN, out Signed320 upperD)
 153    {
 15566154        lowerN = default;
 15566155        lowerD = upperN = upperD = Signed320.ExtendValue(Signed192.Signed(1));
 15566156        if (velocity.IsZero)
 2812157            return start.Sign >= 0 && WideArithmetic.SubtractSigned320(start, FullHeight).Sign <= 0;
 12754158        Signed320 first = WideArithmetic.Negate(start);
 12754159        Signed320 second = WideArithmetic.SubtractSigned320(FullHeight, start);
 12754160        Signed320 divisor = velocity;
 12754161        if (velocity.Sign < 0)
 162        {
 5816163            (first, second) = (WideArithmetic.Negate(second), WideArithmetic.Negate(first));
 5816164            divisor = WideArithmetic.Negate(divisor);
 165        }
 12754166        if (second.Sign < 0 || WideArithmetic.SubtractSigned320(first, divisor).Sign > 0)
 10167            return false;
 30382168        if (first.Sign > 0) { lowerN = first; lowerD = divisor; }
 30526169        if (WideArithmetic.SubtractSigned320(second, divisor).Sign < 0) { upperN = second; upperD = divisor; }
 12744170        return true;
 171    }
 172
 173    private static int CompareProducts(Signed576 left, Signed320 leftScale, Signed576 right, Signed320 rightScale)
 174    {
 175        // <528+198 bits fits Signed832; endpoint polynomial evaluation uses
 176        // the existing wide owner's transient products rather than narrowing.
 529177        return WideArithmetic.SubtractSigned832(
 529178            WideArithmetic.MultiplySigned576ToSigned832(left, leftScale),
 529179            WideArithmetic.MultiplySigned576ToSigned832(right, rightScale)).Sign;
 180    }
 181}