< Summary

Information
Class: FixedMathSharp.Geometry.BoxCylinderGeometry
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/BoxCylinderGeometry.cs
Line coverage
100%
Covered lines: 60
Uncovered lines: 0
Coverable lines: 60
Total lines: 111
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
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%22100%
GetCapVertexOffset(...)100%11100%
GetComponent(...)100%44100%
Scale(...)100%11100%
Offset(...)100%66100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/BoxCylinderGeometry.cs

#LineLine coverage
 1//=======================================================================
 2// BoxCylinderGeometry.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>
 13/// Exact box-cylinder geometry in the box's authored rotation frame. Position,
 14/// extent, half-axis and radius coordinates share one reduced scale per raw
 15/// coordinate; the cylinder direction is independently primitive.
 16/// </summary>
 17internal readonly struct BoxCylinderGeometry
 18{
 19    internal readonly WideRationalBasis3d WorldBasis;
 20    internal readonly WideAxis3 Axis;
 21    internal readonly WideAxis3 Half;
 22    internal readonly WideAxis3 CenterDifference;
 23    internal readonly WideAxis3 HalfExtents;
 24    internal readonly Signed320 Radius;
 25    internal readonly Signed192 RawScale;
 26    internal readonly int ValueShift;
 27
 28    internal BoxCylinderGeometry(Vector3d boxCenter, FixedQuaternion boxRotation,
 29        Vector3d boxHalfExtents, Vector3d cylinderCenter, FixedQuaternion cylinderRotation,
 30        Vector3d localCylinderAxis, Fixed64 cylinderLength, Fixed64 cylinderRadius)
 31    {
 118332        WorldBasis = new WideRationalBasis3d(boxRotation);
 118333        var cylinderBasis = new WideRationalBasis3d(cylinderRotation);
 118334        WideRationalBasis3d relative = WideRationalBasis3d.CreateRelative(WorldBasis, cylinderBasis);
 118335        WideAxis3 axis = WideRigidProjection.TransformLocalAxis(relative,
 118336            Signed192.Raw(localCylinderAxis.X), Signed192.Raw(localCylinderAxis.Y),
 118337            Signed192.Raw(localCylinderAxis.Z));
 118338        Signed192 axisX = Signed192.NarrowProven(axis.X);
 118339        Signed192 axisY = Signed192.NarrowProven(axis.Y);
 118340        Signed192 axisZ = Signed192.NarrowProven(axis.Z);
 118341        Signed192 axisGcd = WideArithmetic.GetGreatestCommonDivisor(
 118342            WideArithmetic.GetGreatestCommonDivisor(axisX, axisY), axisZ);
 118343        Axis = new WideAxis3(
 118344            Signed320.ExtendValue(WideArithmetic.DivideExactSigned192(axisX, axisGcd)),
 118345            Signed320.ExtendValue(WideArithmetic.DivideExactSigned192(axisY, axisGcd)),
 118346            Signed320.ExtendValue(WideArithmetic.DivideExactSigned192(axisZ, axisGcd)));
 47
 118348        Signed192 twiceOne = Signed192.Raw(Fixed64.Two);
 118349        Signed320 rawScale = WideArithmetic.MultiplySigned192(relative.Denominator, twiceOne);
 118350        WideAxis3 half = Scale(axis, Signed320.ExtendValue(Signed192.Raw(cylinderLength)));
 118351        WideOrientedBox.GetRelativeLocalPointNumerators(cylinderCenter, boxCenter, WorldBasis,
 118352            out Signed192 dx, out Signed192 dy, out Signed192 dz);
 118353        WideAxis3 difference = Scale(new WideAxis3(Signed320.ExtendValue(dx),
 118354            Signed320.ExtendValue(dy), Signed320.ExtendValue(dz)),
 118355            WideArithmetic.MultiplySigned192(cylinderBasis.Denominator, twiceOne));
 118356        WideAxis3 extents = Scale(new WideAxis3(
 118357            Signed320.ExtendValue(Signed192.Raw(boxHalfExtents.X)),
 118358            Signed320.ExtendValue(Signed192.Raw(boxHalfExtents.Y)),
 118359            Signed320.ExtendValue(Signed192.Raw(boxHalfExtents.Z))), rawScale);
 118360        Signed320 radius = Signed320.NarrowValue(
 118361            WideArithmetic.MultiplySigned320(rawScale, Signed192.Raw(cylinderRadius)));
 62
 63        // Admitted quaternion denominators have at most 65 magnitude bits.
 64        // Relative basis entries are <2^130, the transformed axis <2^165,
 65        // and rawScale <2^163. Full raw-domain positions give difference
 66        // components <2^229; half-axis components are <2^228 and extents
 67        // and radius <2^226. Every product narrowed above therefore fits.
 118368        Span<Signed320> coordinates = stackalloc Signed320[11]
 118369        {
 118370            rawScale, half.X, half.Y, half.Z, difference.X, difference.Y, difference.Z,
 118371            extents.X, extents.Y, extents.Z, radius
 118372        };
 118373        WideArithmetic.ReduceCommonScale(coordinates);
 118374        RawScale = Signed192.NarrowProven(coordinates[0]);
 118375        Half = new WideAxis3(coordinates[1], coordinates[2], coordinates[3]);
 118376        CenterDifference = new WideAxis3(coordinates[4], coordinates[5], coordinates[6]);
 118377        HalfExtents = new WideAxis3(coordinates[7], coordinates[8], coordinates[9]);
 118378        Radius = coordinates[10];
 79
 118380        int bits = 0;
 118381        Span<ulong> magnitude = stackalloc ulong[5];
 2602682        for (int index = 1; index < coordinates.Length; index++)
 83        {
 1183084            WideArithmetic.GetMagnitude(coordinates[index], out magnitude[4], out magnitude[3],
 1183085                out magnitude[2], out magnitude[1], out magnitude[0]);
 1183086            bits = Math.Max(bits, WideArithmetic.GetMagnitudeBitLength(magnitude));
 87        }
 88        // Orthogonal projection cannot increase length. The residual formed
 89        // from vertex + cap half-axis - center and a radius contribution is
 90        // <2^(bits+4), and the authored bounds above also keep it <2^240.
 118391        ValueShift = Math.Min(480, 2 * (bits + 4));
 118392    }
 93
 6063594    internal WideAxis3 GetCapVertexOffset(int cornerBits, int capSign) => new(
 6063595        Offset(HalfExtents.X, Half.X, CenterDifference.X, (cornerBits & 1) != 0, capSign),
 6063596        Offset(HalfExtents.Y, Half.Y, CenterDifference.Y, (cornerBits & 2) != 0, capSign),
 6063597        Offset(HalfExtents.Z, Half.Z, CenterDifference.Z, (cornerBits & 4) != 0, capSign));
 98
 99    internal static Signed320 GetComponent(in WideAxis3 value, int index) =>
 414634100        index switch { 0 => value.X, 1 => value.Y, _ => value.Z };
 101
 3549102    private static WideAxis3 Scale(WideAxis3 value, Signed320 scale) => new(
 3549103        Signed320.NarrowValue(WideArithmetic.MultiplySigned320(value.X, scale)),
 3549104        Signed320.NarrowValue(WideArithmetic.MultiplySigned320(value.Y, scale)),
 3549105        Signed320.NarrowValue(WideArithmetic.MultiplySigned320(value.Z, scale)));
 106
 107    private static Signed320 Offset(Signed320 extent, Signed320 half, Signed320 center,
 181905108        bool positiveVertex, int capSign) => WideArithmetic.SubtractSigned320(
 181905109            WideArithmetic.AddSigned320(positiveVertex ? extent : WideArithmetic.Negate(extent),
 181905110                capSign == 0 ? default : capSign > 0 ? half : WideArithmetic.Negate(half)), center);
 111}