< Summary

Information
Class: FixedMathSharp.Geometry.AxisTriangleContactFeature
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/AxisTriangleContactFeature.cs
Line coverage
100%
Covered lines: 43
Uncovered lines: 0
Coverable lines: 43
Total lines: 107
Line coverage: 100%
Branch coverage
100%
Covered branches: 16
Total branches: 16
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%
.ctor(...)100%11100%
GetWorldFeatureFromRigidLocal(...)100%22100%
get_IsZeroSeparation()100%44100%
CompareSeparationProjection(...)100%22100%
CompareSeparationProjection(...)100%66100%
CompareSeparationProjection(...)100%22100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/FiniteAxis/AxisTriangleContactFeature.cs

#LineLine coverage
 1//=======================================================================
 2// AxisTriangleContactFeature.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>Retains exact closest-point feature identity and separation before contact rounding.</summary>
 13internal readonly struct AxisTriangleContactFeature
 14{
 15    private readonly Signed832 _separationX, _separationY, _separationZ;
 16    private readonly bool _wide;
 17
 18    internal AxisTriangleContactFeature(int edgeMask, Signed576 separationX,
 19        Signed576 separationY, Signed576 separationZ, int triangleVertex = -1)
 20    {
 6021        _wide = false;
 6022        EdgeMask = edgeMask;
 6023        TriangleVertex = triangleVertex;
 18024        _separationX = Signed832.ExtendValue(separationX); _separationY = Signed832.ExtendValue(separationY); _separatio
 6025    }
 26
 27    internal AxisTriangleContactFeature(int edgeMask, Signed832 x, Signed832 y, Signed832 z, int triangleVertex = -1)
 28    {
 4129        _wide = true;
 8230        EdgeMask = edgeMask; TriangleVertex = triangleVertex;
 12331        _separationX = x; _separationY = y; _separationZ = z;
 4132    }
 33
 34    /// <summary>Maps a retained rigid-local separation into world orientation without scalar rounding.</summary>
 35    internal AxisTriangleContactFeature GetWorldFeatureFromRigidLocal(FixedQuaternion rotation)
 36    {
 337        if (rotation == FixedQuaternion.Identity) return this;
 38        // This ingress is used only for the legacy local closest chart, whose
 39        // complete components fit Signed576. One normalized basis adds <65
 40        // bits; the resulting world direction fits Signed832.
 141        var basis = new WideRationalBasis3d(rotation);
 342        Signed576 x = Signed576.NarrowValue(_separationX), y = Signed576.NarrowValue(_separationY), z = Signed576.Narrow
 43        Signed832 Component(Signed192 a, Signed192 b, Signed192 c) =>
 44            WideArithmetic.AddSigned832(WideArithmetic.AddSigned832(
 45                WideArithmetic.MultiplySigned576ToSigned832(x, Signed320.ExtendValue(a)),
 46                WideArithmetic.MultiplySigned576ToSigned832(y, Signed320.ExtendValue(b))),
 47                WideArithmetic.MultiplySigned576ToSigned832(z, Signed320.ExtendValue(c)));
 148        return new AxisTriangleContactFeature(EdgeMask, Component(basis.Xx, basis.Yx, basis.Zx),
 149            Component(basis.Xy, basis.Yy, basis.Zy), Component(basis.Xz, basis.Yz, basis.Zz), TriangleVertex);
 50    }
 51    /// <summary>Zero edge halfspaces: AB=1, BC=2, CA=4; 7 declines degenerate classification.</summary>
 52    internal int EdgeMask { get; }
 53
 54    /// <summary>Exact authored vertex ownership; -1 denotes a nonvertex witness.</summary>
 55    internal int TriangleVertex { get; }
 56
 57    /// <summary>Whether the retained core and triangle witnesses coincide exactly.</summary>
 2458    internal bool IsZeroSeparation => _separationX.IsZero && _separationY.IsZero && _separationZ.IsZero;
 59
 60    /// <summary>Gets the exact separation sign along a wide direction in the selected contact chart.</summary>
 61    internal int CompareSeparationProjection(Signed192 x, Signed192 y, Signed192 z)
 62    {
 2663        if (_wide) return CompareSeparationProjection(new WideAxis3(Signed320.ExtendValue(x), Signed320.ExtendValue(y), 
 1064        return WideArithmetic.AddSigned832(WideArithmetic.AddSigned832(
 1065            WideArithmetic.MultiplySigned576ToSigned832(Signed576.NarrowValue(_separationX), Signed320.ExtendValue(x)),
 1066            WideArithmetic.MultiplySigned576ToSigned832(Signed576.NarrowValue(_separationY), Signed320.ExtendValue(y))),
 1067            WideArithmetic.MultiplySigned576ToSigned832(Signed576.NarrowValue(_separationZ), Signed320.ExtendValue(z))).
 68    }
 69
 70    /// <summary>Gets the same exact sign for a rigidly transformed wide axis.</summary>
 71    internal int CompareSeparationProjection(in WideAxis3 direction)
 72    {
 73        // Full 832-by-320 products plus carries need 1154 signed bits. The
 74        // existing quadratic owner retains this rational-only dot without
 75        // narrowing exceptional world-chart plane normals to Signed192.
 3076        int words = _wide ? 19 : 15;
 3077        Span<ulong> values = stackalloc ulong[6 * words];
 3078        Span<int> signs = stackalloc int[6];
 3079        ContactQuadratic sum = ContactQuadratic.At(values, signs, 0, words);
 3080        ContactQuadratic term = ContactQuadratic.At(values, signs, 1, words);
 3081        ContactQuadratic product = ContactQuadratic.At(values, signs, 2, words);
 3082        sum.Clear();
 3083        Span<Signed832> components = stackalloc Signed832[3] { _separationX, _separationY, _separationZ };
 3084        Span<Signed320> axes = stackalloc Signed320[3] { direction.X, direction.Y, direction.Z };
 24085        for (int index = 0; index < 3; index++)
 86        {
 18087            if (_wide) term.Set(components[index]); else term.Set(Signed576.NarrowValue(components[index]));
 9088            ContactQuadratic.Scale(term, Signed576.ExtendValue(axes[index]), product);
 9089            sum.Add(product);
 90        }
 3091        return sum.Sign(ReadOnlySpan<ulong>.Empty);
 92    }
 93
 94    /// <summary>Gets the exact sign of separation dotted with a ray in the selected contact chart.</summary>
 95    internal int CompareSeparationProjection(Vector3d first, Vector3d second)
 96    {
 3997        Signed320 x = Signed320.ExtendValue(WideArithmetic.Difference(second.X, first.X));
 3998        Signed320 y = Signed320.ExtendValue(WideArithmetic.Difference(second.Y, first.Y));
 3999        Signed320 z = Signed320.ExtendValue(WideArithmetic.Difference(second.Z, first.Z));
 39100        if (!_wide)
 29101            return WideArithmetic.AddSigned704(WideArithmetic.AddSigned704(
 29102                WideArithmetic.MultiplySigned576ToSigned704(Signed576.NarrowValue(_separationX), x),
 29103                WideArithmetic.MultiplySigned576ToSigned704(Signed576.NarrowValue(_separationY), y)),
 29104                WideArithmetic.MultiplySigned576ToSigned704(Signed576.NarrowValue(_separationZ), z)).Sign;
 10105        return CompareSeparationProjection(new WideAxis3(x, y, z));
 106    }
 107}