< Summary

Information
Class: Gravitas.Colliders.MeshMassProperties
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/Mesh/MeshMassProperties.cs
Line coverage
100%
Covered lines: 81
Uncovered lines: 0
Coverable lines: 81
Total lines: 173
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%11100%
CalculateInertiaTensor(...)100%11100%
TryScale(...)100%44100%
TryRecoverCovariance(...)100%22100%
TryScaleCovariance(...)100%22100%
TryCreateInertiaFromCovariance(...)100%22100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/Mesh/MeshMassProperties.cs

#LineLine coverage
 1//=======================================================================
 2// MeshMassProperties.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 static Gravitas.Colliders.MeshCheckedMath;
 10
 11namespace Gravitas.Colliders;
 12
 13/// <summary>
 14/// Stores deterministic closed-volume mass properties for an immutable mesh topology.
 15/// </summary>
 16public readonly struct MeshMassProperties
 17{
 18    /// <summary>Creates deterministic closed-volume mass properties.</summary>
 19    public MeshMassProperties(
 20        Fixed64 volume,
 21        Vector3d centerOfMass,
 22        Vector3d inertiaReferencePoint,
 23        Fixed3x3 unitMassInertiaTensor)
 24    {
 18025        Volume = volume;
 18026        CenterOfMass = centerOfMass;
 18027        InertiaReferencePoint = inertiaReferencePoint;
 18028        UnitMassInertiaTensor = unitMassInertiaTensor;
 18029    }
 30
 31    /// <summary>
 32    /// Absolute solid volume in local mesh units.
 33    /// </summary>
 34    public Fixed64 Volume { get; }
 35
 36    /// <summary>
 37    /// Homogeneous center of mass in local mesh coordinates.
 38    /// </summary>
 39    public Vector3d CenterOfMass { get; }
 40
 41    /// <summary>
 42    /// Local reference point about which <see cref="UnitMassInertiaTensor"/> was computed.
 43    /// </summary>
 44    public Vector3d InertiaReferencePoint { get; }
 45
 46    /// <summary>
 47    /// Solid-volume inertia tensor for unit mass about <see cref="InertiaReferencePoint"/>.
 48    /// </summary>
 49    public Fixed3x3 UnitMassInertiaTensor { get; }
 50
 51    /// <summary>
 52    /// Calculates an inertia tensor for the supplied mass about a local point
 53    /// parallel to the mesh center-of-mass axes.
 54    /// </summary>
 55    public Fixed3x3 CalculateInertiaTensor(Fixed64 mass, Vector3d localReferencePoint)
 56    {
 4457        Fixed3x3 referenceTensor = UnitMassInertiaTensor * mass;
 4458        Fixed3x3 centerTensor = InertiaTensorMath.SubtractParallelAxisTensor(
 4459            referenceTensor,
 4460            mass,
 4461            InertiaReferencePoint - CenterOfMass);
 4462        return InertiaTensorMath.AddParallelAxisTensor(centerTensor, mass, localReferencePoint - CenterOfMass);
 63    }
 64
 65    internal MeshMassScaleResult TryScale(Vector3d scale, out MeshMassProperties properties)
 66    {
 6867        properties = default;
 6868        bool valid = TryMultiply(Volume, scale.X, out Fixed64 scaledVolume);
 6869        valid &= TryMultiply(scaledVolume, scale.Y, out scaledVolume);
 6870        valid &= TryMultiply(scaledVolume, scale.Z, out scaledVolume);
 6871        if (!valid)
 72        {
 573            return MeshMassScaleResult.NonRepresentableVolume;
 74        }
 75
 6376        valid = TrySubtract(InertiaReferencePoint, CenterOfMass, out Vector3d referenceOffset);
 6377        valid &= TryCreateParallelAxisTensor(referenceOffset, out Fixed3x3 referenceShift);
 6378        valid &= TrySubtract(UnitMassInertiaTensor, referenceShift, out Fixed3x3 centerTensor);
 6379        valid &= TryRecoverCovariance(centerTensor, out Fixed3x3 covariance);
 6380        valid &= TryScaleCovariance(covariance, scale, out Fixed3x3 scaledCovariance);
 6381        valid &= TryCreateInertiaFromCovariance(scaledCovariance, out Fixed3x3 scaledCenterTensor);
 6382        valid &= TryMultiply(CenterOfMass, scale, out Vector3d scaledCenter);
 6383        valid &= TryMultiply(InertiaReferencePoint, scale, out Vector3d scaledReference);
 6384        valid &= TrySubtract(scaledReference, scaledCenter, out Vector3d scaledReferenceOffset);
 6385        valid &= TryCreateParallelAxisTensor(scaledReferenceOffset, out Fixed3x3 scaledReferenceShift);
 6386        valid &= TryAdd(scaledCenterTensor, scaledReferenceShift, out Fixed3x3 scaledReferenceTensor);
 6387        if (!valid)
 88        {
 589            return MeshMassScaleResult.NonRepresentableMassProperties;
 90        }
 91
 5892        properties = new MeshMassProperties(
 5893            scaledVolume,
 5894            scaledCenter,
 5895            scaledReference,
 5896            scaledReferenceTensor);
 5897        return MeshMassScaleResult.Valid;
 98    }
 99
 100    private static bool TryRecoverCovariance(Fixed3x3 tensor, out Fixed3x3 covariance)
 101    {
 63102        covariance = default;
 63103        bool valid = TryAdd(tensor.M22, tensor.M33, out Fixed64 xSum);
 63104        valid &= TrySubtract(xSum, tensor.M11, out Fixed64 xTwice);
 63105        valid &= TryMultiply(xTwice, Fixed64.Half, out Fixed64 x);
 63106        valid &= TryAdd(tensor.M11, tensor.M33, out Fixed64 ySum);
 63107        valid &= TrySubtract(ySum, tensor.M22, out Fixed64 yTwice);
 63108        valid &= TryMultiply(yTwice, Fixed64.Half, out Fixed64 y);
 63109        valid &= TryAdd(tensor.M11, tensor.M22, out Fixed64 zSum);
 63110        valid &= TrySubtract(zSum, tensor.M33, out Fixed64 zTwice);
 63111        valid &= TryMultiply(zTwice, Fixed64.Half, out Fixed64 z);
 63112        valid &= TryNegate(tensor.M12, out Fixed64 xy);
 63113        valid &= TryNegate(tensor.M13, out Fixed64 xz);
 63114        valid &= TryNegate(tensor.M23, out Fixed64 yz);
 63115        if (!valid)
 116        {
 1117            return false;
 118        }
 119
 62120        covariance = new Fixed3x3(x, xy, xz, xy, y, yz, xz, yz, z);
 62121        return true;
 122    }
 123
 124    private static bool TryScaleCovariance(Fixed3x3 covariance, Vector3d scale, out Fixed3x3 scaled)
 125    {
 63126        scaled = default;
 63127        bool valid = TryMultiply(scale.X, scale.X, out Fixed64 xxScale);
 63128        valid &= TryMultiply(scale.Y, scale.Y, out Fixed64 yyScale);
 63129        valid &= TryMultiply(scale.Z, scale.Z, out Fixed64 zzScale);
 63130        valid &= TryMultiply(scale.X, scale.Y, out Fixed64 xyScale);
 63131        valid &= TryMultiply(scale.X, scale.Z, out Fixed64 xzScale);
 63132        valid &= TryMultiply(scale.Y, scale.Z, out Fixed64 yzScale);
 63133        valid &= TryMultiply(covariance.M11, xxScale, out Fixed64 xx);
 63134        valid &= TryMultiply(covariance.M22, yyScale, out Fixed64 yy);
 63135        valid &= TryMultiply(covariance.M33, zzScale, out Fixed64 zz);
 63136        valid &= TryMultiply(covariance.M12, xyScale, out Fixed64 xy);
 63137        valid &= TryMultiply(covariance.M13, xzScale, out Fixed64 xz);
 63138        valid &= TryMultiply(covariance.M23, yzScale, out Fixed64 yz);
 63139        if (!valid)
 140        {
 2141            return false;
 142        }
 143
 61144        scaled = new Fixed3x3(xx, xy, xz, xy, yy, yz, xz, yz, zz);
 61145        return true;
 146    }
 147
 148    private static bool TryCreateInertiaFromCovariance(Fixed3x3 covariance, out Fixed3x3 tensor)
 149    {
 63150        tensor = default;
 63151        bool valid = TryAdd(covariance.M22, covariance.M33, out Fixed64 xx);
 63152        valid &= TryAdd(covariance.M11, covariance.M33, out Fixed64 yy);
 63153        valid &= TryAdd(covariance.M11, covariance.M22, out Fixed64 zz);
 63154        valid &= TryNegate(covariance.M12, out Fixed64 xy);
 63155        valid &= TryNegate(covariance.M13, out Fixed64 xz);
 63156        valid &= TryNegate(covariance.M23, out Fixed64 yz);
 63157        if (!valid)
 158        {
 1159            return false;
 160        }
 161
 62162        tensor = new Fixed3x3(xx, xy, xz, xy, yy, yz, xz, yz, zz);
 62163        return true;
 164    }
 165
 166}
 167
 168internal enum MeshMassScaleResult
 169{
 170    Valid,
 171    NonRepresentableVolume,
 172    NonRepresentableMassProperties
 173}