< Summary

Information
Class: FixedMathSharp.Geometry.CylinderPairGeometry
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/CylinderPairGeometry.cs
Line coverage
100%
Covered lines: 83
Uncovered lines: 0
Coverable lines: 83
Total lines: 143
Line coverage: 100%
Branch coverage
100%
Covered branches: 10
Total branches: 10
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%66100%
GetCapOffset(...)100%11100%
WriteInvariants(...)100%11100%
Primitive(...)100%11100%
Scale(...)100%11100%
Offset(...)100%44100%
Import(...)100%11100%
Write(...)100%11100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/CylinderPairGeometry.cs

#LineLine coverage
 1//=======================================================================
 2// CylinderPairGeometry.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 cylinder-pair geometry in the first authored rotation frame. Positions
 14/// and radii use one reduced integer scale per raw coordinate; axis directions
 15/// and the perpendicular plane basis are independently primitive.
 16/// </summary>
 17internal readonly struct CylinderPairGeometry
 18{
 19    internal readonly WideRationalBasis3d WorldBasis;
 20    internal readonly WideAxis3 FirstAxis;
 21    internal readonly WideAxis3 SecondAxis;
 22    internal readonly WideAxis3 PlaneU;
 23    internal readonly WideAxis3 PlaneW;
 24    internal readonly WideAxis3 FirstHalf;
 25    internal readonly WideAxis3 SecondHalf;
 26    internal readonly WideAxis3 CenterDifference;
 27    internal readonly Signed320 FirstRadius;
 28    internal readonly Signed320 SecondRadius;
 29    internal readonly Signed192 RawScale;
 30    internal readonly int ValueShift;
 31
 32    internal CylinderPairGeometry(Vector3d firstCenter, FixedQuaternion firstRotation,
 33        Vector3d firstLocalAxis, Signed192 firstLength, Fixed64 firstRadius,
 34        Vector3d secondCenter, FixedQuaternion secondRotation, Vector3d secondLocalAxis,
 35        Signed192 secondLength, Fixed64 secondRadius)
 36    {
 48937        WorldBasis = new WideRationalBasis3d(firstRotation);
 48938        var secondBasis = new WideRationalBasis3d(secondRotation);
 48939        WideRationalBasis3d relative = WideRationalBasis3d.CreateRelative(WorldBasis, secondBasis);
 48940        var first = new WideAxis3(Signed320.ExtendValue(Signed192.Raw(firstLocalAxis.X)),
 48941            Signed320.ExtendValue(Signed192.Raw(firstLocalAxis.Y)),
 48942            Signed320.ExtendValue(Signed192.Raw(firstLocalAxis.Z)));
 48943        WideAxis3 second = WideRigidProjection.TransformLocalAxis(relative,
 48944            Signed192.Raw(secondLocalAxis.X), Signed192.Raw(secondLocalAxis.Y), Signed192.Raw(secondLocalAxis.Z));
 48945        FirstAxis = Primitive(first);
 48946        SecondAxis = Primitive(second);
 48947        PlaneU = FirstAxis.X.IsZero && FirstAxis.Y.IsZero
 48948            ? new WideAxis3(Signed320.ExtendValue(Signed192.Signed(1)), default, default)
 48949            : Primitive(new WideAxis3(FirstAxis.Y, WideArithmetic.Negate(FirstAxis.X), default));
 48950        PlaneW = Primitive(WideAxis3.Cross(FirstAxis, PlaneU));
 51
 48952        Signed192 twiceOne = Signed192.Raw(Fixed64.Two);
 48953        Signed320 rawScale = WideArithmetic.MultiplySigned192(relative.Denominator, twiceOne);
 48954        WideAxis3 firstHalf = Scale(first,
 48955            WideArithmetic.MultiplySigned192(relative.Denominator, firstLength));
 48956        WideAxis3 secondHalf = Scale(second, Signed320.ExtendValue(secondLength));
 48957        WideOrientedBox.GetRelativeLocalPointNumerators(secondCenter, firstCenter, WorldBasis,
 48958            out Signed192 dx, out Signed192 dy, out Signed192 dz);
 48959        WideAxis3 difference = Scale(new WideAxis3(Signed320.ExtendValue(dx), Signed320.ExtendValue(dy),
 48960            Signed320.ExtendValue(dz)), WideArithmetic.MultiplySigned192(secondBasis.Denominator, twiceOne));
 48961        Signed320 radiusA = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(rawScale, Signed192.Raw(firstRadius))
 48962        Signed320 radiusB = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(rawScale, Signed192.Raw(secondRadius)
 48963        Span<Signed320> coordinates = stackalloc Signed320[12]
 48964        {
 48965            rawScale, firstHalf.X, firstHalf.Y, firstHalf.Z, secondHalf.X, secondHalf.Y, secondHalf.Z,
 48966            difference.X, difference.Y, difference.Z, radiusA, radiusB
 48967        };
 48968        WideArithmetic.ReduceCommonScale(coordinates);
 48969        RawScale = Signed192.NarrowProven(coordinates[0]);
 48970        FirstHalf = new WideAxis3(coordinates[1], coordinates[2], coordinates[3]);
 48971        SecondHalf = new WideAxis3(coordinates[4], coordinates[5], coordinates[6]);
 48972        CenterDifference = new WideAxis3(coordinates[7], coordinates[8], coordinates[9]);
 48973        FirstRadius = coordinates[10];
 48974        SecondRadius = coordinates[11];
 48975        int bits = 0;
 48976        Span<ulong> magnitude = stackalloc ulong[5];
 1173677        for (int index = 1; index < coordinates.Length; index++)
 78        {
 537979            Import(coordinates[index], magnitude);
 537980            bits = Math.Max(bits, WideArithmetic.GetMagnitudeBitLength(magnitude));
 81        }
 82        // Each residual is c+p+q. The component-wise bound gives magnitude
 83        // <2^(bits+4); the authored full-domain bound independently gives
 84        // magnitude <2^230. Use the tighter squared-value upper bound.
 48985        ValueShift = Math.Min(460, 2 * (bits + 4));
 48986    }
 87
 1301688    internal WideAxis3 GetCapOffset(int firstSign, int secondSign) => new(
 1301689        Offset(FirstHalf.X, SecondHalf.X, CenterDifference.X, firstSign, secondSign),
 1301690        Offset(FirstHalf.Y, SecondHalf.Y, CenterDifference.Y, firstSign, secondSign),
 1301691        Offset(FirstHalf.Z, SecondHalf.Z, CenterDifference.Z, firstSign, secondSign));
 92
 93    internal void WriteInvariants(int firstSign, int secondSign,
 94        Span<ulong> values, Span<sbyte> signs, int words)
 95    {
 768496        WideAxis3 c = GetCapOffset(firstSign, secondSign);
 768497        Write(PlaneU.SquaredLength, values, signs, 0, words);
 768498        Write(PlaneW.SquaredLength, values, signs, 1, words);
 768499        Write(SecondAxis.SquaredLength, values, signs, 2, words);
 7684100        Write(WideArithmetic.MultiplySigned320(FirstRadius, FirstRadius), values, signs, 3, words);
 7684101        Write(WideArithmetic.MultiplySigned320(SecondRadius, SecondRadius), values, signs, 4, words);
 7684102        Write(c.SquaredLength, values, signs, 5, words);
 7684103        Write(WideAxis3.Dot(c, PlaneU), values, signs, 6, words);
 7684104        Write(WideAxis3.Dot(c, PlaneW), values, signs, 7, words);
 7684105        Write(WideAxis3.Dot(SecondAxis, PlaneU), values, signs, 8, words);
 7684106        Write(WideAxis3.Dot(SecondAxis, PlaneW), values, signs, 9, words);
 7684107        Write(WideAxis3.Dot(SecondAxis, c), values, signs, 10, words);
 7684108    }
 109
 110    private static WideAxis3 Primitive(WideAxis3 axis)
 111    {
 1863112        Signed192 x = Signed192.NarrowProven(axis.X);
 1863113        Signed192 y = Signed192.NarrowProven(axis.Y);
 1863114        Signed192 z = Signed192.NarrowProven(axis.Z);
 1863115        Signed192 gcd = WideArithmetic.GetGreatestCommonDivisor(
 1863116            WideArithmetic.GetGreatestCommonDivisor(x, y), z);
 1863117        return new WideAxis3(Signed320.ExtendValue(WideArithmetic.DivideExactSigned192(x, gcd)),
 1863118            Signed320.ExtendValue(WideArithmetic.DivideExactSigned192(y, gcd)),
 1863119            Signed320.ExtendValue(WideArithmetic.DivideExactSigned192(z, gcd)));
 120    }
 121
 1467122    private static WideAxis3 Scale(WideAxis3 axis, Signed320 scale) => new(
 1467123        Signed320.NarrowValue(WideArithmetic.MultiplySigned320(axis.X, scale)),
 1467124        Signed320.NarrowValue(WideArithmetic.MultiplySigned320(axis.Y, scale)),
 1467125        Signed320.NarrowValue(WideArithmetic.MultiplySigned320(axis.Z, scale)));
 126
 127    private static Signed320 Offset(Signed320 first, Signed320 second, Signed320 center,
 39048128        int firstSign, int secondSign) => WideArithmetic.SubtractSigned320(
 39048129            WideArithmetic.AddSigned320(firstSign > 0 ? first : WideArithmetic.Negate(first),
 39048130                secondSign > 0 ? second : WideArithmetic.Negate(second)), center);
 131
 132    private static void Import(Signed320 value, Span<ulong> magnitude) =>
 5379133        WideArithmetic.GetMagnitude(value, out magnitude[4], out magnitude[3], out magnitude[2],
 5379134            out magnitude[1], out magnitude[0]);
 135
 136    private static void Write(Signed576 value, Span<ulong> values, Span<sbyte> signs, int index, int words)
 137    {
 84524138        Span<ulong> destination = values.Slice(index * words, words);
 84524139        destination.Clear();
 84524140        WideArithmetic.GetMagnitude(value, destination[..9]);
 84524141        signs[index] = (sbyte)value.Sign;
 84524142    }
 143}