< Summary

Line coverage
100%
Covered lines: 118
Uncovered lines: 0
Coverable lines: 118
Total lines: 248
Line coverage: 100%
Branch coverage
100%
Covered branches: 50
Total branches: 50
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WidePlaneMetrics.cs

#LineLine coverage
 1//=======================================================================
 2// WidePlaneMetrics.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>Exact metrics of representable points projected onto an exact rigid plane.</summary>
 13/// <content>Compact projected metrics and shared exact plane geometry.</content>
 14internal readonly partial struct WidePlaneMetrics
 15{
 16    private readonly WideAxis3 normal;
 17    private readonly Signed576 metric;
 18
 19    /// <summary>Uses a nonzero exact normal with components below 262 bits.</summary>
 20    internal WidePlaneMetrics(in WideAxis3 exactNormal)
 21    {
 322        if (exactNormal.IsZero) throw new ArgumentException("The metric requires a nonzero normal.", nameof(exactNormal)
 123        normal = exactNormal;
 124        metric = normal.SquaredLength;
 125    }
 26
 27    internal WidePlaneMetrics(FixedTriangle plane, FixedQuaternion rotation)
 28    {
 1929        plane.GetExactNormal(out Signed192 x, out Signed192 y, out Signed192 z, out _);
 1930        if (x.IsZero && y.IsZero && z.IsZero)
 131            throw new ArgumentException("The metric requires a nondegenerate plane.", nameof(plane));
 1832        var basis = new WideRationalBasis3d(rotation);
 1833        if (basis.Denominator.IsZero)
 134            throw new ArgumentException("The metric requires a nonzero rotation.", nameof(rotation));
 1735        normal = WideRigidProjection.TransformLocalAxis(basis, x, y, z);
 1736        metric = normal.SquaredLength;
 1737    }
 38
 39    /// <summary>Uses admitted scaled geometry with centered reach at most 4096 units.</summary>
 40    internal WidePlaneMetrics(FixedTriangle plane, in ScaledRigidFrame3d frame)
 41    {
 1042        if (frame.IsRigid) { this = new WidePlaneMetrics(plane, frame.Rotation); return; }
 443        WideDirection3d direction = WideTriangleRelations.GetScaledTriangleLocalNormal(plane, frame)
 444            .Transform(frame.GeometryBasis);
 445        normal = new WideAxis3(Signed320.NarrowValue(direction.X), Signed320.NarrowValue(direction.Y), Signed320.NarrowV
 646        if (normal.IsZero) throw new ArgumentException("The metric requires a nondegenerate scaled plane.", nameof(plane
 47        // Centered raw radius <=2^44 gives scaled-edge numerators <=2^109.
 48        // Their cross and one normalized basis give |N|<2^283. Thus M<2^566
 49        // and full-domain projected area squares <2^830 fit the compact owners.
 250        metric = normal.SquaredLength;
 251    }
 52
 53    // Raw endpoint differences <2^64, authored normal components <2^130
 54    // and arbitrary quaternion basis components <2^130 give N<2^262.
 55    // M=N.N<2^526; G(u,v)=M(u.v)-(N.u)(N.v)<2^657;
 56    // T(u,v)=N.(u cross v)<2^393 and T²<2^786. Signed832 retains
 57    // every metric. Ratio comparison uses the existing 26-word products.
 58
 59    /// <summary>Returns M times squared projected distance in raw coordinate units.</summary>
 60    internal Signed832 GetSpanSquared(Vector3d first, Vector3d second)
 61    {
 7062        WideAxis3 edge = Difference(second, first);
 7063        return Gram(edge, edge);
 64    }
 65
 66    /// <summary>Returns 4M times squared projected triangle area in raw coordinate units.</summary>
 67    internal Signed832 GetAreaSquared(Vector3d first, Vector3d second, Vector3d third)
 68    {
 6569        Signed576 area = Triple(Difference(second, first), Difference(third, first));
 6570        return WideArithmetic.MultiplySigned576ToSigned832(area, area);
 71    }
 72
 73    /// <summary>
 74    /// Returns exact squared distance between the projected point and filled
 75    /// projected triangle as a nonnegative numerator over a positive denominator,
 76    /// in raw coordinate units squared. Degenerate projections reduce to edges.
 77    /// </summary>
 78    internal void GetTriangleDistanceSquared(Vector3d point, Vector3d first, Vector3d second, Vector3d third,
 79        out Signed832 numerator, out Signed832 denominator)
 80    {
 60681        WideAxis3 edge = Difference(second, first), offset = Difference(point, first);
 30382        int orientation = Triple(edge, Difference(third, first)).Sign;
 30383        if (orientation != 0
 30384            && orientation * Triple(edge, offset).Sign >= 0
 30385            && orientation * Triple(Difference(third, second), Difference(point, second)).Sign >= 0
 30386            && orientation * Triple(Difference(first, third), Difference(point, third)).Sign >= 0)
 87        {
 16088            numerator = default;
 16089            denominator = Signed832.ExtendValue(metric);
 16090            return;
 91        }
 14392        GetSegmentDistanceSquared(point, first, second, out numerator, out denominator);
 14393        GetSegmentDistanceSquared(point, second, third, out Signed832 nextNumerator, out Signed832 nextDenominator);
 14394        if (CompareRatios(nextNumerator, nextDenominator, numerator, denominator) < 0)
 95        {
 10696            numerator = nextNumerator; denominator = nextDenominator;
 97        }
 14398        GetSegmentDistanceSquared(point, third, first, out nextNumerator, out nextDenominator);
 14399        if (CompareRatios(nextNumerator, nextDenominator, numerator, denominator) < 0)
 100        {
 34101            numerator = nextNumerator; denominator = nextDenominator;
 102        }
 143103    }
 104
 105    /// <summary>Compares nonnegative metric ratios with positive denominators.</summary>
 106    internal static int CompareRatios(Signed832 firstNumerator, Signed832 firstDenominator,
 107        Signed832 secondNumerator, Signed832 secondDenominator) =>
 436108        WideArithmetic.CompareNonNegativeProducts(firstNumerator, secondDenominator, secondNumerator, firstDenominator);
 109
 110    private void GetSegmentDistanceSquared(Vector3d point, Vector3d first, Vector3d second,
 111        out Signed832 numerator, out Signed832 denominator)
 112    {
 858113        WideAxis3 edge = Difference(second, first), offset = Difference(point, first);
 858114        Signed832 length = Gram(edge, edge), projection = Gram(offset, edge);
 429115        if (length.IsZero || projection.Sign <= 0)
 116        {
 156117            numerator = Gram(offset, offset);
 156118            denominator = Signed832.ExtendValue(metric);
 119        }
 273120        else if (WideArithmetic.SubtractSigned832(projection, length).Sign >= 0)
 121        {
 154122            offset = Difference(point, second);
 154123            numerator = Gram(offset, offset);
 154124            denominator = Signed832.ExtendValue(metric);
 125        }
 126        else
 127        {
 128            // G(v,v)G(e,e)-G(v,e)² = M*T(v,e)². Cancel M before
 129            // forming a numerator, avoiding an unnecessary >832-bit product.
 119130            Signed576 area = Triple(offset, edge);
 119131            numerator = WideArithmetic.MultiplySigned576ToSigned832(area, area);
 119132            denominator = length;
 133        }
 119134    }
 135
 136    private Signed832 Gram(WideAxis3 first, WideAxis3 second) =>
 1238137        WideArithmetic.SubtractSigned832(
 1238138            WideArithmetic.MultiplySigned576ToSigned832(metric, WideAxis3.Dot(first, second)),
 1238139            WideArithmetic.MultiplySigned576ToSigned832(WideAxis3.Dot(normal, first), WideAxis3.Dot(normal, second)));
 140
 1208141    private Signed576 Triple(WideAxis3 first, WideAxis3 second) => WideAxis3.Dot(normal, WideAxis3.Cross(first, second))
 142
 3916143    private static WideAxis3 Difference(Vector3d end, Vector3d start) => new(
 3916144        Signed320.ExtendValue(WideArithmetic.SubtractSigned192(Signed192.Raw(end.X), Signed192.Raw(start.X))),
 3916145        Signed320.ExtendValue(WideArithmetic.SubtractSigned192(Signed192.Raw(end.Y), Signed192.Raw(start.Y))),
 3916146        Signed320.ExtendValue(WideArithmetic.SubtractSigned192(Signed192.Raw(end.Z), Signed192.Raw(start.Z))));
 147}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Common/WidePlaneMetrics.ExactAxis.cs

#LineLine coverage
 1//=======================================================================
 2// WidePlaneMetrics.ExactAxis.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/// <content>Borrowed projected metrics for exact scaled directions without narrowing the plane normal.</content>
 13internal readonly partial struct WidePlaneMetrics
 14{
 15    // Scaled collision directions have components below 400 bits. With full
 16    // scalar differences, Gram values need <932 bits and squared areas <1064.
 17    // Caller-owned 2048-bit fields retain complete metrics; ratio comparison
 18    // supplies its own complete cross-product scratch.
 19    internal static void GetSpanSquared(in WideDirection3d axis, Vector3d first, Vector3d second,
 1420        scoped ContactQuadratic result) => GetWideGram(axis, Difference(second, first), Difference(second, first), resul
 21
 22    internal static void GetAreaSquared(in WideDirection3d axis, Vector3d first, Vector3d second, Vector3d third,
 23        scoped ContactQuadratic result)
 24    {
 1425        Signed832 triple = GetWideTriple(axis, Difference(second, first), Difference(third, first));
 1426        int words = result.FieldWords;
 2827        Span<ulong> values = stackalloc ulong[2 * words]; Span<int> signs = stackalloc int[2];
 2828        var value = ContactQuadratic.At(values, signs, 0, words); value.Set(triple);
 1429        ContactQuadratic.Multiply(value, value, ReadOnlySpan<ulong>.Empty, result);
 1430    }
 31
 32    internal static int GetAreaSign(in WideDirection3d axis, Vector3d first, Vector3d second, Vector3d third) =>
 1433        GetWideTriple(axis, Difference(second, first), Difference(third, first)).Sign;
 34
 35    internal static void GetTriangleDistanceSquared(in WideDirection3d axis, Vector3d point,
 36        Vector3d first, Vector3d second, Vector3d third, scoped ContactQuadratic numerator, scoped ContactQuadratic deno
 37    {
 20038        WideAxis3 edge = Difference(second, first), offset = Difference(point, first);
 10039        int orientation = GetWideTriple(axis, edge, Difference(third, first)).Sign;
 10040        if (orientation != 0 && orientation * GetWideTriple(axis, edge, offset).Sign >= 0
 10041            && orientation * GetWideTriple(axis, Difference(third, second), Difference(point, second)).Sign >= 0
 10042            && orientation * GetWideTriple(axis, Difference(first, third), Difference(point, third)).Sign >= 0)
 43        {
 17144            numerator.Clear(); denominator.Set(axis.SquaredLength); return;
 45        }
 4346        GetWideSegmentDistance(axis, point, first, second, numerator, denominator);
 4347        int words = numerator.FieldWords;
 8648        Span<ulong> values = stackalloc ulong[4 * words]; Span<int> signs = stackalloc int[4];
 4349        var nextN = ContactQuadratic.At(values, signs, 0, words);
 4350        var nextD = ContactQuadratic.At(values, signs, 1, words);
 4351        GetWideSegmentDistance(axis, point, second, third, nextN, nextD);
 4352        if (ContactQuadratic.CompareRatios(nextN, nextD, ReadOnlySpan<ulong>.Empty,
 8153            numerator, denominator, ReadOnlySpan<ulong>.Empty) < 0) { nextN.CopyTo(numerator); nextD.CopyTo(denominator)
 4354        GetWideSegmentDistance(axis, point, third, first, nextN, nextD);
 4355        if (ContactQuadratic.CompareRatios(nextN, nextD, ReadOnlySpan<ulong>.Empty,
 5156            numerator, denominator, ReadOnlySpan<ulong>.Empty) < 0) { nextN.CopyTo(numerator); nextD.CopyTo(denominator)
 4357    }
 58
 59    private static void GetWideSegmentDistance(in WideDirection3d axis, Vector3d point, Vector3d first, Vector3d second,
 60        scoped ContactQuadratic numerator, scoped ContactQuadratic denominator)
 61    {
 12962        int words = numerator.FieldWords;
 25863        Span<ulong> values = stackalloc ulong[6 * words]; Span<int> signs = stackalloc int[6];
 12964        var length = ContactQuadratic.At(values, signs, 0, words);
 12965        var projection = ContactQuadratic.At(values, signs, 1, words);
 12966        var remainder = ContactQuadratic.At(values, signs, 2, words);
 25867        WideAxis3 edge = Difference(second, first), offset = Difference(point, first);
 25868        GetWideGram(axis, edge, edge, length); GetWideGram(axis, offset, edge, projection);
 25869        projection.CopyTo(remainder); remainder.Add(length, -1);
 12970        if (length.Signs[0] == 0 || projection.Signs[0] <= 0)
 11071        { GetWideGram(axis, offset, offset, numerator); denominator.Set(axis.SquaredLength); }
 7472        else if (remainder.Signs[0] >= 0)
 12373        { offset = Difference(point, second); GetWideGram(axis, offset, offset, numerator); denominator.Set(axis.Squared
 74        else
 75        {
 76            // Cancel the common normal metric before squaring the triple product.
 3377            projection.Set(GetWideTriple(axis, offset, edge));
 3378            ContactQuadratic.Multiply(projection, projection, ReadOnlySpan<ulong>.Empty, numerator);
 3379            length.CopyTo(denominator);
 80        }
 3381    }
 82
 83    private static void GetWideGram(in WideDirection3d axis, in WideAxis3 first, in WideAxis3 second,
 84        scoped ContactQuadratic result)
 85    {
 36886        int words = result.FieldWords;
 73687        Span<ulong> values = stackalloc ulong[8 * words]; Span<int> signs = stackalloc int[8];
 36888        var metric = ContactQuadratic.At(values, signs, 0, words);
 36889        var projectionA = ContactQuadratic.At(values, signs, 1, words);
 36890        var projectionB = ContactQuadratic.At(values, signs, 2, words);
 36891        var product = ContactQuadratic.At(values, signs, 3, words);
 36892        metric.Set(axis.SquaredLength);
 36893        ContactQuadratic.Scale(metric, WideAxis3.Dot(first, second), result);
 73694        projectionA.Set(WideDirection3d.Dot(axis, first)); projectionB.Set(WideDirection3d.Dot(axis, second));
 36895        ContactQuadratic.Multiply(projectionA, projectionB, ReadOnlySpan<ulong>.Empty, product);
 36896        result.Add(product, -1);
 36897    }
 98
 99    private static Signed832 GetWideTriple(in WideDirection3d axis, in WideAxis3 first, in WideAxis3 second) =>
 395100        WideDirection3d.Dot(axis, WideAxis3.Cross(first, second));
 101}

Methods/Properties

.ctor(FixedMathSharp.Geometry.WideAxis3&)
.ctor(FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.FixedQuaternion)
.ctor(FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Geometry.ScaledRigidFrame3d&)
GetSpanSquared(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetAreaSquared(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetTriangleDistanceSquared(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
CompareRatios(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed832)
GetSegmentDistanceSquared(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
Gram(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3)
Triple(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3)
Difference(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetSpanSquared(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.ContactQuadratic)
GetAreaSquared(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.ContactQuadratic)
GetAreaSign(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetTriangleDistanceSquared(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
GetWideSegmentDistance(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
GetWideGram(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.ContactQuadratic)
GetWideTriple(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&)