< Summary

Information
Class: Gravitas.InertiaTensorMath
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Core/3D/InertiaTensorMath.cs
Line coverage
100%
Covered lines: 74
Uncovered lines: 0
Coverable lines: 74
Total lines: 128
Line coverage: 100%
Branch coverage
100%
Covered branches: 36
Total branches: 36
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
IsDiagonal(...)100%1010100%
InvertForSolver(...)100%88100%
AddParallelAxisTensor(...)100%44100%
SubtractParallelAxisTensor(...)100%44100%
RotateToFrame(...)100%22100%
InvertDiagonalForSolver(...)100%66100%
ClampNearZero(...)100%11100%
ClampNearZero(...)100%22100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Core/3D/InertiaTensorMath.cs

#LineLine coverage
 1//=======================================================================
 2// InertiaTensorMath.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using System.Runtime.CompilerServices;
 10
 11namespace Gravitas;
 12
 13/// <summary>
 14/// Deterministic helpers for 3D inertia tensors used by body mass properties
 15/// and solver effective mass calculations.
 16/// </summary>
 17internal static class InertiaTensorMath
 18{
 19    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 20    public static bool IsDiagonal(Fixed3x3 tensor) =>
 1018521        tensor.M12 == Fixed64.Zero
 1018522        && tensor.M13 == Fixed64.Zero
 1018523        && tensor.M21 == Fixed64.Zero
 1018524        && tensor.M23 == Fixed64.Zero
 1018525        && tensor.M31 == Fixed64.Zero
 1018526        && tensor.M32 == Fixed64.Zero;
 27
 28    public static Fixed3x3 InvertForSolver(Fixed3x3 tensor)
 29    {
 1021630        if (tensor == Fixed3x3.Zero)
 3131            return Fixed3x3.Zero;
 32
 1018533        if (IsDiagonal(tensor))
 1013034            return InvertDiagonalForSolver(tensor);
 35
 5536        if (!Fixed3x3.Invert(tensor, out Fixed3x3? inverse) || !inverse.HasValue)
 137            return Fixed3x3.Zero;
 38
 5439        return ClampNearZero(inverse.Value);
 40    }
 41
 42    public static Fixed3x3 AddParallelAxisTensor(Fixed3x3 tensor, Fixed64 mass, Vector3d offset)
 43    {
 18044        if (mass <= Fixed64.Zero || offset == Vector3d.Zero)
 16745            return tensor;
 46
 1347        Fixed64 xx = mass * ((offset.Y * offset.Y) + (offset.Z * offset.Z));
 1348        Fixed64 yy = mass * ((offset.X * offset.X) + (offset.Z * offset.Z));
 1349        Fixed64 zz = mass * ((offset.X * offset.X) + (offset.Y * offset.Y));
 1350        Fixed64 xy = mass * offset.X * offset.Y;
 1351        Fixed64 xz = mass * offset.X * offset.Z;
 1352        Fixed64 yz = mass * offset.Y * offset.Z;
 53
 1354        tensor.M11 += xx;
 1355        tensor.M22 += yy;
 1356        tensor.M33 += zz;
 1357        tensor.M12 -= xy;
 1358        tensor.M21 -= xy;
 1359        tensor.M13 -= xz;
 1360        tensor.M31 -= xz;
 1361        tensor.M23 -= yz;
 1362        tensor.M32 -= yz;
 1363        return ClampNearZero(tensor);
 64    }
 65
 66    public static Fixed3x3 SubtractParallelAxisTensor(Fixed3x3 tensor, Fixed64 mass, Vector3d offset)
 67    {
 16768        if (mass <= Fixed64.Zero || offset == Vector3d.Zero)
 16169            return tensor;
 70
 671        Fixed64 xx = mass * ((offset.Y * offset.Y) + (offset.Z * offset.Z));
 672        Fixed64 yy = mass * ((offset.X * offset.X) + (offset.Z * offset.Z));
 673        Fixed64 zz = mass * ((offset.X * offset.X) + (offset.Y * offset.Y));
 674        Fixed64 xy = mass * offset.X * offset.Y;
 675        Fixed64 xz = mass * offset.X * offset.Z;
 676        Fixed64 yz = mass * offset.Y * offset.Z;
 77
 678        tensor.M11 -= xx;
 679        tensor.M22 -= yy;
 680        tensor.M33 -= zz;
 681        tensor.M12 += xy;
 682        tensor.M21 += xy;
 683        tensor.M13 += xz;
 684        tensor.M31 += xz;
 685        tensor.M23 += yz;
 686        tensor.M32 += yz;
 687        return ClampNearZero(tensor);
 88    }
 89
 90    public static Fixed3x3 RotateToFrame(Fixed3x3 tensor, FixedQuaternion rotation)
 91    {
 18292        if (rotation == FixedQuaternion.Identity)
 15393            return tensor;
 94
 2995        Fixed3x3 rotationMatrix = rotation.ToMatrix3x3();
 2996        return ClampNearZero(rotationMatrix * tensor * rotationMatrix.Transpose());
 97    }
 98
 99    private static Fixed3x3 InvertDiagonalForSolver(Fixed3x3 tensor) =>
 10130100        new(
 10130101            tensor.M11 > Fixed64.Zero ? Fixed64.One / tensor.M11 : Fixed64.Zero,
 10130102            Fixed64.Zero,
 10130103            Fixed64.Zero,
 10130104            Fixed64.Zero,
 10130105            tensor.M22 > Fixed64.Zero ? Fixed64.One / tensor.M22 : Fixed64.Zero,
 10130106            Fixed64.Zero,
 10130107            Fixed64.Zero,
 10130108            Fixed64.Zero,
 10130109            tensor.M33 > Fixed64.Zero ? Fixed64.One / tensor.M33 : Fixed64.Zero);
 110
 111    private static Fixed3x3 ClampNearZero(Fixed3x3 tensor)
 112    {
 102113        tensor.M11 = ClampNearZero(tensor.M11);
 102114        tensor.M12 = ClampNearZero(tensor.M12);
 102115        tensor.M13 = ClampNearZero(tensor.M13);
 102116        tensor.M21 = ClampNearZero(tensor.M21);
 102117        tensor.M22 = ClampNearZero(tensor.M22);
 102118        tensor.M23 = ClampNearZero(tensor.M23);
 102119        tensor.M31 = ClampNearZero(tensor.M31);
 102120        tensor.M32 = ClampNearZero(tensor.M32);
 102121        tensor.M33 = ClampNearZero(tensor.M33);
 102122        return tensor;
 123    }
 124
 125    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 126    private static Fixed64 ClampNearZero(Fixed64 value) =>
 918127        value.Abs() <= Fixed64.Epsilon ? Fixed64.Zero : value;
 128}