< Summary

Information
Class: Gravitas.Colliders.TriangleShellMassProperties
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/MassProperties/TriangleShellMassProperties.cs
Line coverage
100%
Covered lines: 309
Uncovered lines: 0
Coverable lines: 309
Total lines: 419
Line coverage: 100%
Branch coverage
100%
Covered branches: 14
Total branches: 14
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
TryCreateUniformShell(...)100%88100%
AddWeightedVertexSum(...)100%11100%
AddWeighted(...)100%11100%
GetProductSums(...)100%11100%
SquaredBarycentricSum(...)100%11100%
BarycentricCrossSum(...)100%11100%
TranslateSquaredMoment(...)100%11100%
TranslateProductMoment(...)100%11100%
GetTriangle(...)100%66100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/MassProperties/TriangleShellMassProperties.cs

#LineLine coverage
 1//=======================================================================
 2// TriangleShellMassProperties.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
 10using FixedMathSharp;
 11using FixedMathSharp.Geometry;
 12
 13namespace Gravitas.Colliders;
 14
 15/// <summary>
 16/// Owns wide uniform thin-shell integration for indexed triangle surfaces.
 17/// </summary>
 18internal static class TriangleShellMassProperties
 19{
 220    private static readonly Signed192 Three = Signed192.Signed(3);
 221    private static readonly Signed192 Six = Signed192.Signed(6);
 222    private static readonly Signed192 Twelve = Signed192.Signed(12);
 23
 24    internal static bool TryCreateUniformShell(
 25        ReadOnlySpan<Vector3d> vertices,
 26        ReadOnlySpan<int> triangleIndices,
 27        out ExactMassWeight surfaceWeight,
 28        out Vector3d centerOfMass,
 29        out Fixed3x3 unitMassInertiaTensor)
 30    {
 46231        if (triangleIndices.Length % FixedTriangle.VertexCount != 0)
 32        {
 133            throw new ArgumentException(
 134                "Triangle indices must contain complete index triplets.",
 135                nameof(triangleIndices));
 36        }
 37
 46138        Signed576 totalWeight = default;
 46139        Signed576 firstMomentX = default;
 46140        Signed576 firstMomentY = default;
 46141        Signed576 firstMomentZ = default;
 46142        Signed576 secondMomentX = default;
 46143        Signed576 secondMomentY = default;
 46144        Signed576 secondMomentZ = default;
 46145        Signed576 productMomentXY = default;
 46146        Signed576 productMomentXZ = default;
 46147        Signed576 productMomentYZ = default;
 32482248        for (int i = 0; i < triangleIndices.Length; i += FixedTriangle.VertexCount)
 49        {
 16195350            GetTriangle(
 16195351                vertices,
 16195352                triangleIndices,
 16195353                i,
 16195354                out FixedTriangle triangle);
 16195055            triangle.GetExactNormal(
 16195056                out _,
 16195057                out _,
 16195058                out _,
 16195059                out Signed320 squaredDoubleArea);
 16195060            ExactMassWeight weight =
 16195061                ExactMassProperties.CreateTriangleAreaWeight(
 16195062                    squaredDoubleArea);
 16195063            Signed320 weightNumerator = weight.Numerator;
 16195064            totalWeight = WideArithmetic.AddSigned576(
 16195065                totalWeight,
 16195066                Signed576.ExtendValue(weightNumerator));
 16195067            firstMomentX = AddWeightedVertexSum(
 16195068                firstMomentX,
 16195069                triangle.A.X,
 16195070                triangle.B.X,
 16195071                triangle.C.X,
 16195072                weightNumerator);
 16195073            firstMomentY = AddWeightedVertexSum(
 16195074                firstMomentY,
 16195075                triangle.A.Y,
 16195076                triangle.B.Y,
 16195077                triangle.C.Y,
 16195078                weightNumerator);
 16195079            firstMomentZ = AddWeightedVertexSum(
 16195080                firstMomentZ,
 16195081                triangle.A.Z,
 16195082                triangle.B.Z,
 16195083                triangle.C.Z,
 16195084                weightNumerator);
 16195085            GetProductSums(
 16195086                triangle,
 16195087                out Signed320 x2,
 16195088                out Signed320 y2,
 16195089                out Signed320 z2,
 16195090                out Signed320 xy,
 16195091                out Signed320 xz,
 16195092                out Signed320 yz);
 16195093            secondMomentX = AddWeighted(
 16195094                secondMomentX,
 16195095                x2,
 16195096                weightNumerator);
 16195097            secondMomentY = AddWeighted(
 16195098                secondMomentY,
 16195099                y2,
 161950100                weightNumerator);
 161950101            secondMomentZ = AddWeighted(
 161950102                secondMomentZ,
 161950103                z2,
 161950104                weightNumerator);
 161950105            productMomentXY = AddWeighted(
 161950106                productMomentXY,
 161950107                xy,
 161950108                weightNumerator);
 161950109            productMomentXZ = AddWeighted(
 161950110                productMomentXZ,
 161950111                xz,
 161950112                weightNumerator);
 161950113            productMomentYZ = AddWeighted(
 161950114                productMomentYZ,
 161950115                yz,
 161950116                weightNumerator);
 117        }
 118
 458119        if (totalWeight.IsZero)
 120        {
 1121            surfaceWeight = default;
 1122            centerOfMass = default;
 1123            unitMassInertiaTensor = default;
 1124            return false;
 125        }
 126
 457127        surfaceWeight = new ExactMassWeight(
 457128            Signed320.NarrowValue(totalWeight));
 457129        Signed576 centerDenominator =
 457130            WideArithmetic.MultiplySigned576(
 457131                totalWeight,
 457132                Three);
 457133        _ = Fixed64.TryGetSignedRawRatio(
 457134            firstMomentX,
 457135            centerDenominator,
 457136            out Fixed64 centerX);
 457137        _ = Fixed64.TryGetSignedRawRatio(
 457138            firstMomentY,
 457139            centerDenominator,
 457140            out Fixed64 centerY);
 457141        _ = Fixed64.TryGetSignedRawRatio(
 457142            firstMomentZ,
 457143            centerDenominator,
 457144            out Fixed64 centerZ);
 457145        centerOfMass = new Vector3d(
 457146            centerX,
 457147            centerY,
 457148            centerZ);
 149
 457150        Signed576 centeredX = TranslateSquaredMoment(
 457151            secondMomentX,
 457152            firstMomentX,
 457153            totalWeight,
 457154            centerX);
 457155        Signed576 centeredY = TranslateSquaredMoment(
 457156            secondMomentY,
 457157            firstMomentY,
 457158            totalWeight,
 457159            centerY);
 457160        Signed576 centeredZ = TranslateSquaredMoment(
 457161            secondMomentZ,
 457162            firstMomentZ,
 457163            totalWeight,
 457164            centerZ);
 457165        Signed576 centeredXY = TranslateProductMoment(
 457166            productMomentXY,
 457167            firstMomentX,
 457168            firstMomentY,
 457169            totalWeight,
 457170            centerX,
 457171            centerY);
 457172        Signed576 centeredXZ = TranslateProductMoment(
 457173            productMomentXZ,
 457174            firstMomentX,
 457175            firstMomentZ,
 457176            totalWeight,
 457177            centerX,
 457178            centerZ);
 457179        Signed576 centeredYZ = TranslateProductMoment(
 457180            productMomentYZ,
 457181            firstMomentY,
 457182            firstMomentZ,
 457183            totalWeight,
 457184            centerY,
 457185            centerZ);
 457186        Signed576 inertiaXX =
 457187            WideArithmetic.AddSigned576(centeredY, centeredZ);
 457188        Signed576 inertiaYY =
 457189            WideArithmetic.AddSigned576(centeredX, centeredZ);
 457190        Signed576 inertiaZZ =
 457191            WideArithmetic.AddSigned576(centeredX, centeredY);
 192
 457193        Signed576 diagonalDenominator =
 457194            WideArithmetic.MultiplySigned576(
 457195                totalWeight,
 457196                Signed192.One,
 457197                Six);
 457198        Signed576 productDenominator =
 457199            WideArithmetic.MultiplySigned576(
 457200                totalWeight,
 457201                Signed192.One,
 457202                Twelve);
 457203        bool representable = Fixed64.TryGetSignedRawRatio(
 457204                inertiaXX,
 457205                diagonalDenominator,
 457206                out Fixed64 tensorXX)
 457207            & Fixed64.TryGetSignedRawRatio(
 457208                inertiaYY,
 457209                diagonalDenominator,
 457210                out Fixed64 tensorYY)
 457211            & Fixed64.TryGetSignedRawRatio(
 457212                inertiaZZ,
 457213                diagonalDenominator,
 457214                out Fixed64 tensorZZ)
 457215            & Fixed64.TryGetSignedRawRatio(
 457216                WideArithmetic.SubtractSigned576(default, centeredXY),
 457217                productDenominator,
 457218                out Fixed64 tensorXY)
 457219            & Fixed64.TryGetSignedRawRatio(
 457220                WideArithmetic.SubtractSigned576(default, centeredXZ),
 457221                productDenominator,
 457222                out Fixed64 tensorXZ)
 457223            & Fixed64.TryGetSignedRawRatio(
 457224                WideArithmetic.SubtractSigned576(default, centeredYZ),
 457225                productDenominator,
 457226                out Fixed64 tensorYZ);
 457227        if (!representable)
 228        {
 27229            surfaceWeight = default;
 27230            centerOfMass = default;
 27231            unitMassInertiaTensor = default;
 27232            return false;
 233        }
 234
 430235        unitMassInertiaTensor = new Fixed3x3(
 430236            tensorXX, tensorXY, tensorXZ,
 430237            tensorXY, tensorYY, tensorYZ,
 430238            tensorXZ, tensorYZ, tensorZZ);
 430239        return true;
 240    }
 241
 242    private static Signed576 AddWeightedVertexSum(
 243        Signed576 total,
 244        Fixed64 first,
 245        Fixed64 second,
 246        Fixed64 third,
 247        Signed320 weight)
 248    {
 485850249        Signed320 sum = WideArithmetic.AddSigned320(
 485850250            WideArithmetic.AddSigned320(
 485850251                Signed320.ExtendValue(Signed192.Raw(first)),
 485850252                Signed320.ExtendValue(Signed192.Raw(second))),
 485850253            Signed320.ExtendValue(Signed192.Raw(third)));
 485850254        return AddWeighted(total, sum, weight);
 255    }
 256
 257    private static Signed576 AddWeighted(
 258        Signed576 total,
 259        Signed320 value,
 260        Signed320 weight) =>
 1457550261        WideArithmetic.AddSigned576(
 1457550262            total,
 1457550263            WideArithmetic.MultiplySigned320(
 1457550264                value,
 1457550265                weight));
 266
 267    private static void GetProductSums(
 268        FixedTriangle triangle,
 269        out Signed320 x2,
 270        out Signed320 y2,
 271        out Signed320 z2,
 272        out Signed320 xy,
 273        out Signed320 xz,
 274        out Signed320 yz)
 275    {
 161950276        Signed192 ax = Signed192.Raw(triangle.A.X);
 161950277        Signed192 ay = Signed192.Raw(triangle.A.Y);
 161950278        Signed192 az = Signed192.Raw(triangle.A.Z);
 161950279        Signed192 bx = Signed192.Raw(triangle.B.X);
 161950280        Signed192 by = Signed192.Raw(triangle.B.Y);
 161950281        Signed192 bz = Signed192.Raw(triangle.B.Z);
 161950282        Signed192 cx = Signed192.Raw(triangle.C.X);
 161950283        Signed192 cy = Signed192.Raw(triangle.C.Y);
 161950284        Signed192 cz = Signed192.Raw(triangle.C.Z);
 161950285        x2 = SquaredBarycentricSum(ax, bx, cx);
 161950286        y2 = SquaredBarycentricSum(ay, by, cy);
 161950287        z2 = SquaredBarycentricSum(az, bz, cz);
 161950288        xy = BarycentricCrossSum(ax, bx, cx, ay, by, cy);
 161950289        xz = BarycentricCrossSum(ax, bx, cx, az, bz, cz);
 161950290        yz = BarycentricCrossSum(ay, by, cy, az, bz, cz);
 161950291    }
 292
 293    private static Signed320 SquaredBarycentricSum(
 294        Signed192 first,
 295        Signed192 second,
 296        Signed192 third) =>
 485850297        WideArithmetic.AddSigned320(
 485850298            WideArithmetic.AddSigned320(
 485850299                WideArithmetic.AddSigned320(
 485850300                    WideArithmetic.MultiplySigned192(first, first),
 485850301                    WideArithmetic.MultiplySigned192(second, second)),
 485850302                WideArithmetic.AddSigned320(
 485850303                    WideArithmetic.MultiplySigned192(third, third),
 485850304                    WideArithmetic.MultiplySigned192(first, second))),
 485850305            WideArithmetic.AddSigned320(
 485850306                WideArithmetic.MultiplySigned192(first, third),
 485850307                WideArithmetic.MultiplySigned192(second, third)));
 308
 309    private static Signed320 BarycentricCrossSum(
 310        Signed192 firstA,
 311        Signed192 firstB,
 312        Signed192 firstC,
 313        Signed192 secondA,
 314        Signed192 secondB,
 315        Signed192 secondC)
 316    {
 485850317        Signed192 firstSum = Signed192.NarrowProven(
 485850318            WideArithmetic.AddSigned320(
 485850319                WideArithmetic.AddSigned320(
 485850320                    Signed320.ExtendValue(firstA),
 485850321                    Signed320.ExtendValue(firstB)),
 485850322                Signed320.ExtendValue(firstC)));
 485850323        Signed192 secondSum = Signed192.NarrowProven(
 485850324            WideArithmetic.AddSigned320(
 485850325                WideArithmetic.AddSigned320(
 485850326                    Signed320.ExtendValue(secondA),
 485850327                    Signed320.ExtendValue(secondB)),
 485850328                Signed320.ExtendValue(secondC)));
 485850329        Signed320 matching = WideArithmetic.AddSigned320(
 485850330            WideArithmetic.AddSigned320(
 485850331                WideArithmetic.MultiplySigned192(firstA, secondA),
 485850332                WideArithmetic.MultiplySigned192(firstB, secondB)),
 485850333            WideArithmetic.MultiplySigned192(firstC, secondC));
 485850334        return WideArithmetic.AddSigned320(
 485850335            WideArithmetic.MultiplySigned192(
 485850336                firstSum,
 485850337                secondSum),
 485850338            matching);
 339    }
 340
 341    private static Signed576 TranslateSquaredMoment(
 342        Signed576 secondMoment,
 343        Signed576 firstMoment,
 344        Signed576 totalWeight,
 345        Fixed64 center)
 346    {
 1371347        Signed192 centerRaw = Signed192.Raw(center);
 1371348        Signed576 shifted = WideArithmetic.SubtractSigned576(
 1371349            secondMoment,
 1371350            WideArithmetic.MultiplySigned576(
 1371351                firstMoment,
 1371352                centerRaw,
 1371353                Signed192.Signed(4)));
 1371354        return WideArithmetic.AddSigned576(
 1371355            shifted,
 1371356            WideArithmetic.MultiplySigned576(
 1371357                totalWeight,
 1371358                centerRaw,
 1371359                centerRaw,
 1371360                Six));
 361    }
 362
 363    private static Signed576 TranslateProductMoment(
 364        Signed576 productMoment,
 365        Signed576 firstMoment,
 366        Signed576 secondMoment,
 367        Signed576 totalWeight,
 368        Fixed64 firstCenter,
 369        Fixed64 secondCenter)
 370    {
 1371371        Signed192 firstCenterRaw =
 1371372            Signed192.Raw(firstCenter);
 1371373        Signed192 secondCenterRaw =
 1371374            Signed192.Raw(secondCenter);
 1371375        Signed576 shifted = WideArithmetic.SubtractSigned576(
 1371376            productMoment,
 1371377            WideArithmetic.MultiplySigned576(
 1371378                secondMoment,
 1371379                firstCenterRaw,
 1371380                Signed192.Signed(4)));
 1371381        shifted = WideArithmetic.SubtractSigned576(
 1371382            shifted,
 1371383            WideArithmetic.MultiplySigned576(
 1371384                firstMoment,
 1371385                secondCenterRaw,
 1371386                Signed192.Signed(4)));
 1371387        return WideArithmetic.AddSigned576(
 1371388            shifted,
 1371389            WideArithmetic.MultiplySigned576(
 1371390                totalWeight,
 1371391                firstCenterRaw,
 1371392                secondCenterRaw,
 1371393                Twelve));
 394    }
 395
 396    private static void GetTriangle(
 397        ReadOnlySpan<Vector3d> vertices,
 398        ReadOnlySpan<int> triangleIndices,
 399        int index,
 400        out FixedTriangle triangle)
 401    {
 161953402        int first = triangleIndices[index];
 161953403        int second = triangleIndices[index + 1];
 161953404        int third = triangleIndices[index + 2];
 161953405        if ((uint)first >= (uint)vertices.Length
 161953406            || (uint)second >= (uint)vertices.Length
 161953407            || (uint)third >= (uint)vertices.Length)
 408        {
 3409            throw new ArgumentOutOfRangeException(
 3410                nameof(triangleIndices),
 3411                "Triangle indices must reference supplied vertices.");
 412        }
 413
 161950414        triangle = new FixedTriangle(
 161950415            vertices[first],
 161950416            vertices[second],
 161950417            vertices[third]);
 161950418    }
 419}