< Summary

Line coverage
100%
Covered lines: 1631
Uncovered lines: 0
Coverable lines: 1631
Total lines: 2680
Line coverage: 100%
Branch coverage
100%
Covered branches: 612
Total branches: 612
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: .ctor(...)100%11100%
File 1: GetBoundaryFaceContacts(...)100%3030100%
File 1: BoundaryIntervalsOverlap(...)100%66100%
File 1: BoundaryWall(...)100%11100%
File 1: ClipBoundaryParameter(...)100%1212100%
File 1: KeepBoundaryFacePoint(...)100%1212100%
File 1: InterpolateBoundaryValue(...)100%11100%
File 1: CompareBoundaryRatios(...)100%11100%
File 1: MaterializeBoundaryFace(...)100%11100%
File 2: TryIntersectBoundarySegments(...)100%4646100%
File 2: WithinBoundaryInterval(...)100%88100%
File 3: GetCapsuleBoundaryFaceContacts(...)100%1818100%
File 3: HasContact(...)100%22100%
File 3: get_HasTwo()100%11100%
File 3: Q(...)100%11100%
File 3: Root(...)100%11100%
File 3: .ctor(...)100%88100%
File 3: AddDisk(...)100%1212100%
File 3: AddSides(...)100%1818100%
File 3: Keep()100%1818100%
File 3: Copy(...)100%11100%
File 3: SetRoot(...)100%11100%
File 3: Integer(...)100%11100%
File 3: Materialize(...)100%44100%
File 3: Coordinate(...)100%22100%
File 4: TryGetBoundaryVertexContact(...)100%1010100%
File 4: KeepBoundaryVertexAxis(...)100%88100%
File 4: SupportsBoundaryFan(...)100%44100%
File 4: SupportsBoundaryFan(...)100%44100%
File 4: SameBoundaryPlane(...)100%1414100%
File 4: LocateBoundaryPoint(...)100%3232100%
File 5: get_IsZero()100%22100%
File 5: .ctor(...)100%11100%
File 5: op_UnaryNegation(...)100%11100%
File 5: get_IsPoint()100%11100%
File 5: .ctor(...)100%11100%
File 5: .ctor(...)100%11100%
File 5: DoConvexesOverlap(...)100%1414100%
File 5: GetBoundsClippedToDomain(...)100%1010100%
File 5: GetTransformedEdgeDirection(...)100%11100%
File 5: GetRelativePointNumerators(...)100%11100%
File 5: IsStrictlyConvex(...)100%1212100%
File 5: GetSupportOffset(...)100%11100%
File 5: GetSupportOffset(...)100%44100%
File 5: GetClosestPointOffset(...)100%11100%
File 5: GetClosestPointOffset(...)100%66100%
File 5: GetSweptPointTargetContactOffset(...)100%11100%
File 5: GetSweptPointTargetContactOffset(...)100%11100%
File 5: GetSweptAnchorTargetContactOffset(...)100%11100%
File 5: ContainsPoint(...)100%1414100%
File 5: ContainsPointUnrotated(...)100%1212100%
File 5: ContainsDegeneratePoint(...)100%88100%
File 5: TryProjectAnchorOntoFeature(...)100%11100%
File 5: TryGetContactOffsets(...)100%2222100%
File 5: TryGetAreaAndCentroid(...)100%44100%
File 5: TryGetSignedDoubleAreaAndCentroid(...)100%44100%
File 5: TryKeepAxes(...)100%88100%
File 5: TryKeepAxis(...)100%2828100%
File 6: TryGetEdgeCoverage(...)100%1616100%
File 6: CoveragePoint(...)100%11100%
File 7: IntersectsSweptUprightCapsule(...)100%2020100%
File 7: HasPlanarSweepCoreOverlap(...)100%3838100%
File 7: IsSweepPointNearSegment(...)100%44100%
File 7: GetPlanarSweepWinding(...)100%44100%
File 7: IncludeSweepProjection(...)100%44100%
File 7: DoubleSweepOffset(...)100%11100%
File 7: SubtractSweepPoint(...)100%11100%
File 7: SweepCross(...)100%11100%
File 7: SweepDot(...)100%11100%
File 8: GetMinimumSupportFeature(...)100%11100%
File 8: GetSupportFeature(...)100%2424100%
File 8: GetProjectionRange(...)100%66100%
File 8: GetProjection(...)100%11100%
File 8: GetSquaredDistance(...)100%11100%
File 8: AddProjectedEndpoint(...)100%88100%
File 8: TryProjectPointOntoFeature(...)100%11100%
File 8: TryProjectPointOntoFeature(...)100%1212100%
File 8: GetProjectedOffsetCoordinate(...)100%11100%
File 8: GetDepth(...)100%22100%
File 8: CorrectDepth(...)100%22100%
File 8: CompareDepthToTwiceRaw(...)100%11100%
File 8: GetTransformedEdge(...)100%11100%
File 8: GetWorldPoint(...)100%11100%
File 8: GetWorldPoint(...)100%11100%
File 8: GetRotatedOffset(...)100%11100%
File 8: GetRotatedOffset(...)100%11100%
File 8: GetDirection(...)100%11100%
File 9: .cctor()100%11100%
File 9: .ctor(...)100%11100%
File 9: .ctor(...)100%11100%
File 10: GetSweptConvexContact(...)100%2222100%
File 10: TryGetSweptCenteredAxisContact(...)100%1616100%
File 10: KeepConvexSweepContactAxis(...)100%11100%
File 10: KeepCoreSweepContactAxis(...)100%11100%
File 10: GetSweepCoreRange(...)100%22100%
File 10: KeepSweepContactAxis(...)100%22100%
File 10: KeepSweepEntryAxis(...)100%66100%
File 10: ProjectSweepSupport(...)100%88100%
File 10: GetSweepProjectedCoordinate(...)100%11100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.BoundaryFaces.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.BoundaryFaces.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>Finite planar face witnesses clipped in their original exact edge parameter.</content>
 13internal static partial class WideConvex2dRelations
 14{
 15    private readonly struct BoundaryFacePoint
 16    {
 17        internal readonly Vector2d Start, End;
 18        internal readonly Signed576 N, D;
 19        internal readonly Signed832 Gap, Tangent;
 20        internal BoundaryFacePoint(Vector2d start, Vector2d end, Signed576 n, Signed576 d,
 21            Signed832 gap, Signed832 tangent)
 18922        { Start = start; End = end; N = n; D = d; Gap = gap; Tangent = tangent; }
 23    }
 24
 25    /// <summary>
 26    /// Returns the deepest one or two polygon witnesses against an oriented
 27    /// finite face. The retained face must actually intersect the polygon;
 28    /// this does not turn a remote supporting plane into a contact or recovery.
 29    /// A caller-proven crossing on the same connected cooriented supporting
 30    /// line may admit this supplier; finite tangent clipping still applies.
 31    /// </summary>
 32    internal static int GetBoundaryFaceContacts(Vector2d moverOrigin, Fixed64 moverRotation,
 33        ReadOnlySpan<Vector2d> moverOffsets, Vector2d targetOrigin, Fixed64 targetRotation,
 34        FixedSegment2d edge, Vector2d inward, in RationalSegmentInterval clip,
 35        Span<FixedContactAnchors2d> contacts, bool planeAdmitted = false)
 36    {
 1837        if (contacts.Length < 2) throw new ArgumentException("Two contact slots are required.", nameof(contacts));
 1638        if (!planeAdmitted && (!TryGetEdgeCoverage(targetOrigin, targetRotation, edge, inward,
 1639            moverOrigin, moverRotation, moverOffsets, out RationalSegmentInterval overlap, out _)
 2140            || !BoundaryIntervalsOverlap(clip, overlap))) return 0;
 41
 1142        RotationFrame2d frame = new(targetRotation);
 1143        GetTransformedEdge(frame, edge.Start, edge.End, out Signed192 ex, out Signed192 ey);
 1144        GetTransformedEdge(frame, edge.Start, inward, out Signed192 ix, out Signed192 iy);
 1145        WideAxis2d outward = new(ey, WideArithmetic.Negate(ex));
 1946        if (WideArithmetic.AddProducts(outward.X, ix, outward.Y, iy).Sign > 0) outward = -outward;
 1147        Signed320 squared = WideArithmetic.AddProducts(ex, ex, ey, ey);
 1248        if (squared.IsZero) return 0;
 1049        Signed320 lowerN = clip.IsClipped ? clip.LowerNumerator : default;
 1050        Signed320 lowerD = clip.IsClipped ? clip.LowerDenominator : Signed320.One;
 1051        Signed320 upperN = clip.IsClipped ? clip.UpperNumerator : Signed320.One;
 1052        Signed320 upperD = clip.IsClipped ? clip.UpperDenominator : Signed320.One;
 1053        GetRelativePointNumerators(targetOrigin, targetRotation, edge.Start, targetOrigin,
 1054            out Signed192 ax, out Signed192 ay);
 1055        bool found = false;
 2056        BoundaryFacePoint first = default, last = default;
 9657        for (int index = 0; index < moverOffsets.Length; index++)
 58        {
 7659            Vector2d start = moverOffsets[index], end = moverOffsets[(index + 1) % moverOffsets.Length];
 3860            GetRelativePointNumerators(moverOrigin, moverRotation, start, targetOrigin, out Signed192 sx, out Signed192 
 3861            GetRelativePointNumerators(moverOrigin, moverRotation, end, targetOrigin, out Signed192 tx, out Signed192 ty
 7662            sx = WideArithmetic.SubtractSigned192(sx, ax); sy = WideArithmetic.SubtractSigned192(sy, ay);
 7663            tx = WideArithmetic.SubtractSigned192(tx, ax); ty = WideArithmetic.SubtractSigned192(ty, ay);
 3864            Signed320 u0 = WideArithmetic.AddProducts(sx, ex, sy, ey);
 3865            Signed320 u1 = WideArithmetic.AddProducts(tx, ex, ty, ey);
 15266            Signed576 ln = default, ld = Signed576.One, un = Signed576.One, ud = Signed576.One;
 3867            if (!ClipBoundaryParameter(BoundaryWall(u0, squared, lowerN, lowerD), BoundaryWall(u1, squared, lowerN, lowe
 3868                    ref ln, ref ld, ref un, ref ud)
 3869                || !ClipBoundaryParameter(BoundaryWall(squared, u0, upperD, upperN), BoundaryWall(squared, u1, upperD, u
 3870                    ref ln, ref ld, ref un, ref ud)) continue;
 2471            Signed320 g0 = WideArithmetic.Negate(WideArithmetic.AddProducts(sx, outward.X, sy, outward.Y));
 2472            Signed320 g1 = WideArithmetic.Negate(WideArithmetic.AddProducts(tx, outward.X, ty, outward.Y));
 2473            KeepBoundaryFacePoint(start, end, ln, ld, g0, g1, u0, u1, ref found, ref first, ref last);
 2474            KeepBoundaryFacePoint(start, end, un, ud, g0, g1, u0, u1, ref found, ref first, ref last);
 75        }
 1176        if (!found) return 0;
 977        Vector2d normal = WideNormalization.GetNormalized(WideArithmetic.Negate(outward.X), WideArithmetic.Negate(outwar
 78        // Point/edge numerators share an S scale. Full Signed320 clip bounds
 79        // keep walls below 521 bits, point projections below 723 and depth
 80        // denominators below 554, fitting the existing Signed576/832 banks.
 981        Signed576 denominator = WideArithmetic.MultiplySigned576(first.D, Signed192.One);
 982        Fixed64 depth = WideArithmetic.GetRoundedNonNegativeNormalizedDepth(first.Gap,
 983            Signed832.ExtendValue(squared), denominator, out bool clamped);
 984        contacts[0] = MaterializeBoundaryFace(first, squared, moverOrigin, moverRotation,
 985            targetOrigin, targetRotation, edge, normal, depth, clamped);
 1086        if (CompareBoundaryRatios(first.Tangent, first.D, last.Tangent, last.D) == 0) return 1;
 887        contacts[1] = MaterializeBoundaryFace(last, squared, moverOrigin, moverRotation,
 888            targetOrigin, targetRotation, edge, normal, depth, clamped);
 889        return 2;
 90    }
 91
 92    private static bool BoundaryIntervalsOverlap(in RationalSegmentInterval first, in RationalSegmentInterval second)
 93    {
 1194        if (!first.IsClipped || !second.IsClipped) return true;
 795        return RationalSegmentInterval.CompareParameters(first.LowerNumerator, first.LowerDenominator, second.UpperNumer
 796            && RationalSegmentInterval.CompareParameters(second.LowerNumerator, second.LowerDenominator, first.UpperNume
 97    }
 98
 99    private static Signed576 BoundaryWall(Signed320 value, Signed320 plane, Signed320 n, Signed320 d) =>
 132100        WideArithmetic.SubtractSigned576(WideArithmetic.MultiplySigned320(value, d), WideArithmetic.MultiplySigned320(pl
 101
 102    private static bool ClipBoundaryParameter(Signed576 first, Signed576 second,
 103        ref Signed576 ln, ref Signed576 ld, ref Signed576 un, ref Signed576 ud)
 104    {
 96105        if (first.Sign >= 0 && second.Sign >= 0) return true;
 50106        if (first.Sign < 0 && second.Sign < 0) return false;
 44107        Signed576 n = first, d = WideArithmetic.SubtractSigned576(first, second);
 44108        if (d.Sign < 0) { n = WideArithmetic.SubtractSigned576(default, n); d = WideArithmetic.SubtractSigned576(default
 109        // The ordered parallel lower/upper walls constrain opposite endpoints.
 44110        if (first.Sign < 0) { ln = n; ld = d; }
 22111        else { un = n; ud = d; }
 22112        return CompareBoundaryRatios(Signed832.ExtendValue(ln), ld, Signed832.ExtendValue(un), ud) <= 0;
 113    }
 114
 115    private static void KeepBoundaryFacePoint(Vector2d start, Vector2d end, Signed576 n, Signed576 d,
 116        Signed320 g0, Signed320 g1, Signed320 u0, Signed320 u1,
 117        ref bool found, ref BoundaryFacePoint first, ref BoundaryFacePoint last)
 118    {
 48119        Signed832 gap = InterpolateBoundaryValue(g0, g1, n, d);
 69120        if (gap.Sign < 0) return;
 27121        Signed832 tangent = InterpolateBoundaryValue(u0, u1, n, d);
 27122        var candidate = new BoundaryFacePoint(start, end, n, d, gap, tangent);
 27123        int comparison = found ? CompareBoundaryRatios(gap, d, first.Gap, first.D) : 1;
 45124        if (comparison > 0) { found = true; first = last = candidate; }
 18125        else if (comparison == 0)
 126        {
 16127            if (CompareBoundaryRatios(tangent, d, first.Tangent, first.D) < 0) first = candidate;
 20128            if (CompareBoundaryRatios(tangent, d, last.Tangent, last.D) > 0) last = candidate;
 129        }
 18130    }
 131
 132    private static Signed832 InterpolateBoundaryValue(Signed320 start, Signed320 end, Signed576 n, Signed576 d) =>
 75133        WideArithmetic.AddSigned832(WideArithmetic.MultiplySigned576ToSigned832(d, start),
 75134            WideArithmetic.MultiplySigned576ToSigned832(n, WideArithmetic.SubtractSigned320(end, start)));
 135
 136    private static int CompareBoundaryRatios(Signed832 n, Signed576 d, Signed832 otherN, Signed576 otherD) =>
 77137        WideArithmetic.CompareNonNegativeProducts(n, Signed832.ExtendValue(otherD), otherN, Signed832.ExtendValue(d));
 138
 139    private static FixedContactAnchors2d MaterializeBoundaryFace(in BoundaryFacePoint point, Signed320 squared,
 140        Vector2d moverOrigin, Fixed64 moverRotation, Vector2d targetOrigin, Fixed64 targetRotation,
 141        FixedSegment2d edge, Vector2d normal, Fixed64 depth, bool clamped)
 142    {
 17143        Vector2d moving = new(GetSweepProjectedCoordinate(point.Start.X, point.End.X, point.N, point.D),
 17144            GetSweepProjectedCoordinate(point.Start.Y, point.End.Y, point.N, point.D));
 17145        Signed832 d = WideArithmetic.MultiplySigned576ToSigned832(point.D, squared);
 17146        var parameter = new RationalSegmentInterval(point.Tangent, d, point.Tangent, d);
 17147        return new FixedContactAnchors2d(new FixedPointAnchor2d(moverOrigin, moverRotation, moving),
 17148            new FixedPointAnchor2d(targetOrigin, targetRotation, parameter.GetEndpoint(edge, false)), normal, depth, cla
 149    }
 150}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.BoundaryIntervals.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.BoundaryIntervals.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>Intersects retained nondegenerate native-yaw source edges in their original parameters.</content>
 13internal static partial class WideConvex2dRelations
 14{
 15    internal static bool TryIntersectBoundarySegments(Vector2d origin, Fixed64 yaw, FixedSegment2d edge,
 16        in RationalSegmentInterval clip, Vector2d otherOrigin, Fixed64 otherYaw, FixedSegment2d other,
 17        in RationalSegmentInterval otherClip, out RationalSegmentInterval intersection)
 18    {
 19        // The output may alias either retained input interval. Publish it only
 20        // after every input read, including on rejected intersections.
 2621        GetRelativePointNumerators(origin, yaw, edge.Start, origin, out var ax, out var ay);
 2622        GetRelativePointNumerators(origin, yaw, edge.End, origin, out var bx, out var by);
 2623        GetRelativePointNumerators(otherOrigin, otherYaw, other.Start, origin, out var cx, out var cy);
 2624        GetRelativePointNumerators(otherOrigin, otherYaw, other.End, origin, out var dx, out var dy);
 5225        Signed192 ex = WideArithmetic.SubtractSigned192(bx, ax), ey = WideArithmetic.SubtractSigned192(by, ay),
 5226            fx = WideArithmetic.SubtractSigned192(dx, cx), fy = WideArithmetic.SubtractSigned192(dy, cy),
 5227            rx = WideArithmetic.SubtractSigned192(cx, ax), ry = WideArithmetic.SubtractSigned192(cy, ay);
 2628        Signed320 denominator = WideArithmetic.MultiplySubtract(ex, fy, ey, fx);
 2629        if (!denominator.IsZero)
 30        {
 1431            Signed320 n = WideArithmetic.MultiplySubtract(rx, fy, ry, fx),
 1432                otherN = WideArithmetic.MultiplySubtract(rx, ey, ry, ex);
 1433            if (denominator.Sign < 0)
 934            { n = WideArithmetic.Negate(n); otherN = WideArithmetic.Negate(otherN); denominator = WideArithmetic.Negate(
 1435            if (!WithinBoundaryInterval(n, denominator, clip) || !WithinBoundaryInterval(otherN, denominator, otherClip)
 2236            { intersection = default; return false; }
 637            intersection = new(n, denominator, n, denominator); return true;
 38        }
 1439        if (!WideArithmetic.MultiplySubtract(rx, ey, ry, ex).IsZero) { intersection = default; return false; }
 40        // Native relative coordinates are <100 bits. Retained unit cuts <320
 41        // add at most 421 bits to these affine endpoint ratios; Signed832 keeps
 42        // the complete product before the interval owner reduces its content.
 3343        Signed192 e = ex.IsZero ? ey : ex, f = ex.IsZero ? fy : fx, r = ex.IsZero ? ry : rx;
 1144        Signed832 one = Signed832.ExtendValue(Signed192.Signed(1));
 1145        Signed832 ln = otherClip.IsClipped ? otherClip.WideLowerNumerator : default,
 1146            ld = otherClip.IsClipped ? otherClip.WideLowerDenominator : one,
 1147            un = otherClip.IsClipped ? otherClip.WideUpperNumerator : one,
 1148            ud = otherClip.IsClipped ? otherClip.WideUpperDenominator : one;
 1149        ln = WideArithmetic.AddSigned832(WideArithmetic.MultiplySigned832(ld, r), WideArithmetic.MultiplySigned832(ln, f
 1150        un = WideArithmetic.AddSigned832(WideArithmetic.MultiplySigned832(ud, r), WideArithmetic.MultiplySigned832(un, f
 2251        ld = WideArithmetic.MultiplySigned832(ld, e); ud = WideArithmetic.MultiplySigned832(ud, e);
 1152        if (e.Sign < 0)
 53        {
 1054            ln = WideArithmetic.SubtractSigned832(default, ln); un = WideArithmetic.SubtractSigned832(default, un);
 1055            ld = WideArithmetic.SubtractSigned832(default, ld); ud = WideArithmetic.SubtractSigned832(default, ud);
 56        }
 1557        if (e.Sign * f.Sign < 0) { (ln, un) = (un, ln); (ld, ud) = (ud, ld); }
 1158        Signed832 lower = clip.IsClipped ? clip.WideLowerNumerator : default,
 1159            lowerD = clip.IsClipped ? clip.WideLowerDenominator : one,
 1160            upper = clip.IsClipped ? clip.WideUpperNumerator : one,
 1161            upperD = clip.IsClipped ? clip.WideUpperDenominator : one;
 62        // A translated collinear edge may begin before this source's unit
 63        // interval. The interval comparator requires nonnegative numerators;
 64        // clip those signed affine bounds before comparing retained ratios.
 1565        if (un.Sign < 0) { intersection = default; return false; }
 1366        if (ln.Sign < 0 || RationalSegmentInterval.CompareParameters(ln, ld, lower, lowerD) < 0) { ln = lower; ld = lowe
 1967        if (RationalSegmentInterval.CompareParameters(un, ud, upper, upperD) > 0) { un = upper; ud = upperD; }
 1568        if (RationalSegmentInterval.CompareParameters(ln, ld, un, ud) > 0) { intersection = default; return false; }
 1269        intersection = new(ln, ld, un, ud); return true;
 70    }
 71
 72    private static bool WithinBoundaryInterval(Signed320 n, Signed320 d, in RationalSegmentInterval clip)
 73    {
 2774        if (n.Sign < 0 || WideArithmetic.SubtractSigned320(n, d).Sign > 0) return false;
 1975        return !clip.IsClipped || RationalSegmentInterval.CompareParameters(Signed832.ExtendValue(n), Signed832.ExtendVa
 1976                clip.WideLowerNumerator, clip.WideLowerDenominator) >= 0
 1977            && RationalSegmentInterval.CompareParameters(Signed832.ExtendValue(n), Signed832.ExtendValue(d),
 1978                clip.WideUpperNumerator, clip.WideUpperDenominator) <= 0;
 79    }
 80}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.CapsuleBoundaryContacts.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.CapsuleBoundaryContacts.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>Exact circle and capsule witnesses on a retained finite planar face.</content>
 13internal static partial class WideConvex2dRelations
 14{
 15    /// <summary>
 16    /// Returns the deepest finite circle/capsule face witnesses. The caller
 17    /// supplies nonnegative dimensions and bounded mover-relative witnesses;
 18    /// origins may span the full scalar domain. A wholly buried body requires
 19    /// a separate recovery path rather than a remote supporting-plane contact.
 20    /// Plane admission may be borrowed only from an actual crossing of the
 21    /// same oriented plane in a positively connected declared surface.
 22    /// </summary>
 23    internal static int GetCapsuleBoundaryFaceContacts(Vector2d moverOrigin, Fixed64 moverRotation,
 24        Fixed64 coreLength, Fixed64 radius, Vector2d targetOrigin, Fixed64 targetRotation,
 25        FixedSegment2d edge, Vector2d inward, in RationalSegmentInterval clip,
 26        Span<FixedContactAnchors2d> contacts, bool planeAdmitted = false)
 27    {
 2428        if (contacts.Length < 2) throw new ArgumentException("Two contact slots are required.", nameof(contacts));
 2329        if (clip.HasWideBounds) throw new ArgumentException("Planar coverage bounds must fit Signed320.", nameof(clip));
 2130        RotationFrame2d frame = new(targetRotation);
 2131        GetTransformedEdge(frame, edge.Start, edge.End, out Signed192 ex, out Signed192 ey);
 2132        Signed320 squared = WideArithmetic.AddProducts(ex, ex, ey, ey);
 2233        if (squared.IsZero) return 0;
 2034        GetTransformedEdge(frame, edge.Start, inward, out Signed192 ix, out Signed192 iy);
 2035        WideAxis2d normal = new(WideArithmetic.Negate(ey), ex);
 2036        int orientation = WideArithmetic.AddProducts(normal.X, ix, normal.Y, iy).Sign;
 2137        if (orientation == 0) return 0;
 3438        if (orientation < 0) normal = -normal;
 1939        GetRelativePointNumerators(targetOrigin, targetRotation, edge.Start, moverOrigin, out Signed192 ax, out Signed19
 1940        Signed320 centerU = WideArithmetic.Negate(WideArithmetic.AddProducts(ax, ex, ay, ey));
 1941        Signed320 centerV = WideArithmetic.Negate(WideArithmetic.AddProducts(ax, normal.X, ay, normal.Y));
 3842        Signed320 du = default, dv = default;
 1943        bool hasCore = coreLength != Fixed64.Zero;
 1944        if (hasCore)
 45        {
 946            _ = Vector2d.TryRotate(Vector2d.Forward, moverRotation, out Vector2d axis);
 947            Signed192 cx = Signed192.NarrowValue(WideArithmetic.MultiplySigned192(Signed192.Raw(coreLength), Signed192.R
 948            Signed192 cy = Signed192.NarrowValue(WideArithmetic.MultiplySigned192(Signed192.Raw(coreLength), Signed192.R
 1849            du = WideArithmetic.AddProducts(cx, ex, cy, ey); dv = WideArithmetic.AddProducts(cx, normal.X, cy, normal.Y)
 50        }
 1951        Signed192 r = Signed192.NarrowValue(WideArithmetic.MultiplySigned192(Signed192.Raw(radius), Signed192.One));
 1952        Signed576 radialSquared = WideArithmetic.MultiplySigned320(WideArithmetic.MultiplySigned192(r, r), squared);
 53        // All coordinates share the exact scalar Sin/Cos chart. Doubled core
 54        // centers retain odd raw lengths; no clipped endpoint is materialized.
 1955        Span<ulong> values = stackalloc ulong[18 * 2 * CapsuleFaceCandidates.Words];
 1956        Span<int> signs = stackalloc int[18 * 2];
 1957        Span<ulong> roots = stackalloc ulong[3 * CapsuleFaceCandidates.Words];
 1958        var candidates = new CapsuleFaceCandidates(values, signs, roots, squared, clip);
 1959        Signed320 u0 = WideArithmetic.SubtractSigned320(WideArithmetic.AddSigned320(centerU, centerU), du);
 1960        Signed320 v0 = WideArithmetic.SubtractSigned320(WideArithmetic.AddSigned320(centerV, centerV), dv);
 1961        candidates.AddDisk(u0, v0, radialSquared);
 1962        if (hasCore)
 63        {
 964            candidates.AddDisk(WideArithmetic.AddSigned320(WideArithmetic.AddSigned320(centerU, centerU), du),
 965                WideArithmetic.AddSigned320(WideArithmetic.AddSigned320(centerV, centerV), dv), radialSquared);
 966            candidates.AddSides(u0, v0, du, dv, radialSquared);
 67        }
 2668        if (!candidates.HasContact(planeAdmitted)) return 0;
 1269        Vector2d direction = WideNormalization.GetNormalized(normal.X, normal.Y);
 1270        contacts[0] = candidates.Materialize(6, moverOrigin, targetOrigin, targetRotation, edge, ex, ey, normal, ax, ay,
 2071        if (!candidates.HasTwo) return 1;
 472        contacts[1] = candidates.Materialize(9, moverOrigin, targetOrigin, targetRotation, edge, ex, ey, normal, ax, ay,
 473        return 2;
 74    }
 75
 76    private ref struct CapsuleFaceCandidates
 77    {
 78        // Full-domain point/edge projections need <200 bits, core projections
 79        // <230 and retained cut bounds <320. Radicands need <1040 bits and
 80        // fields <1120; 1280-bit banks retain all complete transient products.
 81        internal const int Words = 20;
 82        private readonly Span<ulong> _values, _roots;
 83        private readonly Span<int> _signs;
 84        private readonly Signed320 _squared, _lowerD, _upperD;
 85        private readonly Signed576 _lower, _upper;
 86        private bool _found, _outside;
 1987        internal bool HasContact(bool planeAdmitted) => _found && (_outside || planeAdmitted);
 1288        internal bool HasTwo => ContactQuadratic.CompareRatios(Q(6), Q(8), Root(1), Q(9), Q(11), Root(2)) != 0;
 452289        private ContactQuadratic Q(int index) => ContactQuadratic.At(_values, _signs, index, Words);
 51190        private Span<ulong> Root(int index) => _roots.Slice(index * Words, Words);
 91
 92        internal CapsuleFaceCandidates(Span<ulong> values, Span<int> signs, Span<ulong> roots,
 93            Signed320 squared, in RationalSegmentInterval clip)
 94        {
 7695            _values = values; _signs = signs; _roots = roots; _squared = squared;
 1996            _lowerD = clip.IsClipped ? clip.LowerDenominator : Signed320.One;
 1997            _upperD = clip.IsClipped ? clip.UpperDenominator : Signed320.One;
 1998            _lower = WideArithmetic.MultiplySigned320(squared, clip.IsClipped ? clip.LowerNumerator : default);
 1999            _upper = WideArithmetic.MultiplySigned320(squared, clip.IsClipped ? clip.UpperNumerator : Signed320.One);
 19100            _found = _outside = false;
 19101        }
 102
 103        internal void AddDisk(Signed320 u, Signed320 v, Signed576 radialSquared)
 104        {
 168105            for (int branch = -1; branch <= 1; branch += 2)
 106            {
 168107                Q(0).Set(Signed576.ExtendValue(u)); Q(1).Set(Signed576.ExtendValue(v)); Q(2).Set(Integer(2));
 56108                SetRoot(WideArithmetic.MultiplySigned576(radialSquared, 4));
 112109                Q(1).Radical[0] = 1; Q(1).Signs[1] = branch;
 56110                Keep();
 111            }
 168112            for (int bound = 0; bound < 2; bound++)
 113            {
 56114                Signed320 d = bound == 0 ? _lowerD : _upperD;
 56115                Signed576 cut = bound == 0 ? _lower : _upper;
 56116                Q(12).Set(WideArithmetic.MultiplySigned576(cut, 2));
 112117                Q(13).Set(WideArithmetic.MultiplySigned320(u, d)); Q(12).Add(Q(13), -1);
 56118                Q(13).Set(Signed576.ExtendValue(d));
 56119                ContactQuadratic.Multiply(Q(13), Q(13), ReadOnlySpan<ulong>.Empty, Q(14));
 56120                ContactQuadratic.Scale(Q(14), WideArithmetic.MultiplySigned576(radialSquared, 4), Q(15));
 112121                ContactQuadratic.Multiply(Q(12), Q(12), ReadOnlySpan<ulong>.Empty, Q(14)); Q(15).Add(Q(14), -1);
 56122                if (Q(15).Signs[0] < 0) continue;
 12123                Q(15).Rational.CopyTo(Root(0));
 72124                for (int branch = -1; branch <= 1; branch += 2)
 125                {
 24126                    Q(0).Set(WideArithmetic.MultiplySigned576(cut, 2));
 72127                    Q(1).Set(WideArithmetic.MultiplySigned320(v, d)); Q(1).Radical[0] = 1; Q(1).Signs[1] = branch;
 24128                    Q(2).Set(WideArithmetic.MultiplySigned576(Signed576.ExtendValue(d), 2));
 24129                    Keep();
 130                }
 131            }
 28132        }
 133
 134        internal void AddSides(Signed320 u, Signed320 v, Signed320 du, Signed320 dv, Signed576 radialSquared)
 135        {
 13136            if (du.IsZero) return; // Vertical sides have no interior tangent-cut extremum.
 5137            Signed576 h = WideArithmetic.AddSigned576(WideArithmetic.MultiplySigned320(du, du), WideArithmetic.MultiplyS
 10138            Q(12).Set(h); Q(13).Set(radialSquared);
 10139            ContactQuadratic.Multiply(Q(12), Q(13), ReadOnlySpan<ulong>.Empty, Q(14)); Q(14).Rational.CopyTo(Root(0));
 30140            for (int bound = 0; bound < 2; bound++)
 60141            for (int side = -1; side <= 1; side += 2)
 142            {
 20143                Signed320 d = bound == 0 ? _lowerD : _upperD;
 20144                Signed576 cut = bound == 0 ? _lower : _upper;
 145                // q=(cut-u/2+side*dv*sqrt(QH)/H)/du must stay on
 146                // the finite core. Its two signed tests retain the radical.
 60147                Q(12).Set(WideArithmetic.MultiplySigned576(cut, 2)); Q(13).Set(WideArithmetic.MultiplySigned320(u, d)); 
 20148                ContactQuadratic.Scale(Q(12), h, Q(15));
 20149                Q(13).Set(WideArithmetic.MultiplySigned576(WideArithmetic.MultiplySigned320(dv, d), side * 2));
 40150                Q(13).Rational.CopyTo(Q(15).Radical); Q(15).Signs[1] = Q(13).Signs[0];
 20151                Q(12).Set(WideArithmetic.MultiplySigned576(WideArithmetic.MultiplySigned320(du, d), 2));
 20152                ContactQuadratic.Scale(Q(12), h, Q(16));
 44153                if (du.Sign < 0) { Q(15).MultiplySign(-1); Q(16).MultiplySign(-1); }
 20154                if (Q(15).Sign(Root(0)) < 0) continue;
 28155                Q(16).Add(Q(15), -1); if (Q(16).Sign(Root(0)) < 0) continue;
 8156                Q(0).Set(WideArithmetic.MultiplySigned576(cut, 2));
 16157                ContactQuadratic.Scale(Q(0), Signed576.ExtendValue(du), Q(12)); Q(12).CopyTo(Q(0));
 8158                Q(12).Set(WideArithmetic.SubtractSigned576(WideArithmetic.MultiplySigned320(v, du), WideArithmetic.Multi
 8159                ContactQuadratic.Scale(Q(12), Signed576.ExtendValue(d), Q(1));
 24160                Q(12).Set(WideArithmetic.MultiplySigned576(cut, 2)); ContactQuadratic.Scale(Q(12), Signed576.ExtendValue
 8161                Q(12).Set(WideArithmetic.MultiplySigned576(Signed576.ExtendValue(d), side * 2));
 16162                Q(12).Rational.CopyTo(Q(1).Radical); Q(1).Signs[1] = Q(12).Signs[0];
 8163                Q(2).Set(WideArithmetic.MultiplySigned576(WideArithmetic.MultiplySigned320(du, d), 2));
 20164                if (du.Sign < 0) { Q(0).MultiplySign(-1); Q(1).MultiplySign(-1); Q(2).MultiplySign(-1); }
 8165                Keep();
 166            }
 5167        }
 168
 169        private void Keep()
 170        {
 88171            ContactQuadratic.Scale(Q(0), Signed576.ExtendValue(_lowerD), Q(3));
 176172            ContactQuadratic.Scale(Q(2), _lower, Q(4)); Q(3).Add(Q(4), -1);
 100173            if (Q(3).Sign(Root(0)) < 0) return;
 76174            ContactQuadratic.Scale(Q(2), _upper, Q(3));
 152175            ContactQuadratic.Scale(Q(0), Signed576.ExtendValue(_upperD), Q(4)); Q(3).Add(Q(4), -1);
 90176            if (Q(3).Sign(Root(0)) < 0) return;
 62177            int sign = Q(1).Sign(Root(0));
 92178            if (sign <= 0) _outside = true;
 92179            if (sign < 0) return;
 32180            int comparison = _found ? ContactQuadratic.CompareRatios(Q(1), Q(2), Root(0), Q(7), Q(8), Root(1)) : 1;
 86181            if (comparison > 0) { _found = true; Copy(6, 1); Copy(9, 2); }
 14182            else if (comparison == 0)
 183            {
 8184                if (ContactQuadratic.CompareRatios(Q(0), Q(2), Root(0), Q(6), Q(8), Root(1)) < 0) Copy(6, 1);
 8185                if (ContactQuadratic.CompareRatios(Q(0), Q(2), Root(0), Q(9), Q(11), Root(2)) > 0) Copy(9, 2);
 186            }
 14187        }
 188
 189        private void Copy(int slot, int root)
 200190        { Q(0).CopyTo(Q(slot)); Q(1).CopyTo(Q(slot + 1)); Q(2).CopyTo(Q(slot + 2)); Root(0).CopyTo(Root(root)); }
 191
 168192        private void SetRoot(Signed576 value) { Q(17).Set(value); Q(17).Rational.CopyTo(Root(0)); }
 56193        private static Signed576 Integer(long value) => Signed576.ExtendValue(Signed320.ExtendValue(Signed192.Signed(val
 194
 195        internal FixedContactAnchors2d Materialize(int slot, Vector2d moverOrigin, Vector2d targetOrigin,
 196            Fixed64 targetRotation, FixedSegment2d edge, Signed192 ex, Signed192 ey, WideAxis2d normal,
 197            Signed192 ax, Signed192 ay, Vector2d direction)
 198        {
 16199            ReadOnlySpan<ulong> root = Root(slot == 6 ? 1 : 2);
 32200            Span<ulong> metric = stackalloc ulong[9], scale = stackalloc ulong[9];
 16201            WideArithmetic.GetMagnitude(Signed576.ExtendValue(_squared), metric);
 16202            Signed576 scaledLength = WideArithmetic.MultiplySigned320(_squared, Signed192.One);
 16203            WideArithmetic.GetMagnitude(scaledLength, scale);
 16204            bool represented = ContactQuadratic.TryRoundRootRatio(Q(slot + 1), Q(slot + 2), root, metric, scale, out Fix
 17205            if (!represented) depth = Fixed64.MaxValue;
 16206            Vector2d moving = new(Coordinate(slot, root, ex, normal.X, ax, true), Coordinate(slot, root, ey, normal.Y, a
 16207            Vector2d target = new(Coordinate(slot, root, WideArithmetic.Difference(edge.End.X, edge.Start.X), default, S
 16208                Coordinate(slot, root, WideArithmetic.Difference(edge.End.Y, edge.Start.Y), default, Signed192.Raw(edge.
 16209            return new FixedContactAnchors2d(new FixedPointAnchor2d(moverOrigin, Fixed64.Zero, moving),
 16210                new FixedPointAnchor2d(targetOrigin, targetRotation, target), direction, depth, !represented);
 211        }
 212
 213        private Fixed64 Coordinate(int slot, ReadOnlySpan<ulong> root, Signed192 tangent, Signed192 normal,
 214            Signed192 origin, bool world)
 215        {
 64216            ContactQuadratic.Scale(Q(slot), Signed576.ExtendValue(Signed320.ExtendValue(tangent)), Q(3));
 128217            ContactQuadratic.Scale(Q(slot + 1), Signed576.ExtendValue(Signed320.ExtendValue(normal)), Q(4)); Q(3).Add(Q(
 128218            ContactQuadratic.Scale(Q(slot + 2), WideArithmetic.MultiplySigned320(_squared, origin), Q(4)); Q(3).Add(Q(4)
 64219            ContactQuadratic.Scale(Q(slot + 2), world ? WideArithmetic.MultiplySigned320(_squared, Signed192.One) : Sign
 64220            return ContactQuadratic.RoundRatio(Q(3), Q(5), root);
 221        }
 222    }
 223}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.ContactVertex.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.ContactVertex.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>Exact normal admission against independently framed incident convex sectors.</content>
 13internal static partial class WideConvex2dRelations
 14{
 15    /// <summary>
 16    /// Returns a finite polygon contact with an original target vertex. All
 17    /// incident points are plain native vertex anchors; their exact inward
 18    /// rays restrict response normals before normalization or depth ranking.
 19    /// </summary>
 20    internal static bool TryGetBoundaryVertexContact(Vector2d moverOrigin, Fixed64 moverRotation,
 21        ReadOnlySpan<Vector2d> moverOffsets, in FixedPointAnchor2d vertex,
 22        ReadOnlySpan<FixedPointAnchor2d> incidentPoints, out FixedContactAnchors2d contact)
 23    {
 1024        RotationFrame2d moverFrame = new(moverRotation), targetFrame = new(vertex.Rotation);
 525        PenetrationAxis best = default;
 526        Vector2d bestPoint = default;
 3827        for (int edge = 0; edge < moverOffsets.Length; edge++)
 28        {
 1629            GetTransformedEdge(moverFrame, moverOffsets[edge], moverOffsets[(edge + 1) % moverOffsets.Length],
 1630                out Signed192 ex, out Signed192 ey);
 1631            WideAxis2d axis = new(ey, WideArithmetic.Negate(ex));
 1632            if (axis.IsZero) continue;
 1533            GetProjectionRange(moverOrigin, moverFrame, moverOffsets, axis, out Signed320 minimum, out Signed320 maximum
 1534            Signed320 point = GetProjection(vertex.Origin, targetFrame, vertex.LocalPoint, axis);
 1535            Signed320 positive = WideArithmetic.SubtractSigned320(maximum, point);
 1536            Signed320 negative = WideArithmetic.SubtractSigned320(point, minimum);
 37            // A forbidden response direction remains a valid separation axis.
 1938            if (positive.Sign < 0 || negative.Sign < 0) { contact = default; return false; }
 1339            KeepBoundaryVertexAxis(moverOrigin, moverRotation, moverOffsets, vertex, incidentPoints,
 1340                axis, positive, ref best, ref bestPoint);
 1341            KeepBoundaryVertexAxis(moverOrigin, moverRotation, moverOffsets, vertex, incidentPoints,
 1342                -axis, negative, ref best, ref bestPoint);
 43        }
 544        if (!best.HasValue) { contact = default; return false; }
 245        GetDepth(best.Overlap, best.AxisSquared, out Fixed64 depth, out bool clamped);
 246        contact = new FixedContactAnchors2d(new FixedPointAnchor2d(moverOrigin, moverRotation, bestPoint),
 247            vertex, WideNormalization.GetNormalized(best.Axis.X, best.Axis.Y), depth, clamped);
 248        return true;
 49    }
 50
 51    private static void KeepBoundaryVertexAxis(Vector2d origin, Fixed64 rotation, ReadOnlySpan<Vector2d> offsets,
 52        in FixedPointAnchor2d vertex, ReadOnlySpan<FixedPointAnchor2d> incidentPoints,
 53        WideAxis2d axis, Signed320 overlap, ref PenetrationAxis best, ref Vector2d bestPoint)
 54    {
 4455        if (!SupportsBoundaryFan(axis.X, axis.Y, vertex, incidentPoints)) return;
 856        GetSupportFeature(origin, new RotationFrame2d(rotation), offsets, axis, true, out Feature feature);
 857        if (!TryProjectAnchorOntoFeature(vertex, origin, rotation, feature.Start, feature.End,
 958            requireInteriorProjection: true, out Vector2d point)) return;
 759        Signed320 squared = WideArithmetic.AddProducts(axis.X, axis.X, axis.Y, axis.Y);
 760        Signed576 overlapSquared = WideArithmetic.MultiplySigned320(overlap, overlap);
 761        if (best.HasValue && WideArithmetic.SubtractSigned832(
 762            WideArithmetic.MultiplySigned576ToSigned832(overlapSquared, best.AxisSquared),
 1163            WideArithmetic.MultiplySigned576ToSigned832(best.OverlapSquared, squared)).Sign >= 0) return;
 364        best = new PenetrationAxis(axis, overlap, overlapSquared, squared, false);
 365        bestPoint = point;
 366    }
 67
 68    internal static bool SupportsBoundaryFan(Signed192 x, Signed192 y, in FixedPointAnchor2d vertex,
 69        ReadOnlySpan<FixedPointAnchor2d> incidentPoints)
 70    {
 3571        GetRelativePointNumerators(vertex.Origin, vertex.Rotation, vertex.LocalPoint, vertex.Origin,
 3572            out Signed192 vx, out Signed192 vy);
 18373        foreach (ref readonly FixedPointAnchor2d point in incidentPoints)
 74        {
 6875            GetRelativePointNumerators(point.Origin, point.Rotation, point.LocalPoint, vertex.Origin,
 6876                out Signed192 px, out Signed192 py);
 6877            if (WideArithmetic.AddProducts(x, WideArithmetic.SubtractSigned192(px, vx),
 9178                y, WideArithmetic.SubtractSigned192(py, vy)).Sign < 0) return false;
 79        }
 1280        return true;
 81    }
 82
 83    /// <summary>Tests an unnormalized world outward axis against the complete exact incident sectors.</summary>
 84    internal static bool SupportsBoundaryFan(in WideDirection3d outward, in FixedPointAnchor2d point,
 85        ReadOnlySpan<FixedPointAnchor2d> incidentPoints)
 86    {
 487        RationalPoint3d reference = RationalPoint3d.FromAnchor(point);
 1488        foreach (ref readonly FixedPointAnchor2d incident in incidentPoints)
 489            if (WideDirection3d.Dot(outward, WideTriangleRelations.GetScaledPointDifference(
 490                RationalPoint3d.FromAnchor(incident), reference,
 691                WideArithmetic.TruncateSigned320By64(reference.Denominator))).Sign > 0) return false;
 292        return true;
 93    }
 94    /// <summary>Tests exact equality and inward orientation of two independently framed supporting lines.</summary>
 95    internal static bool SameBoundaryPlane(Vector2d origin, Fixed64 rotation, FixedSegment2d edge, Vector2d inward,
 96        Vector2d otherOrigin, Fixed64 otherRotation, FixedSegment2d otherEdge, Vector2d otherInward)
 97    {
 1898        RotationFrame2d frame = new(rotation), otherFrame = new(otherRotation);
 999        GetTransformedEdge(frame, edge.Start, edge.End, out Signed192 ex, out Signed192 ey);
 9100        GetTransformedEdge(otherFrame, otherEdge.Start, otherEdge.End, out Signed192 ox, out Signed192 oy);
 9101        if ((ex.IsZero && ey.IsZero) || (ox.IsZero && oy.IsZero)
 12102            || !WideArithmetic.MultiplySubtract(ex, oy, ey, ox).IsZero) return false;
 6103        GetRotatedOffset(frame, edge.Start, out Signed192 ax, out Signed192 ay);
 6104        GetRelativePointNumerators(otherOrigin, otherRotation, otherEdge.Start, origin, out Signed192 bx, out Signed192 
 6105        if (!WideArithmetic.MultiplySubtract(ex, WideArithmetic.SubtractSigned192(by, ay),
 7106            ey, WideArithmetic.SubtractSigned192(bx, ax)).IsZero) return false;
 5107        GetTransformedEdge(frame, edge.Start, inward, out Signed192 ix, out Signed192 iy);
 5108        GetTransformedEdge(otherFrame, otherEdge.Start, otherInward, out Signed192 jx, out Signed192 jy);
 5109        int first = WideArithmetic.MultiplySubtract(ex, iy, ey, ix).Sign;
 5110        return first != 0 && first == WideArithmetic.MultiplySubtract(ex, jy, ey, jx).Sign;
 111    }
 112
 113    /// <summary>Returns -1 outside the retained span, 0 inside, 1 at its lower endpoint, or 2 at its upper endpoint.</s
 114    internal static int LocateBoundaryPoint(in FixedPointAnchor2d point, Vector2d origin, Fixed64 rotation,
 115        FixedSegment2d edge, in RationalSegmentInterval interval)
 116    {
 21117        if (point.LocalDisplacement != Vector2d.Zero || !point.ExactLocalTerm.IsZero)
 118        {
 4119            int location = WideTriangleRelations.LocatePointOnFrameEdge(RationalPoint3d.FromAnchor(point),
 4120                new FixedSegment(new(edge.Start.X, Fixed64.Zero, edge.Start.Y), new(edge.End.X, Fixed64.Zero, edge.End.Y
 4121                new NativePrismYawFrame3d(new(origin.X, Fixed64.Zero, origin.Y), rotation), interval);
 4122            return location == 0 ? 1 : location == 1 ? 0 : location;
 123        }
 17124        GetRelativePointNumerators(point.Origin, point.Rotation, point.LocalPoint, origin, out Signed192 px, out Signed1
 17125        GetRotatedOffset(new RotationFrame2d(rotation), edge.Start, out Signed192 ax, out Signed192 ay);
 17126        GetTransformedEdge(new RotationFrame2d(rotation), edge.Start, edge.End, out Signed192 ex, out Signed192 ey);
 34127        px = WideArithmetic.SubtractSigned192(px, ax); py = WideArithmetic.SubtractSigned192(py, ay);
 18128        if (!WideArithmetic.MultiplySubtract(px, ey, py, ex).IsZero) return -1;
 16129        Signed320 d = WideArithmetic.AddProducts(ex, ex, ey, ey);
 22130        if (d.IsZero) return px.IsZero && py.IsZero ? 1 : -1;
 10131        Signed320 n = WideArithmetic.AddProducts(px, ex, py, ey);
 12132        if (n.Sign < 0 || WideArithmetic.SubtractSigned320(n, d).Sign > 0) return -1;
 8133        int lower = interval.IsClipped ? RationalSegmentInterval.CompareParameters(Signed832.ExtendValue(n), Signed832.E
 8134            interval.WideLowerNumerator, interval.WideLowerDenominator) : n.Sign;
 8135        int upper = interval.IsClipped ? RationalSegmentInterval.CompareParameters(Signed832.ExtendValue(n), Signed832.E
 8136            interval.WideUpperNumerator, interval.WideUpperDenominator) : WideArithmetic.SubtractSigned320(n, d).Sign;
 10137        if (lower < 0 || upper > 0) return -1;
 6138        return lower == 0 ? 1 : upper == 0 ? 2 : 0;
 139    }
 140}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.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>
 13/// Contains methods for computing geometric relations between convex shapes in 2D space using wide fixed-point arithmet
 14/// </summary>
 15/// <content>Owns exact planar convex projection, containment, contact and sweep relations.</content>
 16internal static partial class WideConvex2dRelations
 17{
 18    #region Nested Types
 19
 20    private readonly struct WideAxis2d
 21    {
 22        internal readonly Signed192 X;
 23        internal readonly Signed192 Y;
 24
 1252625        internal bool IsZero => X.IsZero && Y.IsZero;
 26
 27        internal WideAxis2d(Signed192 x, Signed192 y)
 28        {
 19537929            X = x;
 19537930            Y = y;
 19537931        }
 32
 33        public static WideAxis2d operator -(WideAxis2d value) =>
 213234            new(WideArithmetic.Negate(value.X), WideArithmetic.Negate(value.Y));
 35    }
 36
 37
 38
 39    private readonly struct Feature
 40    {
 41        internal readonly Vector2d Start;
 42        internal readonly Vector2d End;
 43
 50344        internal bool IsPoint => Start == End;
 45
 46        internal Feature(Vector2d start, Vector2d end)
 47        {
 107748            Start = start;
 107749            End = end;
 107750        }
 51    }
 52
 53    private readonly struct PenetrationAxis
 54    {
 55        internal readonly WideAxis2d Axis;
 56        internal readonly Signed320 Overlap;
 57        internal readonly Signed576 OverlapSquared;
 58        internal readonly Signed320 AxisSquared;
 59        internal readonly bool Negate;
 60        internal readonly bool HasValue;
 61
 62        internal PenetrationAxis(
 63            WideAxis2d axis,
 64            Signed320 overlap,
 65            Signed576 overlapSquared,
 66            Signed320 axisSquared,
 67            bool negate)
 68        {
 33469            Axis = axis;
 33470            Overlap = overlap;
 33471            OverlapSquared = overlapSquared;
 33472            AxisSquared = axisSquared;
 33473            Negate = negate;
 33474            HasValue = true;
 33475        }
 76    }
 77
 78    #endregion
 79
 80    /// <summary>Tests exact closed contact or strict penetration without rounding a normal or contact depth.</summary>
 81    internal static bool DoConvexesOverlap(Vector2d firstOrigin, Fixed64 firstRotation, ReadOnlySpan<Vector2d> firstOffs
 82        Vector2d secondOrigin, Fixed64 secondRotation, ReadOnlySpan<Vector2d> secondOffsets, bool strict = true)
 83    {
 4484        RotationFrame2d firstFrame = new(firstRotation), secondFrame = new(secondRotation);
 2285        PenetrationAxis best = default;
 2286        if (!TryKeepAxes(firstOrigin, firstFrame, firstOffsets, secondOrigin, secondFrame, secondOffsets, true, ref best
 2587            || !TryKeepAxes(secondOrigin, secondFrame, secondOffsets, firstOrigin, firstFrame, firstOffsets, false, ref 
 1988        if (GetPlanarSweepWinding(firstOffsets) == 0 && GetPlanarSweepWinding(secondOffsets) == 0
 1989            && (!TryKeepAxis(new(Signed192.One, default), firstOrigin, firstFrame, firstOffsets,
 1990                secondOrigin, secondFrame, secondOffsets, true, ref best)
 1991                || !TryKeepAxis(new(default, Signed192.One), firstOrigin, firstFrame, firstOffsets,
 2392                    secondOrigin, secondFrame, secondOffsets, true, ref best))) return false;
 1593        return strict ? best.Overlap.Sign > 0 : best.Overlap.Sign >= 0;
 94    }
 95
 96    internal static FixedBoundArea GetBoundsClippedToDomain(
 97        Vector2d origin,
 98        Fixed64 rotation,
 99        ReadOnlySpan<Vector2d> vertexOffsets)
 100    {
 2101        RotationFrame2d rotationFrame = new(rotation);
 2102        GetWorldPoint(
 2103            origin,
 2104            rotationFrame,
 2105            vertexOffsets[0],
 2106            Vector2d.Zero,
 2107            out Signed192 minimumX,
 2108            out Signed192 minimumY);
 2109        Signed192 maximumX = minimumX;
 2110        Signed192 maximumY = minimumY;
 16111        for (int i = 1; i < vertexOffsets.Length; i++)
 112        {
 6113            GetWorldPoint(
 6114                origin,
 6115                rotationFrame,
 6116                vertexOffsets[i],
 6117                Vector2d.Zero,
 6118                out Signed192 x,
 6119                out Signed192 y);
 6120            if (WideArithmetic.SubtractSigned192(x, minimumX).Sign < 0)
 2121                minimumX = x;
 6122            if (WideArithmetic.SubtractSigned192(x, maximumX).Sign > 0)
 1123                maximumX = x;
 6124            if (WideArithmetic.SubtractSigned192(y, minimumY).Sign < 0)
 1125                minimumY = y;
 6126            if (WideArithmetic.SubtractSigned192(y, maximumY).Sign > 0)
 2127                maximumY = y;
 128        }
 129
 2130        Signed192 denominator = Signed192.One;
 2131        return FixedBoundArea.FromMinMax(
 2132            new Vector2d(
 2133                WideGeometry.GetRationalBoundClippedToDomain(
 2134                    Signed320.ExtendValue(minimumX),
 2135                    denominator,
 2136                    minimum: true),
 2137                WideGeometry.GetRationalBoundClippedToDomain(
 2138                    Signed320.ExtendValue(minimumY),
 2139                    denominator,
 2140                    minimum: true)),
 2141            new Vector2d(
 2142                WideGeometry.GetRationalBoundClippedToDomain(
 2143                    Signed320.ExtendValue(maximumX),
 2144                    denominator,
 2145                    minimum: false),
 2146                WideGeometry.GetRationalBoundClippedToDomain(
 2147                    Signed320.ExtendValue(maximumY),
 2148                    denominator,
 2149                    minimum: false)));
 150    }
 151
 152    internal static Vector2d GetTransformedEdgeDirection(
 153        Fixed64 rotation,
 154        Vector2d start,
 155        Vector2d end)
 156    {
 1590157        GetTransformedEdge(
 1590158            new RotationFrame2d(rotation),
 1590159            start,
 1590160            end,
 1590161            out Signed192 x,
 1590162            out Signed192 y);
 1590163        return WideNormalization.GetNormalized(x, y);
 164    }
 165
 166    internal static void GetRelativePointNumerators(
 167        Vector2d pointOrigin,
 168        Fixed64 pointRotation,
 169        Vector2d pointLocalOffset,
 170        Vector2d referenceOrigin,
 171        out Signed192 x,
 172        out Signed192 y)
 173    {
 144192174        GetWorldPoint(
 144192175            pointOrigin,
 144192176            new RotationFrame2d(pointRotation),
 144192177            pointLocalOffset,
 144192178            Vector2d.Zero,
 144192179            out Signed192 pointX,
 144192180            out Signed192 pointY);
 144192181        GetWorldPoint(
 144192182            referenceOrigin,
 144192183            RotationFrame2d.Identity,
 144192184            Vector2d.Zero,
 144192185            Vector2d.Zero,
 144192186            out Signed192 referenceX,
 144192187            out Signed192 referenceY);
 144192188        x = WideArithmetic.SubtractSigned192(pointX, referenceX);
 144192189        y = WideArithmetic.SubtractSigned192(pointY, referenceY);
 144192190    }
 191
 192    internal static bool IsStrictlyConvex(
 193        ReadOnlySpan<Vector2d> vertexOffsets)
 194    {
 5195        int winding = 0;
 32196        for (int index = 0; index < vertexOffsets.Length; index++)
 197        {
 13198            Vector2d first = vertexOffsets[index];
 13199            Vector2d second = vertexOffsets[
 13200                index + 1 == vertexOffsets.Length ? 0 : index + 1];
 13201            Vector2d third = vertexOffsets[
 13202                index + 2 >= vertexOffsets.Length
 13203                    ? index + 2 - vertexOffsets.Length
 13204                    : index + 2];
 13205            Signed192 firstEdgeX = WideArithmetic.Difference(second.X, first.X);
 13206            Signed192 firstEdgeY = WideArithmetic.Difference(second.Y, first.Y);
 13207            Signed192 secondEdgeX = WideArithmetic.Difference(third.X, second.X);
 13208            Signed192 secondEdgeY = WideArithmetic.Difference(third.Y, second.Y);
 13209            Signed320 cross = WideArithmetic.SubtractSigned320(
 13210                WideArithmetic.MultiplySigned192(firstEdgeX, secondEdgeY),
 13211                WideArithmetic.MultiplySigned192(firstEdgeY, secondEdgeX));
 13212            int sign = cross.Sign;
 13213            if (sign == 0)
 1214                return false;
 12215            if (winding == 0)
 4216                winding = sign;
 8217            else if (sign != winding)
 1218                return false;
 219        }
 220
 3221        return true;
 222    }
 223
 224    internal static Vector2d GetSupportOffset(
 225        ReadOnlySpan<Vector2d> vertexOffsets,
 226        Vector2d direction) =>
 2227        GetSupportOffset(
 2228            Fixed64.Zero,
 2229            vertexOffsets,
 2230            direction);
 231
 232    internal static Vector2d GetSupportOffset(
 233        Fixed64 rotation,
 234        ReadOnlySpan<Vector2d> vertexOffsets,
 235        Vector2d direction)
 236    {
 3237        RotationFrame2d rotationFrame = new(rotation);
 3238        GetDirection(direction, out WideAxis2d axis);
 3239        int bestIndex = 0;
 3240        Signed320 bestProjection = GetProjection(
 3241            Vector2d.Zero,
 3242            rotationFrame,
 3243            vertexOffsets[0],
 3244            axis);
 24245        for (int i = 1; i < vertexOffsets.Length; i++)
 246        {
 9247            Signed320 projection = GetProjection(
 9248                Vector2d.Zero,
 9249                rotationFrame,
 9250                vertexOffsets[i],
 9251                axis);
 9252            if (WideArithmetic.SubtractSigned320(
 9253                    projection,
 9254                    bestProjection).Sign <= 0)
 255            {
 256                continue;
 257            }
 258
 1259            bestIndex = i;
 1260            bestProjection = projection;
 261        }
 262
 3263        return vertexOffsets[bestIndex];
 264    }
 265
 266    internal static Vector2d GetClosestPointOffset(
 267        Vector2d pointOrigin,
 268        Vector2d pointOriginOffset,
 269        Vector2d convexOrigin,
 270        ReadOnlySpan<Vector2d> convexVertexOffsets) =>
 1271        GetClosestPointOffset(
 1272            pointOrigin,
 1273            pointOriginOffset,
 1274            convexOrigin,
 1275            Fixed64.Zero,
 1276            convexVertexOffsets);
 277
 278    internal static Vector2d GetClosestPointOffset(
 279        Vector2d pointOrigin,
 280        Vector2d pointOriginOffset,
 281        Vector2d convexOrigin,
 282        Fixed64 convexRotation,
 283        ReadOnlySpan<Vector2d> convexVertexOffsets)
 284    {
 2285        RotationFrame2d convexFrame = new(convexRotation);
 2286        Vector2d start = convexVertexOffsets[0];
 2287        Vector2d end = convexVertexOffsets[1];
 2288        _ = TryProjectPointOntoFeature(
 2289            pointOrigin,
 2290            pointOriginOffset,
 2291            convexOrigin,
 2292            convexFrame,
 2293            start,
 2294            end,
 2295            requireInteriorProjection: false,
 2296            out Vector2d convexPointOffset);
 2297        Signed320 bestSquaredDistance = GetSquaredDistance(
 2298            pointOrigin,
 2299            pointOriginOffset,
 2300            convexOrigin,
 2301            convexFrame,
 2302            convexPointOffset);
 16303        for (int i = 1; i < convexVertexOffsets.Length; i++)
 304        {
 6305            start = convexVertexOffsets[i];
 6306            end = convexVertexOffsets[
 6307                i + 1 == convexVertexOffsets.Length ? 0 : i + 1];
 6308            _ = TryProjectPointOntoFeature(
 6309                pointOrigin,
 6310                pointOriginOffset,
 6311                convexOrigin,
 6312                convexFrame,
 6313                start,
 6314                end,
 6315                requireInteriorProjection: false,
 6316                out Vector2d candidateOffset);
 317
 6318            Signed320 squaredDistance = GetSquaredDistance(
 6319                pointOrigin,
 6320                pointOriginOffset,
 6321                convexOrigin,
 6322                convexFrame,
 6323                candidateOffset);
 6324            if (WideArithmetic.SubtractSigned320(
 6325                    squaredDistance,
 6326                    bestSquaredDistance).Sign >= 0)
 327            {
 328                continue;
 329            }
 330
 3331            bestSquaredDistance = squaredDistance;
 3332            convexPointOffset = candidateOffset;
 333        }
 334
 2335        return convexPointOffset;
 336    }
 337
 338    internal static Vector2d GetSweptPointTargetContactOffset(
 339        Vector2d sourceOrigin,
 340        Vector2d sourceTranslationOffset,
 341        Vector2d sourceLocalOffset,
 342        Vector2d targetOrigin,
 343        ReadOnlySpan<Vector2d> targetVertexOffsets,
 344        Vector2d targetSupportDirection) =>
 1345        GetSweptPointTargetContactOffset(
 1346            sourceOrigin,
 1347            sourceTranslationOffset,
 1348            sourceLocalOffset,
 1349            targetOrigin,
 1350            Fixed64.Zero,
 1351            targetVertexOffsets,
 1352            targetSupportDirection);
 353
 354    internal static Vector2d GetSweptPointTargetContactOffset(
 355        Vector2d sourceOrigin,
 356        Vector2d sourceTranslationOffset,
 357        Vector2d sourceLocalOffset,
 358        Vector2d targetOrigin,
 359        Fixed64 targetRotation,
 360        ReadOnlySpan<Vector2d> targetVertexOffsets,
 361        Vector2d targetSupportDirection)
 362    {
 2363        RotationFrame2d targetFrame = new(targetRotation);
 2364        GetDirection(targetSupportDirection, out WideAxis2d axis);
 2365        GetSupportFeature(
 2366            targetOrigin,
 2367            targetFrame,
 2368            targetVertexOffsets,
 2369            axis,
 2370            maximum: true,
 2371            out Feature targetFeature);
 2372        _ = TryProjectPointOntoFeature(
 2373            sourceOrigin,
 2374            RotationFrame2d.Identity,
 2375            sourceLocalOffset,
 2376            Vector2d.Zero,
 2377            sourceTranslationOffset,
 2378            targetOrigin,
 2379            targetFrame,
 2380            targetFeature.Start,
 2381            targetFeature.End,
 2382            requireInteriorProjection: false,
 2383            out Vector2d targetContactOffset);
 2384        return targetContactOffset;
 385    }
 386
 387    internal static Vector2d GetSweptAnchorTargetContactOffset(
 388        in FixedPointAnchor2d source,
 389        Vector2d sourceTranslationOffset,
 390        Vector2d targetOrigin,
 391        Fixed64 targetRotation,
 392        ReadOnlySpan<Vector2d> targetVertexOffsets,
 393        Vector2d targetSupportDirection)
 394    {
 149395        RotationFrame2d targetFrame = new(targetRotation);
 149396        GetDirection(targetSupportDirection, out WideAxis2d axis);
 149397        GetSupportFeature(
 149398            targetOrigin,
 149399            targetFrame,
 149400            targetVertexOffsets,
 149401            axis,
 149402            maximum: true,
 149403            out Feature targetFeature);
 149404        _ = TryProjectPointOntoFeature(
 149405            source.Origin,
 149406            new RotationFrame2d(source.Rotation),
 149407            source.LocalPoint,
 149408            source.LocalDisplacement,
 149409            sourceTranslationOffset,
 149410            targetOrigin,
 149411            targetFrame,
 149412            targetFeature.Start,
 149413            targetFeature.End,
 149414            requireInteriorProjection: false,
 149415            out Vector2d targetContactOffset,
 149416            source.ExactLocalTerm);
 149417        return targetContactOffset;
 418    }
 419
 420    internal static bool ContainsPoint(
 421        Vector2d point,
 422        Vector2d convexOrigin,
 423        Fixed64 convexRotation,
 424        ReadOnlySpan<Vector2d> convexVertexOffsets)
 425    {
 1675426        if (convexRotation == Fixed64.Zero)
 1398427            return ContainsPointUnrotated(point, convexOrigin, convexVertexOffsets);
 428
 277429        RotationFrame2d convexFrame = new(convexRotation);
 430        // Widen before subtracting: the point-to-origin displacement can exceed
 431        // the scalar domain. Keep it at the rotated vertices' product scale.
 277432        Signed192 relativePointX = WideArithmetic.SubtractSigned192(
 277433            WideArithmetic.Scale(point.X),
 277434            WideArithmetic.Scale(convexOrigin.X));
 277435        Signed192 relativePointY = WideArithmetic.SubtractSigned192(
 277436            WideArithmetic.Scale(point.Y),
 277437            WideArithmetic.Scale(convexOrigin.Y));
 277438        GetRotatedOffset(
 277439            convexFrame,
 277440            convexVertexOffsets[0],
 277441            out Signed192 startX,
 277442            out Signed192 startY);
 277443        bool hasPositive = false;
 277444        bool hasNegative = false;
 2360445        for (int i = 0; i < convexVertexOffsets.Length; i++)
 446        {
 945447            Vector2d end = convexVertexOffsets[
 945448                i + 1 == convexVertexOffsets.Length ? 0 : i + 1];
 945449            GetRotatedOffset(
 945450                convexFrame,
 945451                end,
 945452                out Signed192 endX,
 945453                out Signed192 endY);
 454            // Wide rotation is linear without rounding: R(end) - R(start)
 455            // equals R(end - start), and the next edge reuses this endpoint.
 945456            Signed192 edgeX = WideArithmetic.SubtractSigned192(endX, startX);
 945457            Signed192 edgeY = WideArithmetic.SubtractSigned192(endY, startY);
 945458            Signed192 pointX = WideArithmetic.SubtractSigned192(relativePointX, startX);
 945459            Signed192 pointY = WideArithmetic.SubtractSigned192(relativePointY, startY);
 945460            int orientation = WideArithmetic.MultiplySubtract(
 945461                edgeX,
 945462                pointY,
 945463                edgeY,
 945464                pointX).Sign;
 945465            if (orientation > 0)
 136466                hasPositive = true;
 809467            else if (orientation < 0)
 71468                hasNegative = true;
 945469            if (hasPositive && hasNegative)
 42470                return false;
 471
 903472            startX = endX;
 903473            startY = endY;
 474        }
 475
 235476        return hasPositive || hasNegative
 235477            || ContainsDegeneratePoint(point, convexOrigin, convexFrame, convexVertexOffsets);
 478    }
 479
 480    private static bool ContainsPointUnrotated(
 481        Vector2d point,
 482        Vector2d convexOrigin,
 483        ReadOnlySpan<Vector2d> convexVertexOffsets)
 484    {
 485        // At zero rotation the general determinant is this raw determinant times
 486        // 2^64, so its sign is unchanged. Widen before every subtraction: edges
 487        // need 65 signed bits and point - origin - vertex can need 66.
 1398488        Signed192 relativePointX = WideArithmetic.Difference(point.X, convexOrigin.X);
 1398489        Signed192 relativePointY = WideArithmetic.Difference(point.Y, convexOrigin.Y);
 1398490        Vector2d start = convexVertexOffsets[0];
 1398491        bool hasPositive = false;
 1398492        bool hasNegative = false;
 10222493        for (int i = 0; i < convexVertexOffsets.Length; i++)
 494        {
 4491495            Vector2d end = convexVertexOffsets[
 4491496                i + 1 == convexVertexOffsets.Length ? 0 : i + 1];
 4491497            Signed192 edgeX = WideArithmetic.Difference(end.X, start.X);
 4491498            Signed192 edgeY = WideArithmetic.Difference(end.Y, start.Y);
 4491499            Signed192 pointX = WideArithmetic.SubtractSigned192(relativePointX, Signed192.Raw(start.X));
 4491500            Signed192 pointY = WideArithmetic.SubtractSigned192(relativePointY, Signed192.Raw(start.Y));
 4491501            int orientation = WideArithmetic.MultiplySubtract(
 4491502                edgeX,
 4491503                pointY,
 4491504                edgeY,
 4491505                pointX).Sign;
 4491506            if (orientation > 0)
 2336507                hasPositive = true;
 2155508            else if (orientation < 0)
 1019509                hasNegative = true;
 4491510            if (hasPositive && hasNegative)
 778511                return false;
 512
 3713513            start = end;
 514        }
 515
 620516        return hasPositive || hasNegative
 620517            || ContainsDegeneratePoint(point, convexOrigin, RotationFrame2d.Identity, convexVertexOffsets);
 518    }
 519
 520    private static bool ContainsDegeneratePoint(Vector2d point, Vector2d origin,
 521        RotationFrame2d frame, ReadOnlySpan<Vector2d> offsets)
 522    {
 523        // With every edge determinant zero, coordinate bounds close the finite
 524        // collinear segment; coincident vertices additionally require both coordinates.
 1732525        for (int component = 0; component < 2; component++)
 526        {
 706527            WideAxis2d axis = component == 0
 706528                ? new(Signed192.One, default) : new(default, Signed192.One);
 706529            GetProjectionRange(origin, frame, offsets, axis, out Signed320 minimum, out Signed320 maximum);
 706530            Signed320 projection = GetProjection(point, RotationFrame2d.Identity, Vector2d.Zero, axis);
 706531            if (WideArithmetic.SubtractSigned320(projection, minimum).Sign < 0
 706532                || WideArithmetic.SubtractSigned320(maximum, projection).Sign < 0)
 303533                return false;
 534        }
 160535        return true;
 536    }
 537
 538    internal static bool TryProjectAnchorOntoFeature(
 539        in FixedPointAnchor2d source,
 540        Vector2d targetOrigin,
 541        Fixed64 targetRotation,
 542        Vector2d featureStart,
 543        Vector2d featureEnd,
 544        bool requireInteriorProjection,
 545        out Vector2d targetOffset) =>
 275546        TryProjectPointOntoFeature(
 275547            source.Origin,
 275548            new RotationFrame2d(source.Rotation),
 275549            source.LocalPoint,
 275550            source.LocalDisplacement,
 275551            Vector2d.Zero,
 275552            targetOrigin,
 275553            new RotationFrame2d(targetRotation),
 275554            featureStart,
 275555            featureEnd,
 275556            requireInteriorProjection,
 275557            out targetOffset,
 275558            source.ExactLocalTerm);
 559
 560    internal static bool TryGetContactOffsets(
 561        Vector2d firstOrigin,
 562        Fixed64 firstRotation,
 563        ReadOnlySpan<Vector2d> firstVertexOffsets,
 564        Vector2d secondOrigin,
 565        Fixed64 secondRotation,
 566        ReadOnlySpan<Vector2d> secondVertexOffsets,
 567        Span<Vector2d> firstContactOffsets,
 568        Span<Vector2d> secondContactOffsets,
 569        out int contactCount,
 570        out Vector2d normal,
 571        out Fixed64 depth,
 572        out bool depthIsClamped)
 573    {
 318574        RotationFrame2d firstFrame = new(firstRotation);
 318575        RotationFrame2d secondFrame = new(secondRotation);
 318576        var best = default(PenetrationAxis);
 318577        if (!TryKeepAxes(
 318578                firstOrigin,
 318579                firstFrame,
 318580                firstVertexOffsets,
 318581                secondOrigin,
 318582                secondFrame,
 318583                secondVertexOffsets,
 318584                sourceIsFirst: true,
 318585                ref best)
 318586            || !TryKeepAxes(
 318587                secondOrigin,
 318588                secondFrame,
 318589                secondVertexOffsets,
 318590                firstOrigin,
 318591                firstFrame,
 318592                firstVertexOffsets,
 318593                sourceIsFirst: false,
 318594                ref best)
 318595            // Edge normals alone leave collinear extent and point/point gaps
 318596            // unconstrained. Coordinate axes complete only collapsed pairs.
 318597            || (GetPlanarSweepWinding(firstVertexOffsets) == 0
 318598                && GetPlanarSweepWinding(secondVertexOffsets) == 0
 318599                && (!TryKeepAxis(new WideAxis2d(Signed192.One, default),
 318600                        firstOrigin, firstFrame, firstVertexOffsets, secondOrigin, secondFrame, secondVertexOffsets,
 318601                        sourceIsFirst: true, ref best)
 318602                    || !TryKeepAxis(new WideAxis2d(default, Signed192.One),
 318603                        firstOrigin, firstFrame, firstVertexOffsets, secondOrigin, secondFrame, secondVertexOffsets,
 318604                        sourceIsFirst: true, ref best))))
 605        {
 149606            contactCount = default;
 149607            normal = default;
 149608            depth = default;
 149609            depthIsClamped = default;
 149610            return false;
 611        }
 612
 169613        WideAxis2d orientedAxis = best.Negate ? -best.Axis : best.Axis;
 169614        normal = WideNormalization.GetNormalized(
 169615            orientedAxis.X,
 169616            orientedAxis.Y);
 169617        GetDepth(
 169618            best.Overlap,
 169619            best.AxisSquared,
 169620            out depth,
 169621            out depthIsClamped);
 169622        GetSupportFeature(
 169623            firstOrigin,
 169624            firstFrame,
 169625            firstVertexOffsets,
 169626            orientedAxis,
 169627            maximum: true,
 169628            out Feature firstFeature);
 169629        GetSupportFeature(
 169630            secondOrigin,
 169631            secondFrame,
 169632            secondVertexOffsets,
 169633            orientedAxis,
 169634            maximum: false,
 169635            out Feature secondFeature);
 169636        contactCount = 0;
 637
 169638        if (firstFeature.IsPoint && secondFeature.IsPoint)
 639        {
 4640            firstContactOffsets[0] = firstFeature.Start;
 4641            secondContactOffsets[0] = secondFeature.Start;
 4642            contactCount = 1;
 4643            return true;
 644        }
 645
 165646        if (firstFeature.IsPoint)
 647        {
 104648            _ = TryProjectPointOntoFeature(
 104649                firstOrigin,
 104650                firstFrame,
 104651                firstFeature.Start,
 104652                Vector2d.Zero,
 104653                Vector2d.Zero,
 104654                secondOrigin,
 104655                secondFrame,
 104656                secondFeature.Start,
 104657                secondFeature.End,
 104658                requireInteriorProjection: false,
 104659                out Vector2d secondOffset);
 660
 104661            firstContactOffsets[0] = firstFeature.Start;
 104662            secondContactOffsets[0] = secondOffset;
 104663            contactCount = 1;
 104664            return true;
 665        }
 666
 61667        if (secondFeature.IsPoint)
 668        {
 43669            _ = TryProjectPointOntoFeature(
 43670                secondOrigin,
 43671                secondFrame,
 43672                secondFeature.Start,
 43673                Vector2d.Zero,
 43674                Vector2d.Zero,
 43675                firstOrigin,
 43676                firstFrame,
 43677                firstFeature.Start,
 43678                firstFeature.End,
 43679                requireInteriorProjection: false,
 43680                out Vector2d firstOffset);
 681
 43682            firstContactOffsets[0] = firstOffset;
 43683            secondContactOffsets[0] = secondFeature.Start;
 43684            contactCount = 1;
 43685            return true;
 686        }
 687
 18688        AddProjectedEndpoint(
 18689            secondOrigin,
 18690            secondFrame,
 18691            secondFeature.Start,
 18692            firstOrigin,
 18693            firstFrame,
 18694            firstFeature,
 18695            sourceIsFirst: false,
 18696            firstContactOffsets,
 18697            secondContactOffsets,
 18698            ref contactCount);
 18699        AddProjectedEndpoint(
 18700            secondOrigin,
 18701            secondFrame,
 18702            secondFeature.End,
 18703            firstOrigin,
 18704            firstFrame,
 18705            firstFeature,
 18706            sourceIsFirst: false,
 18707            firstContactOffsets,
 18708            secondContactOffsets,
 18709            ref contactCount);
 18710        AddProjectedEndpoint(
 18711            firstOrigin,
 18712            firstFrame,
 18713            firstFeature.Start,
 18714            secondOrigin,
 18715            secondFrame,
 18716            secondFeature,
 18717            sourceIsFirst: true,
 18718            firstContactOffsets,
 18719            secondContactOffsets,
 18720            ref contactCount);
 18721        AddProjectedEndpoint(
 18722            firstOrigin,
 18723            firstFrame,
 18724            firstFeature.End,
 18725            secondOrigin,
 18726            secondFrame,
 18727            secondFeature,
 18728            sourceIsFirst: true,
 18729            firstContactOffsets,
 18730            secondContactOffsets,
 18731            ref contactCount);
 732        // Overlapping closed convex support segments have overlapping
 733        // tangential intervals, so at least one endpoint projection is
 734        // necessarily retained by the four exact checks above.
 18735        return true;
 736    }
 737
 738    internal static bool TryGetAreaAndCentroid(
 739        ReadOnlySpan<Vector2d> vertices,
 740        out Fixed64 area,
 741        out Vector2d centroid)
 742    {
 133743        bool result = TryGetSignedDoubleAreaAndCentroid(
 133744            vertices,
 133745            out Signed320 signedDoubleArea,
 133746            out centroid);
 133747        Signed320 absoluteDoubleArea = signedDoubleArea.Sign < 0
 133748            ? WideArithmetic.SubtractSigned320(
 133749                default,
 133750                signedDoubleArea)
 133751            : signedDoubleArea;
 133752        Signed192 doubledFixedScale =
 133753            WideArithmetic.AddSigned192(
 133754                Signed192.One,
 133755                Signed192.One);
 133756        if (!Fixed64.TryGetSignedRawRatio(
 133757                Signed576.ExtendValue(absoluteDoubleArea),
 133758                Signed576.ExtendValue(
 133759                    Signed320.ExtendValue(doubledFixedScale)),
 133760                out area))
 761        {
 1762            area = Fixed64.MaxValue;
 763        }
 133764        return result;
 765    }
 766
 767    internal static bool TryGetSignedDoubleAreaAndCentroid(
 768        ReadOnlySpan<Vector2d> vertices,
 769        out Signed320 signedDoubleArea,
 770        out Vector2d centroid)
 771    {
 133772        Vector2d anchor = vertices[0];
 133773        signedDoubleArea = default;
 133774        Signed576 weightedX = default;
 133775        Signed576 weightedY = default;
 538776        for (int i = 1; i < vertices.Length - 1; i++)
 777        {
 136778            Signed192 ax = WideArithmetic.SubtractSigned192(
 136779                Signed192.Raw(vertices[i].X),
 136780                Signed192.Raw(anchor.X));
 136781            Signed192 ay = WideArithmetic.SubtractSigned192(
 136782                Signed192.Raw(vertices[i].Y),
 136783                Signed192.Raw(anchor.Y));
 136784            Signed192 bx = WideArithmetic.SubtractSigned192(
 136785                Signed192.Raw(vertices[i + 1].X),
 136786                Signed192.Raw(anchor.X));
 136787            Signed192 by = WideArithmetic.SubtractSigned192(
 136788                Signed192.Raw(vertices[i + 1].Y),
 136789                Signed192.Raw(anchor.Y));
 136790            Signed320 cross = WideArithmetic.SubtractSigned320(
 136791                WideArithmetic.MultiplySigned192(ax, by),
 136792                WideArithmetic.MultiplySigned192(ay, bx));
 136793            signedDoubleArea =
 136794                WideArithmetic.AddSigned320(signedDoubleArea, cross);
 136795            weightedX = WideArithmetic.AddSigned576(
 136796                weightedX,
 136797                WideArithmetic.MultiplySigned320(
 136798                    Signed320.ExtendValue(
 136799                        WideArithmetic.AddSigned192(ax, bx)),
 136800                    cross));
 136801            weightedY = WideArithmetic.AddSigned576(
 136802                weightedY,
 136803                WideArithmetic.MultiplySigned320(
 136804                    Signed320.ExtendValue(
 136805                        WideArithmetic.AddSigned192(ay, by)),
 136806                    cross));
 807        }
 808
 133809        int areaSign = signedDoubleArea.Sign;
 133810        if (areaSign == 0)
 811        {
 1812            centroid = default;
 1813            return false;
 814        }
 815
 816        // The signed area can require more than one word. Multiplication by
 817        // three is therefore performed directly at the five-word width.
 132818        Signed320 centroidDenominator = WideArithmetic.AddSigned320(
 132819            WideArithmetic.AddSigned320(
 132820                signedDoubleArea,
 132821                signedDoubleArea),
 132822            signedDoubleArea);
 132823        Signed576 denominator =
 132824            Signed576.ExtendValue(centroidDenominator);
 132825        Signed576 centroidXNumerator = WideArithmetic.AddSigned576(
 132826            WideArithmetic.MultiplySigned320(
 132827                Signed320.ExtendValue(Signed192.Raw(anchor.X)),
 132828                centroidDenominator),
 132829            weightedX);
 132830        Signed576 centroidYNumerator = WideArithmetic.AddSigned576(
 132831            WideArithmetic.MultiplySigned320(
 132832                Signed320.ExtendValue(Signed192.Raw(anchor.Y)),
 132833                centroidDenominator),
 132834            weightedY);
 835        // A centroid remains inside the convex hull of representable inputs.
 132836        _ = Fixed64.TryGetSignedRawRatio(
 132837            centroidXNumerator,
 132838            denominator,
 132839            out Fixed64 x);
 132840        _ = Fixed64.TryGetSignedRawRatio(
 132841            centroidYNumerator,
 132842            denominator,
 132843            out Fixed64 y);
 132844        centroid = new Vector2d(x, y);
 132845        return true;
 846    }
 847
 848    private static bool TryKeepAxes(
 849        Vector2d axisSourceOrigin,
 850        RotationFrame2d axisSourceRotation,
 851        ReadOnlySpan<Vector2d> axisSourceOffsets,
 852        Vector2d otherOrigin,
 853        RotationFrame2d otherRotation,
 854        ReadOnlySpan<Vector2d> otherOffsets,
 855        bool sourceIsFirst,
 856        ref PenetrationAxis best)
 857    {
 4376858        for (int i = 0; i < axisSourceOffsets.Length; i++)
 859        {
 1774860            Vector2d start = axisSourceOffsets[i];
 1774861            Vector2d end = axisSourceOffsets[
 1774862                i + 1 == axisSourceOffsets.Length ? 0 : i + 1];
 1774863            GetTransformedEdge(
 1774864                axisSourceRotation,
 1774865                start,
 1774866                end,
 1774867                out Signed192 edgeX,
 1774868                out Signed192 edgeY);
 1774869            WideAxis2d axis = new(edgeY, WideArithmetic.Negate(edgeX));
 1774870            if (axis.IsZero)
 871                continue;
 961872            if (!TryKeepAxis(
 961873                    axis,
 961874                    axisSourceOrigin,
 961875                    axisSourceRotation,
 961876                    axisSourceOffsets,
 961877                    otherOrigin,
 961878                    otherRotation,
 961879                    otherOffsets,
 961880                    sourceIsFirst,
 961881                    ref best))
 882            {
 134883                return false;
 884            }
 885        }
 886
 414887        return true;
 888    }
 889
 890    private static bool TryKeepAxis(
 891        WideAxis2d axis,
 892        Vector2d axisSourceOrigin,
 893        RotationFrame2d axisSourceRotation,
 894        ReadOnlySpan<Vector2d> axisSourceOffsets,
 895        Vector2d otherOrigin,
 896        RotationFrame2d otherRotation,
 897        ReadOnlySpan<Vector2d> otherOffsets,
 898        bool sourceIsFirst,
 899        ref PenetrationAxis best)
 900    {
 1303901        Vector2d firstOrigin = sourceIsFirst
 1303902            ? axisSourceOrigin
 1303903            : otherOrigin;
 1303904        ReadOnlySpan<Vector2d> firstOffsets = sourceIsFirst
 1303905            ? axisSourceOffsets
 1303906            : otherOffsets;
 1303907        RotationFrame2d firstRotation = sourceIsFirst
 1303908            ? axisSourceRotation
 1303909            : otherRotation;
 1303910        Vector2d secondOrigin = sourceIsFirst
 1303911            ? otherOrigin
 1303912            : axisSourceOrigin;
 1303913        ReadOnlySpan<Vector2d> secondOffsets = sourceIsFirst
 1303914            ? otherOffsets
 1303915            : axisSourceOffsets;
 1303916        RotationFrame2d secondRotation = sourceIsFirst
 1303917            ? otherRotation
 1303918            : axisSourceRotation;
 1303919        GetProjectionRange(
 1303920            firstOrigin,
 1303921            firstRotation,
 1303922            firstOffsets,
 1303923            axis,
 1303924            out Signed320 firstMinimum,
 1303925            out Signed320 firstMaximum);
 1303926        GetProjectionRange(
 1303927            secondOrigin,
 1303928            secondRotation,
 1303929            secondOffsets,
 1303930            axis,
 1303931            out Signed320 secondMinimum,
 1303932            out Signed320 secondMaximum);
 1303933        Signed320 positive = WideArithmetic.SubtractSigned320(
 1303934            firstMaximum,
 1303935            secondMinimum);
 1303936        Signed320 negative = WideArithmetic.SubtractSigned320(
 1303937            secondMaximum,
 1303938            firstMinimum);
 1303939        if (positive.Sign < 0 || negative.Sign < 0)
 156940            return false;
 941
 1147942        Signed320 signedCenterDifference =
 1147943            WideArithmetic.SubtractSigned320(positive, negative);
 1147944        int signedOverlapComparison = signedCenterDifference.Sign;
 1147945        bool negate = signedOverlapComparison >= 0;
 1147946        Signed320 overlap = negate ? negative : positive;
 1147947        Signed320 axisSquared = WideArithmetic.AddSigned320(
 1147948            WideArithmetic.MultiplySigned192(axis.X, axis.X),
 1147949            WideArithmetic.MultiplySigned192(axis.Y, axis.Y));
 1147950        Signed576 overlapSquared = WideArithmetic.MultiplySigned320(
 1147951            overlap,
 1147952            overlap);
 1147953        if (best.HasValue)
 954        {
 825955            Signed832 candidateScaled =
 825956                WideArithmetic.MultiplyNonNegativeToSigned832(
 825957                    Signed832.ExtendValue(overlapSquared),
 825958                    best.AxisSquared);
 825959            Signed832 bestScaled =
 825960                WideArithmetic.MultiplyNonNegativeToSigned832(
 825961                    Signed832.ExtendValue(best.OverlapSquared),
 825962                    axisSquared);
 825963            int depthComparison = WideArithmetic.SubtractSigned832(
 825964                candidateScaled,
 825965                bestScaled).Sign;
 825966            if (depthComparison >= 0)
 802967                return true;
 968
 969            // Trigonometric frames are representable approximations. Two
 970            // mathematically equal axes can therefore differ below the
 971            // observable Fixed64 depth resolution. Preserve the first authored
 972            // axis when both exact candidates narrow to the same public depth;
 973            // a representable depth still wins over a clamped tie.
 23974            GetDepth(
 23975                overlap,
 23976                axisSquared,
 23977                out Fixed64 candidateDepth,
 23978                out bool candidateDepthIsClamped);
 23979            GetDepth(
 23980                best.Overlap,
 23981                best.AxisSquared,
 23982                out Fixed64 bestDepth,
 23983                out bool bestDepthIsClamped);
 23984            if (candidateDepth == bestDepth
 23985                && !(bestDepthIsClamped
 23986                    && !candidateDepthIsClamped))
 987            {
 14988                return true;
 989            }
 990        }
 991
 331992        best = new PenetrationAxis(
 331993            axis,
 331994            overlap,
 331995            overlapSquared,
 331996            axisSquared,
 331997            negate);
 331998        return true;
 999    }
 1000}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.EdgeCoverage.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.EdgeCoverage.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>Exact independently framed convex coverage of an original planar edge.</content>
 13internal static partial class WideConvex2dRelations
 14{
 15    /// <summary>
 16    /// Clips the source edge against a convex polygon without materializing
 17    /// world vertices. Bits 1/2 denote target fill on inward's/opposite side.
 18    /// A singleton remains closed but does not fill an open neighborhood.
 19    /// Uses the same scalar Sin/Cos geometry as planar convex relations.
 20    /// </summary>
 21    internal static bool TryGetEdgeCoverage(Vector2d sourceOrigin, Fixed64 sourceRotation,
 22        FixedSegment2d source, Vector2d inward, Vector2d targetOrigin, Fixed64 targetRotation,
 23        ReadOnlySpan<Vector2d> targetOffsets, out RationalSegmentInterval interval, out int sides)
 24    {
 6225        interval = default; sides = 0;
 3226        if (targetOffsets.Length < 3) return false;
 3027        int winding = GetPlanarSweepWinding(targetOffsets);
 3128        if (winding == 0) return false;
 2929        WideAxis2d a = CoveragePoint(sourceOrigin, sourceRotation, source.Start, sourceOrigin);
 2930        WideAxis2d b = CoveragePoint(sourceOrigin, sourceRotation, source.End, sourceOrigin);
 2931        WideAxis2d edge = SubtractSweepPoint(b, a);
 2932        int inwardSide = SweepCross(edge, SubtractSweepPoint(
 2933            CoveragePoint(sourceOrigin, sourceRotation, inward, sourceOrigin), a)).Sign;
 3034        if (inwardSide == 0) return false;
 11235        Signed320 lowerN = default, lowerD = Signed320.One, upperN = Signed320.One, upperD = Signed320.One;
 2836        WideAxis2d first = CoveragePoint(targetOrigin, targetRotation, targetOffsets[0], sourceOrigin);
 21437        for (int index = 0; index < targetOffsets.Length; index++)
 38        {
 8639            WideAxis2d next = CoveragePoint(targetOrigin, targetRotation,
 8640                targetOffsets[(index + 1) % targetOffsets.Length], sourceOrigin);
 8641            WideAxis2d targetEdge = SubtractSweepPoint(next, first);
 8642            Signed320 f0 = SweepCross(targetEdge, SubtractSweepPoint(a, first));
 8643            Signed320 f1 = SweepCross(targetEdge, SubtractSweepPoint(b, first));
 16644            if (winding < 0) { f0 = WideArithmetic.Negate(f0); f1 = WideArithmetic.Negate(f1); }
 8645            if (!RationalSegmentInterval.TryClipHalfPlane(f0, f1,
 9346                ref lowerN, ref lowerD, ref upperN, ref upperD)) return false;
 7947            int side = inwardSide * SweepCross(edge, SubtractSweepPoint(first, a)).Sign;
 10448            if (side > 0) sides |= 1;
 10949            if (side < 0) sides |= 2;
 7950            first = next;
 51        }
 52        // Shared S=2^32 coordinates require fewer than 99 bits for any raw
 53        // origin/offset. Their determinants and root differences fit 200 bits;
 54        // Signed320 retains the exact unit parameter without a rounded chart.
 2155        interval = new RationalSegmentInterval(lowerN, lowerD, upperN, upperD);
 2156        return true;
 57    }
 58
 59    private static WideAxis2d CoveragePoint(Vector2d origin, Fixed64 rotation, Vector2d point, Vector2d reference)
 60    {
 20161        GetRelativePointNumerators(origin, rotation, point, reference, out Signed192 x, out Signed192 y);
 20162        return new WideAxis2d(x, y);
 63    }
 64}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.PlanarSweep.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.PlanarSweep.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>Exact continuous upright-capsule coverage in the plane.</content>
 13internal static partial class WideConvex2dRelations
 14{
 15    internal static bool IntersectsSweptUprightCapsule(
 16        Vector2d start, Vector2d end, Fixed64 axisLength, Fixed64 radius,
 17        Vector2d origin, ReadOnlySpan<Vector2d> offsets, bool strict)
 18    {
 197019        int winding = GetPlanarSweepWinding(offsets);
 197020        if (winding == 0 && strict)
 821            return false;
 22
 23        // The swept axis is [start,end] + [-axis/2,+axis/2]Forward.
 24        // Doubled raw coordinates retain odd half-axis lengths exactly.
 25        // Relative coordinates/edge differences are below 2^67 in magnitude;
 26        // dot/cross products below 2^135 and squared comparisons below 2^271.
 27        // Signed192/320/576 therefore cover the entire public scalar domain.
 196228        WideAxis2d first = new(
 196229            WideArithmetic.Double(WideArithmetic.Difference(start.X, origin.X)),
 196230            WideArithmetic.Double(WideArithmetic.Difference(start.Y, origin.Y)));
 196231        WideAxis2d last = new(
 196232            WideArithmetic.Double(WideArithmetic.Difference(end.X, origin.X)),
 196233            WideArithmetic.Double(WideArithmetic.Difference(end.Y, origin.Y)));
 196234        Signed192 length = Signed192.Raw(axisLength);
 196235        Span<WideAxis2d> core = stackalloc WideAxis2d[4];
 196236        core[0] = new(first.X, WideArithmetic.SubtractSigned192(first.Y, length));
 196237        core[1] = new(last.X, WideArithmetic.SubtractSigned192(last.Y, length));
 196238        core[2] = new(last.X, WideArithmetic.AddSigned192(last.Y, length));
 196239        core[3] = new(first.X, WideArithmetic.AddSigned192(first.Y, length));
 40
 196241        if (HasPlanarSweepCoreOverlap(core, offsets, winding, strict: strict && radius == Fixed64.Zero))
 65342            return true;
 130943        if (radius == Fixed64.Zero)
 22844            return false;
 45
 108146        Signed192 doubledRadius = WideArithmetic.Double(Signed192.Raw(radius));
 108147        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(doubledRadius, doubledRadius);
 108148        int maximumDistanceSign = strict ? -1 : 0;
 49        // Disjoint convex sets have an endpoint-to-edge closest pair.
 50        // Four edges suffice even when the core degenerates to a segment/point.
 886051        for (int i = 0; i < offsets.Length; i++)
 52        {
 361253            WideAxis2d a = DoubleSweepOffset(offsets[i]);
 361254            WideAxis2d b = DoubleSweepOffset(offsets[i + 1 == offsets.Length ? 0 : i + 1]);
 3408255            for (int j = 0; j < core.Length; j++)
 56            {
 1369257                if (IsSweepPointNearSegment(core[j], a, b, radiusSquared, maximumDistanceSign)
 1369258                    || IsSweepPointNearSegment(a, core[j], core[(j + 1) & 3], radiusSquared, maximumDistanceSign))
 26359                    return true;
 60            }
 61        }
 81862        return false;
 63    }
 64
 65    private static bool HasPlanarSweepCoreOverlap(
 66        ReadOnlySpan<WideAxis2d> core, ReadOnlySpan<Vector2d> offsets, int winding, bool strict)
 67    {
 68        // Polygon edge halfspaces need only the four core projections: O(n),
 69        // not a full polygon projection for each of its own edge normals.
 1401870        for (int i = 0; i < offsets.Length; i++)
 71        {
 607572            WideAxis2d a = DoubleSweepOffset(offsets[i]);
 607573            WideAxis2d edge = SubtractSweepPoint(
 607574                DoubleSweepOffset(offsets[i + 1 == offsets.Length ? 0 : i + 1]), a);
 607575            if (edge.IsZero)
 76                continue;
 588777            bool enters = false;
 2297678            for (int j = 0; j < core.Length; j++)
 79            {
 80                // A closed collinear boundary traverses its line in both
 81                // directions, so winding zero uses the same signs as positive winding.
 1046082                int side = SweepCross(edge, SubtractSweepPoint(core[j], a)).Sign;
 1079583                if (winding < 0) side = -side;
 1046084                if (strict ? side > 0 : side >= 0)
 85                {
 485986                    enters = true;
 485987                    break;
 88                }
 89            }
 588790            if (!enters)
 102891                return false;
 92        }
 93
 94        // Core edge normals complete ordinary polygon SAT. For a collapsed
 95        // target, coordinate axes also close finite point/parallel-segment extent.
 93496        int axisCount = winding == 0 ? 4 : 2;
 480897        for (int edgeIndex = 0; edgeIndex < axisCount; edgeIndex++)
 98        {
 175199            WideAxis2d edge = edgeIndex < 2
 1751100                ? SubtractSweepPoint(core[edgeIndex + 1], core[edgeIndex])
 1751101                : edgeIndex == 2 ? new(Signed192.One, default) : new(default, Signed192.One);
 1751102            if (edge.IsZero)
 103                continue;
 1297104            Signed320 coreMin = SweepCross(edge, core[0]);
 1297105            Signed320 coreMax = coreMin;
 10376106            for (int i = 1; i < core.Length; i++)
 3891107                IncludeSweepProjection(SweepCross(edge, core[i]), ref coreMin, ref coreMax);
 1297108            Signed320 polygonMin = SweepCross(edge, DoubleSweepOffset(offsets[0]));
 1297109            Signed320 polygonMax = polygonMin;
 10302110            for (int i = 1; i < offsets.Length; i++)
 3854111                IncludeSweepProjection(SweepCross(edge, DoubleSweepOffset(offsets[i])), ref polygonMin, ref polygonMax);
 1297112            int firstGap = WideArithmetic.SubtractSigned320(coreMax, polygonMin).Sign;
 1297113            int secondGap = WideArithmetic.SubtractSigned320(polygonMax, coreMin).Sign;
 1297114            if (strict ? firstGap <= 0 || secondGap <= 0 : firstGap < 0 || secondGap < 0)
 281115                return false;
 116        }
 653117        return true;
 118    }
 119
 120    private static bool IsSweepPointNearSegment(
 121        WideAxis2d point, WideAxis2d start, WideAxis2d end, Signed320 radiusSquared, int maximumDistanceSign)
 122    {
 27160123        WideAxis2d relative = SubtractSweepPoint(point, start);
 27160124        WideAxis2d edge = SubtractSweepPoint(end, start);
 27160125        Signed320 projection = SweepDot(relative, edge);
 27160126        Signed320 lengthSquared = SweepDot(edge, edge);
 27160127        if (projection.Sign <= 0)
 14994128            return WideArithmetic.SubtractSigned320(SweepDot(relative, relative), radiusSquared).Sign <= maximumDistance
 12166129        if (WideArithmetic.SubtractSigned320(projection, lengthSquared).Sign >= 0)
 130        {
 7367131            relative = SubtractSweepPoint(point, end);
 7367132            return WideArithmetic.SubtractSigned320(SweepDot(relative, relative), radiusSquared).Sign <= maximumDistance
 133        }
 4799134        Signed320 cross = SweepCross(edge, relative);
 4799135        return WideArithmetic.SubtractSigned576(
 4799136            WideArithmetic.MultiplySigned320(cross, cross),
 4799137            WideArithmetic.MultiplySigned320(radiusSquared, lengthSquared)).Sign <= maximumDistanceSign;
 138    }
 139
 140    internal static int GetPlanarSweepWinding(ReadOnlySpan<Vector2d> offsets)
 141    {
 142        // A fan around the first vertex also tolerates repeated edge vertices.
 13846143        WideAxis2d first = DoubleSweepOffset(offsets[0]);
 29632144        for (int i = 1; i < offsets.Length - 1; i++)
 145        {
 14236146            int sign = SweepCross(
 14236147                SubtractSweepPoint(DoubleSweepOffset(offsets[i]), first),
 14236148                SubtractSweepPoint(DoubleSweepOffset(offsets[i + 1]), first)).Sign;
 14236149            if (sign != 0)
 13266150                return sign;
 151        }
 580152        return 0;
 153    }
 154
 155    private static void IncludeSweepProjection(Signed320 value, ref Signed320 minimum, ref Signed320 maximum)
 156    {
 7745157        if (WideArithmetic.SubtractSigned320(value, minimum).Sign < 0)
 1204158            minimum = value;
 7745159        if (WideArithmetic.SubtractSigned320(value, maximum).Sign > 0)
 884160            maximum = value;
 7745161    }
 162
 66843163    private static WideAxis2d DoubleSweepOffset(Vector2d value) => new(
 66843164        WideArithmetic.Double(Signed192.Raw(value.X)), WideArithmetic.Double(Signed192.Raw(value.Y)));
 165
 108689166    private static WideAxis2d SubtractSweepPoint(WideAxis2d first, WideAxis2d second) => new(
 108689167        WideArithmetic.SubtractSigned192(first.X, second.X), WideArithmetic.SubtractSigned192(first.Y, second.Y));
 168
 169    private static Signed320 SweepCross(WideAxis2d first, WideAxis2d second) =>
 40114170        WideArithmetic.MultiplySubtract(first.X, second.Y, first.Y, second.X);
 171
 172    private static Signed320 SweepDot(WideAxis2d first, WideAxis2d second) =>
 76681173        WideArithmetic.AddProducts(first.X, second.X, first.Y, second.Y);
 174}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.ProjectionMath.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.ProjectionMath.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>
 13/// Provides high-precision projection math used for support feature
 14/// resolution and axis projection comparisons in convex 2D queries.
 15/// </content>
 16internal static partial class WideConvex2dRelations
 17{
 18    internal static void GetMinimumSupportFeature(
 19        Vector2d origin, RotationFrame2d rotation, ReadOnlySpan<Vector2d> offsets,
 20        Signed192 axisX, Signed192 axisY, out Vector2d start, out Vector2d end)
 21    {
 4422        GetSupportFeature(origin, rotation, offsets, new WideAxis2d(axisX, axisY), false, out Feature feature);
 4423        start = feature.Start;
 4424        end = feature.End;
 4425    }
 26
 27    private static void GetSupportFeature(
 28        Vector2d origin,
 29        RotationFrame2d rotation,
 30        ReadOnlySpan<Vector2d> offsets,
 31        WideAxis2d axis,
 32        bool maximum,
 33        out Feature feature)
 34    {
 107735        int bestIndex = 0;
 107736        Signed320 bestProjection = GetProjection(
 107737            origin,
 107738            rotation,
 107739            offsets[0],
 107740            axis);
 760641        for (int i = 1; i < offsets.Length; i++)
 42        {
 272643            Signed320 projection = GetProjection(
 272644                origin,
 272645                rotation,
 272646                offsets[i],
 272647                axis);
 272648            int comparison = WideArithmetic.SubtractSigned320(
 272649                projection,
 272650                bestProjection).Sign;
 272651            if ((maximum && comparison > 0)
 272652                || (!maximum && comparison < 0))
 53            {
 27554                bestProjection = projection;
 27555                bestIndex = i;
 56            }
 57        }
 58
 107759        int startIndex = bestIndex;
 107760        int count = 1;
 207961        while (count < offsets.Length)
 62        {
 177263            int previous = (startIndex + offsets.Length - 1) % offsets.Length;
 177264            if (!WideArithmetic.SubtractSigned320(
 177265                    GetProjection(origin, rotation, offsets[previous], axis), bestProjection).IsZero)
 66                break;
 100267            startIndex = previous;
 100268            count++;
 69        }
 107770        if (count == offsets.Length)
 71        {
 72            // A point or collinear boundary can tie everywhere. Its complete
 73            // support feature is the tangential span, including repeated points.
 30774            WideAxis2d tangent = new(WideArithmetic.Negate(axis.Y), axis.X);
 61475            int minimumIndex = 0, maximumIndex = 0;
 30776            Signed320 minimum = GetProjection(origin, rotation, offsets[0], tangent);
 30777            Signed320 maximumProjection = minimum;
 226278            for (int i = 1; i < offsets.Length; i++)
 79            {
 82480                Signed320 projection = GetProjection(origin, rotation, offsets[i], tangent);
 82481                if (WideArithmetic.SubtractSigned320(projection, minimum).Sign < 0)
 82                {
 19283                    minimum = projection;
 19284                    minimumIndex = i;
 85                }
 82486                if (WideArithmetic.SubtractSigned320(projection, maximumProjection).Sign > 0)
 87                {
 3688                    maximumProjection = projection;
 3689                    maximumIndex = i;
 90                }
 91            }
 30792            feature = new Feature(offsets[minimumIndex], offsets[maximumIndex]);
 30793            return;
 94        }
 95        // Extend both ends of a supporting edge. For ordinary strict polygons
 96        // this retains the existing previous->best or best->next endpoint order.
 97        // The backward scan found a non-tied vertex, which also bounds this scan.
 77098        int endIndex = bestIndex;
 43699        while (true)
 100        {
 1206101            int next = (endIndex + 1) % offsets.Length;
 1206102            if (!WideArithmetic.SubtractSigned320(
 1206103                    GetProjection(origin, rotation, offsets[next], axis), bestProjection).IsZero)
 104                break;
 436105            endIndex = next;
 106        }
 770107        feature = new Feature(offsets[startIndex], offsets[endIndex]);
 770108    }
 109
 110    private static void GetProjectionRange(
 111        Vector2d origin,
 112        RotationFrame2d rotation,
 113        ReadOnlySpan<Vector2d> offsets,
 114        WideAxis2d axis,
 115        out Signed320 minimum,
 116        out Signed320 maximum)
 117    {
 4910118        minimum = GetProjection(
 4910119            origin,
 4910120            rotation,
 4910121            offsets[0],
 4910122            axis);
 4910123        maximum = minimum;
 35618124        for (int i = 1; i < offsets.Length; i++)
 125        {
 12899126            Signed320 projection = GetProjection(
 12899127                origin,
 12899128                rotation,
 12899129                offsets[i],
 12899130                axis);
 12899131            if (WideArithmetic.SubtractSigned320(
 12899132                    projection,
 12899133                    minimum).Sign < 0)
 134            {
 1292135                minimum = projection;
 136            }
 12899137            if (WideArithmetic.SubtractSigned320(
 12899138                    projection,
 12899139                    maximum).Sign > 0)
 140            {
 2153141                maximum = projection;
 142            }
 143        }
 4910144    }
 145
 146    private static Signed320 GetProjection(
 147        Vector2d origin,
 148        RotationFrame2d rotation,
 149        Vector2d offset,
 150        WideAxis2d axis)
 151    {
 27983152        GetWorldPoint(
 27983153            origin,
 27983154            rotation,
 27983155            offset,
 27983156            Vector2d.Zero,
 27983157            out Signed192 x,
 27983158            out Signed192 y);
 27983159        return WideArithmetic.AddSigned320(
 27983160            WideArithmetic.MultiplySigned192(x, axis.X),
 27983161            WideArithmetic.MultiplySigned192(y, axis.Y));
 162    }
 163
 164    private static Signed320 GetSquaredDistance(
 165        Vector2d firstOrigin,
 166        Vector2d firstOffset,
 167        Vector2d secondOrigin,
 168        RotationFrame2d secondRotation,
 169        Vector2d secondOffset)
 170    {
 8171        GetWorldPoint(
 8172            firstOrigin,
 8173            RotationFrame2d.Identity,
 8174            firstOffset,
 8175            Vector2d.Zero,
 8176            out Signed192 firstX,
 8177            out Signed192 firstY);
 8178        GetWorldPoint(
 8179            secondOrigin,
 8180            secondRotation,
 8181            secondOffset,
 8182            Vector2d.Zero,
 8183            out Signed192 secondX,
 8184            out Signed192 secondY);
 8185        Signed192 x = WideArithmetic.SubtractSigned192(firstX, secondX);
 8186        Signed192 y = WideArithmetic.SubtractSigned192(firstY, secondY);
 8187        return WideArithmetic.AddSigned320(
 8188            WideArithmetic.MultiplySigned192(x, x),
 8189            WideArithmetic.MultiplySigned192(y, y));
 190    }
 191
 192    private static void AddProjectedEndpoint(
 193        Vector2d sourceOrigin,
 194        RotationFrame2d sourceRotation,
 195        Vector2d sourceOffset,
 196        Vector2d targetOrigin,
 197        RotationFrame2d targetRotation,
 198        Feature targetFeature,
 199        bool sourceIsFirst,
 200        Span<Vector2d> firstContactOffsets,
 201        Span<Vector2d> secondContactOffsets,
 202        ref int contactCount)
 203    {
 72204        if (contactCount == 2
 72205            || !TryProjectPointOntoFeature(
 72206                sourceOrigin,
 72207                sourceRotation,
 72208                sourceOffset,
 72209                Vector2d.Zero,
 72210                Vector2d.Zero,
 72211                targetOrigin,
 72212                targetRotation,
 72213                targetFeature.Start,
 72214                targetFeature.End,
 72215                requireInteriorProjection: true,
 72216                out Vector2d targetOffset))
 217        {
 36218            return;
 219        }
 220
 36221        Vector2d firstOffset = sourceIsFirst ? sourceOffset : targetOffset;
 36222        Vector2d secondOffset = sourceIsFirst ? targetOffset : sourceOffset;
 36223        firstContactOffsets[contactCount] = firstOffset;
 36224        secondContactOffsets[contactCount] = secondOffset;
 36225        contactCount++;
 36226    }
 227
 228    private static bool TryProjectPointOntoFeature(
 229        Vector2d sourceOrigin,
 230        Vector2d sourceOffset,
 231        Vector2d targetOrigin,
 232        RotationFrame2d targetRotation,
 233        Vector2d featureStart,
 234        Vector2d featureEnd,
 235        bool requireInteriorProjection,
 236        out Vector2d targetOffset)
 237    {
 8238        return TryProjectPointOntoFeature(
 8239            sourceOrigin,
 8240            RotationFrame2d.Identity,
 8241            sourceOffset,
 8242            Vector2d.Zero,
 8243            Vector2d.Zero,
 8244            targetOrigin,
 8245            targetRotation,
 8246            featureStart,
 8247            featureEnd,
 8248            requireInteriorProjection,
 8249            out targetOffset);
 250    }
 251
 252    private static bool TryProjectPointOntoFeature(
 253        Vector2d sourceOrigin,
 254        RotationFrame2d sourceRotation,
 255        Vector2d firstSourceOffset,
 256        Vector2d secondSourceOffset,
 257        Vector2d sourceTranslationOffset,
 258        Vector2d targetOrigin,
 259        RotationFrame2d targetRotation,
 260        Vector2d featureStart,
 261        Vector2d featureEnd,
 262        bool requireInteriorProjection,
 263        out Vector2d targetOffset,
 264        FixedPointAnchorTerm2d exactLocalTerm = default)
 265    {
 633266        GetTransformedEdge(
 633267            targetRotation,
 633268            featureStart,
 633269            featureEnd,
 633270            out Signed192 edgeX,
 633271            out Signed192 edgeY);
 633272        Signed320 denominator = WideArithmetic.AddSigned320(
 633273            WideArithmetic.MultiplySigned192(edgeX, edgeX),
 633274            WideArithmetic.MultiplySigned192(edgeY, edgeY));
 633275        if (denominator.IsZero)
 276        {
 322277            targetOffset = featureStart;
 322278            return true;
 279        }
 280
 311281        GetWorldPoint(
 311282            sourceOrigin,
 311283            sourceTranslationOffset,
 311284            sourceRotation,
 311285            firstSourceOffset,
 311286            secondSourceOffset,
 311287            out Signed192 sourceWorldX,
 311288            out Signed192 sourceWorldY);
 311289        GetWorldPoint(
 311290            targetOrigin,
 311291            targetRotation,
 311292            featureStart,
 311293            Vector2d.Zero,
 311294            out Signed192 featureWorldX,
 311295            out Signed192 featureWorldY);
 311296        Signed192 sourceX =
 311297            WideArithmetic.SubtractSigned192(
 311298                sourceWorldX,
 311299                featureWorldX);
 311300        Signed192 sourceY =
 311301            WideArithmetic.SubtractSigned192(
 311302                sourceWorldY,
 311303                featureWorldY);
 311304        Signed320 numerator = WideArithmetic.AddSigned320(
 311305            WideArithmetic.MultiplySigned192(sourceX, edgeX),
 311306            WideArithmetic.MultiplySigned192(sourceY, edgeY));
 311307        if (!exactLocalTerm.IsZero)
 308        {
 309            // The public local components are rounded; the anchor retains the
 310            // omitted feature term over 2S. Lift this existing ratio by 2S and
 311            // add its rotated residual before closed-feature admission. Cached
 312            // frame values avoid repeating trigonometry or world projection.
 23313            Signed192 residualX = Signed192.NarrowValue(WideArithmetic.MultiplySubtract(
 23314                Signed192.Signed(exactLocalTerm.X), sourceRotation.Cosine,
 23315                Signed192.Signed(exactLocalTerm.Y), sourceRotation.Sine));
 23316            Signed192 residualY = Signed192.NarrowValue(WideArithmetic.AddSigned320(
 23317                WideArithmetic.MultiplySigned192(Signed192.Signed(exactLocalTerm.X), sourceRotation.Sine),
 23318                WideArithmetic.MultiplySigned192(Signed192.Signed(exactLocalTerm.Y), sourceRotation.Cosine)));
 23319            Signed320 scale = Signed320.ExtendValue(FixedPointAnchorTerm3d.Denominator);
 23320            numerator = WideArithmetic.AddSigned320(Signed320.NarrowValue(WideArithmetic.MultiplySigned320(numerator, sc
 23321                WideArithmetic.AddSigned320(WideArithmetic.MultiplySigned192(residualX, edgeX),
 23322                    WideArithmetic.MultiplySigned192(residualY, edgeY)));
 23323            denominator = Signed320.NarrowValue(WideArithmetic.MultiplySigned320(denominator, scale));
 324            // Full raw origins/offsets keep the lifted dot products below
 325            // 234 bits and residual coordinates below 98 bits (Signed320/192).
 326        }
 311327        if (numerator.Sign < 0)
 328        {
 18329            if (requireInteriorProjection)
 330            {
 16331                targetOffset = default;
 16332                return false;
 333            }
 2334            numerator = default;
 335        }
 293336        else if (WideArithmetic.SubtractSigned320(
 293337                     numerator,
 293338                     denominator).Sign > 0)
 339        {
 14340            if (requireInteriorProjection)
 341            {
 12342                targetOffset = default;
 12343                return false;
 344            }
 2345            numerator = denominator;
 346        }
 347
 283348        targetOffset = new Vector2d(
 283349            GetProjectedOffsetCoordinate(
 283350                featureStart.X,
 283351                WideArithmetic.Difference(featureEnd.X, featureStart.X),
 283352                numerator,
 283353                denominator),
 283354            GetProjectedOffsetCoordinate(
 283355                featureStart.Y,
 283356                WideArithmetic.Difference(featureEnd.Y, featureStart.Y),
 283357                numerator,
 283358                denominator));
 283359        return true;
 360    }
 361
 362    internal static Fixed64 GetProjectedOffsetCoordinate(
 363        Fixed64 featureStart,
 364        Signed192 edge,
 365        Signed320 parameterNumerator,
 366        Signed320 parameterDenominator)
 367    {
 708368        Signed576 numerator = WideArithmetic.AddSigned576(
 708369            WideArithmetic.MultiplySigned320(
 708370                Signed320.ExtendValue(Signed192.Raw(featureStart)),
 708371                parameterDenominator),
 708372            WideArithmetic.MultiplySigned320(
 708373                Signed320.ExtendValue(edge),
 708374                parameterNumerator));
 375        // A clamped interpolation of two representable local coordinates is
 376        // itself representable; only the wide intermediate needs protection.
 708377        _ = Fixed64.TryGetSignedRawRatio(
 708378            numerator,
 708379            Signed576.ExtendValue(parameterDenominator),
 708380            out Fixed64 coordinate);
 708381        return coordinate;
 382    }
 383
 384    private static void GetDepth(
 385        Signed320 overlap,
 386        Signed320 axisSquared,
 387        out Fixed64 depth,
 388        out bool depthIsClamped)
 389    {
 217390        Signed320 scaledLength =
 217391            WideArithmetic.GetFloorSquareRootScaledByFixed64(
 217392                Signed576.ExtendValue(axisSquared));
 217393        if (!Fixed64.TryGetSignedRawRatio(
 217394                Signed576.ExtendValue(overlap),
 217395                Signed576.ExtendValue(scaledLength),
 217396                out depth))
 397        {
 14398            depth = Fixed64.MaxValue;
 14399            depthIsClamped = true;
 14400            return;
 401        }
 402
 203403        CorrectDepth(overlap, axisSquared, ref depth);
 203404        depthIsClamped = false;
 203405    }
 406
 407    private static void CorrectDepth(
 408        Signed320 overlap,
 409        Signed320 axisSquared,
 410        ref Fixed64 depth)
 411    {
 203412        if (depth == Fixed64.Zero)
 156413            return;
 414
 47415        Signed192 lowerMidpoint = WideArithmetic.SubtractSigned192(
 47416            WideArithmetic.AddSigned192(Signed192.Raw(depth), Signed192.Raw(depth)),
 47417            Signed192.Signed(1L));
 47418        int comparison = CompareDepthToTwiceRaw(
 47419            overlap,
 47420            axisSquared,
 47421            lowerMidpoint);
 47422        long adjustment = (uint)comparison >> 31;
 47423        depth = Fixed64.FromRaw(depth.m_rawValue - adjustment);
 47424    }
 425
 426    private static int CompareDepthToTwiceRaw(
 427        Signed320 overlap,
 428        Signed320 axisSquared,
 429        Signed192 twiceRaw)
 430    {
 47431        Signed320 twiceOverlap = WideArithmetic.AddSigned320(
 47432            overlap,
 47433            overlap);
 47434        Signed576 left = WideArithmetic.MultiplySigned320(
 47435            twiceOverlap,
 47436            twiceOverlap);
 47437        Signed320 thresholdSquared = WideArithmetic.MultiplySigned192(
 47438            twiceRaw,
 47439            twiceRaw);
 47440        Signed576 unscaledRight = WideArithmetic.MultiplySigned320(
 47441            thresholdSquared,
 47442            axisSquared);
 47443        Signed576 scaleSquared = WideArithmetic.MultiplySigned320(
 47444            Signed320.ExtendValue(Signed192.One),
 47445            Signed320.ExtendValue(Signed192.One));
 47446        Signed832 right = WideArithmetic.MultiplySigned576ToSigned832(
 47447            unscaledRight,
 47448            scaleSquared);
 47449        return WideArithmetic.SubtractSigned832(
 47450            Signed832.ExtendValue(left),
 47451            right).Sign;
 452    }
 453
 454    private static void GetTransformedEdge(
 455        RotationFrame2d rotation,
 456        Vector2d start,
 457        Vector2d end,
 458        out Signed192 x,
 459        out Signed192 y)
 460    {
 6226461        GetRotatedOffset(
 6226462            rotation,
 6226463            WideArithmetic.SubtractSigned192(
 6226464                Signed192.Raw(end.X),
 6226465                Signed192.Raw(start.X)),
 6226466            WideArithmetic.SubtractSigned192(
 6226467                Signed192.Raw(end.Y),
 6226468                Signed192.Raw(start.Y)),
 6226469            out x,
 6226470            out y);
 6226471    }
 472
 473    private static void GetWorldPoint(
 474        Vector2d origin,
 475        RotationFrame2d rotation,
 476        Vector2d firstLocalPoint,
 477        Vector2d secondLocalPoint,
 478        out Signed192 x,
 479        out Signed192 y) =>
 317160480        GetWorldPoint(
 317160481            origin,
 317160482            Vector2d.Zero,
 317160483            rotation,
 317160484            firstLocalPoint,
 317160485            secondLocalPoint,
 317160486            out x,
 317160487            out y);
 488
 489    private static void GetWorldPoint(
 490        Vector2d origin,
 491        Vector2d translationOffset,
 492        RotationFrame2d rotation,
 493        Vector2d firstLocalPoint,
 494        Vector2d secondLocalPoint,
 495        out Signed192 x,
 496        out Signed192 y)
 497    {
 317471498        GetRotatedOffset(
 317471499            rotation,
 317471500            firstLocalPoint,
 317471501            out Signed192 firstRotatedX,
 317471502            out Signed192 firstRotatedY);
 317471503        GetRotatedOffset(
 317471504            rotation,
 317471505            secondLocalPoint,
 317471506            out Signed192 secondRotatedX,
 317471507            out Signed192 secondRotatedY);
 317471508        x = WideArithmetic.AddSigned192(
 317471509            WideArithmetic.AddSigned192(
 317471510                WideArithmetic.AddSigned192(
 317471511                    WideArithmetic.Scale(origin.X),
 317471512                    WideArithmetic.Scale(translationOffset.X)),
 317471513                firstRotatedX),
 317471514            secondRotatedX);
 317471515        y = WideArithmetic.AddSigned192(
 317471516            WideArithmetic.AddSigned192(
 317471517                WideArithmetic.AddSigned192(
 317471518                    WideArithmetic.Scale(origin.Y),
 317471519                    WideArithmetic.Scale(translationOffset.Y)),
 317471520                firstRotatedY),
 317471521            secondRotatedY);
 317471522    }
 523
 524    internal static void GetRotatedOffset(
 525        RotationFrame2d rotation,
 526        Vector2d localPoint,
 527        out Signed192 x,
 528        out Signed192 y)
 529    {
 851661530        GetRotatedOffset(
 851661531            rotation,
 851661532            Signed192.Raw(localPoint.X),
 851661533            Signed192.Raw(localPoint.Y),
 851661534            out x,
 851661535            out y);
 851661536    }
 537
 538    internal static void GetRotatedOffset(
 539        RotationFrame2d rotation,
 540        Signed192 localX,
 541        Signed192 localY,
 542        out Signed192 x,
 543        out Signed192 y)
 544    {
 860619545        x = Signed192.NarrowValue(
 860619546            WideArithmetic.SubtractSigned320(
 860619547                WideArithmetic.MultiplySigned192(
 860619548                    localX,
 860619549                    rotation.Cosine),
 860619550                WideArithmetic.MultiplySigned192(
 860619551                    localY,
 860619552                    rotation.Sine)));
 860619553        y = Signed192.NarrowValue(
 860619554            WideArithmetic.AddSigned320(
 860619555                WideArithmetic.MultiplySigned192(
 860619556                    localX,
 860619557                    rotation.Sine),
 860619558                WideArithmetic.MultiplySigned192(
 860619559                    localY,
 860619560                    rotation.Cosine)));
 860619561    }
 562
 563    private static void GetDirection(
 564        Vector2d direction,
 565        out WideAxis2d axis)
 566    {
 154567        axis = new WideAxis2d(
 154568            Signed192.Raw(direction.X),
 154569            Signed192.Raw(direction.Y));
 154570    }
 571}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.RotationFrame2d.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.RotationFrame2d.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>RotationFrame2d declaration for WideConvex2dRelations.</content>
 13internal static partial class WideConvex2dRelations
 14{
 15    internal readonly struct RotationFrame2d
 16    {
 117        internal static readonly RotationFrame2d Identity = new(
 118            Signed192.One,
 119            default);
 20
 21        internal readonly Signed192 Cosine;
 22        internal readonly Signed192 Sine;
 23
 24        internal RotationFrame2d(Fixed64 rotation)
 16389525            : this(
 16389526                Signed192.Raw(FixedMath.Cos(rotation)),
 16389527                Signed192.Raw(FixedMath.Sin(rotation)))
 28        {
 16389529        }
 30
 31        private RotationFrame2d(
 32            Signed192 cosine,
 33            Signed192 sine)
 34        {
 16389635            Cosine = cosine;
 16389636            Sine = sine;
 16389637        }
 38    }
 39}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/Convex/WideConvex2dRelations.SweepContacts.cs

#LineLine coverage
 1//=======================================================================
 2// WideConvex2dRelations.SweepContacts.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>Exact contact-axis recovery after an admitted zero-radius sweep.</content>
 13internal static partial class WideConvex2dRelations
 14{
 15    // The caller excluded initial contact and admitted a later hit, so a strict entry axis exists.
 16    internal static void GetSweptConvexContact(
 17        Vector2d sourceOrigin, Fixed64 sourceRotation, ReadOnlySpan<Vector2d> sourceOffsets,
 18        Vector2d targetOrigin, Fixed64 targetRotation, ReadOnlySpan<Vector2d> targetOffsets,
 19        Vector2d direction, out Vector2d normal, out Vector2d targetOffset)
 20    {
 25221        RotationFrame2d sourceFrame = new(sourceRotation), targetFrame = new(targetRotation);
 12622        WideAxis2d best = default;
 25223        Signed320 bestGap = default, bestVelocity = default;
 75624        for (int owner = 0; owner < 2; owner++)
 25        {
 25226            ReadOnlySpan<Vector2d> offsets = owner == 0 ? sourceOffsets : targetOffsets;
 25227            RotationFrame2d frame = owner == 0 ? sourceFrame : targetFrame;
 25228            Vector2d origin = owner == 0 ? sourceOrigin : targetOrigin;
 25229            int winding = GetPlanarSweepWinding(offsets);
 226030            for (int i = 0; i < offsets.Length; i++)
 31            {
 88532                GetTransformedEdge(frame, offsets[i], offsets[(i + 1) % offsets.Length],
 88533                    out Signed192 x, out Signed192 y);
 88534                WideAxis2d axis = new(y, WideArithmetic.Negate(x));
 88535                if (axis.IsZero) continue;
 111336                if (winding < 0) axis = -axis;
 86737                Signed320 plane = GetProjection(origin, frame, offsets[i], axis);
 86738                if (owner == 0)
 39                {
 48440                    GetProjectionRange(targetOrigin, targetFrame, targetOffsets, axis, out Signed320 minimum, out Signed
 48441                    if (winding == 0)
 442                        KeepSweepContactAxis(axis, plane, plane, minimum, maximum, direction, ref best, ref bestGap, ref
 43                    else
 48044                        KeepSweepEntryAxis(-axis, WideArithmetic.SubtractSigned320(minimum, plane), direction,
 48045                            ref best, ref bestGap, ref bestVelocity);
 46                }
 47                else
 48                {
 38349                    GetProjectionRange(sourceOrigin, sourceFrame, sourceOffsets, axis, out Signed320 minimum, out Signed
 38350                    if (winding == 0)
 351                        KeepSweepContactAxis(axis, minimum, maximum, plane, plane, direction, ref best, ref bestGap, ref
 52                    else
 38053                        KeepSweepEntryAxis(axis, WideArithmetic.SubtractSigned320(minimum, plane), direction,
 38054                            ref best, ref bestGap, ref bestVelocity);
 55                }
 86756                if (winding == 0) break;
 57            }
 58        }
 59        // After admission, motion also covers longitudinal collinear and point
 60        // contacts. It is redundant for full-dimensional convex boundaries.
 12661        KeepConvexSweepContactAxis(new WideAxis2d(Signed192.Raw(direction.X), Signed192.Raw(direction.Y)),
 12662            sourceOrigin, sourceFrame, sourceOffsets, targetOrigin, targetFrame, targetOffsets, direction,
 12663            ref best, ref bestGap, ref bestVelocity);
 12664        normal = WideNormalization.GetNormalized(best.X, best.Y);
 12665        GetSupportFeature(targetOrigin, targetFrame, targetOffsets, best, true, out Feature target);
 12666        GetSupportFeature(sourceOrigin, sourceFrame, sourceOffsets, -best, true, out Feature source);
 12667        GetWorldPoint(sourceOrigin, sourceFrame, source.Start, Vector2d.Zero, out Signed192 pointX, out Signed192 pointY
 12668        targetOffset = ProjectSweepSupport(pointX, pointY, 1, targetOrigin, targetFrame, target,
 12669            direction, bestGap, bestVelocity);
 12670    }
 71
 72    internal static bool TryGetSweptCenteredAxisContact(
 73        Vector2d center, Vector2d coreAxis, Fixed64 axisLength,
 74        Vector2d targetOrigin, Fixed64 targetRotation, ReadOnlySpan<Vector2d> targetOffsets,
 75        Vector2d direction, out Vector2d normal, out Vector2d targetOffset)
 76    {
 28877        RotationFrame2d frame = new(targetRotation);
 28878        WideAxis2d best = default;
 57679        Signed320 bestGap = default, bestVelocity = default;
 28880        int winding = GetPlanarSweepWinding(targetOffsets);
 206081        for (int i = 0; i < targetOffsets.Length; i++)
 82        {
 81083            GetTransformedEdge(frame, targetOffsets[i], targetOffsets[(i + 1) % targetOffsets.Length],
 81084                out Signed192 x, out Signed192 y);
 81085            WideAxis2d axis = new(y, WideArithmetic.Negate(x));
 81086            if (axis.IsZero) continue;
 73087            if (winding == 0)
 88            {
 6889                KeepCoreSweepContactAxis(axis, center, coreAxis, axisLength, targetOrigin, frame, targetOffsets, directi
 6890                    ref best, ref bestGap, ref bestVelocity);
 6891                break; // All nonzero edges of a collinear boundary share this axis.
 92            }
 115793            if (winding < 0) axis = -axis;
 66294            GetSweepCoreRange(center, coreAxis, axisLength, axis, out Signed320 minimum, out _);
 66295            Signed320 plane = GetProjection(targetOrigin, frame, targetOffsets[i], axis);
 66296            plane = WideArithmetic.AddSigned320(plane, plane);
 66297            KeepSweepEntryAxis(axis, WideArithmetic.SubtractSigned320(minimum, plane), direction,
 66298                ref best, ref bestGap, ref bestVelocity);
 99        }
 288100        if (axisLength > Fixed64.Zero)
 108101            KeepCoreSweepContactAxis(new WideAxis2d(Signed192.Raw(coreAxis.Y), WideArithmetic.Negate(Signed192.Raw(coreA
 108102                center, coreAxis, axisLength, targetOrigin, frame, targetOffsets, direction, ref best, ref bestGap, ref 
 288103        KeepCoreSweepContactAxis(new WideAxis2d(Signed192.Raw(direction.X), Signed192.Raw(direction.Y)),
 288104            center, coreAxis, axisLength, targetOrigin, frame, targetOffsets, direction, ref best, ref bestGap, ref best
 288105        normal = default;
 288106        targetOffset = default;
 292107        if (best.IsZero) return false;
 284108        normal = WideNormalization.GetNormalized(best.X, best.Y);
 284109        GetSupportFeature(targetOrigin, frame, targetOffsets, best, true, out Feature target);
 284110        Signed320 alignment = WideArithmetic.AddProducts(Signed192.Raw(coreAxis.X), best.X, Signed192.Raw(coreAxis.Y), b
 284111        Signed192 length = Signed192.Raw(axisLength);
 385112        if (alignment.Sign > 0) length = WideArithmetic.Negate(length);
 288113        if (alignment.IsZero) length = default;
 114        // Doubled product-scale coordinates retain odd-raw half-axis endpoints.
 284115        Signed192 pointX = WideArithmetic.AddSigned192(
 284116            WideArithmetic.Double(WideArithmetic.Scale(center.X)),
 284117            Signed192.NarrowValue(WideArithmetic.MultiplySigned192(Signed192.Raw(coreAxis.X), length)));
 284118        Signed192 pointY = WideArithmetic.AddSigned192(
 284119            WideArithmetic.Double(WideArithmetic.Scale(center.Y)),
 284120            Signed192.NarrowValue(WideArithmetic.MultiplySigned192(Signed192.Raw(coreAxis.Y), length)));
 284121        targetOffset = ProjectSweepSupport(pointX, pointY, 2, targetOrigin, frame, target,
 284122            direction, bestGap, bestVelocity);
 284123        return true;
 124    }
 125
 126    private static void KeepConvexSweepContactAxis(WideAxis2d axis,
 127        Vector2d sourceOrigin, RotationFrame2d sourceFrame, ReadOnlySpan<Vector2d> sourceOffsets,
 128        Vector2d targetOrigin, RotationFrame2d targetFrame, ReadOnlySpan<Vector2d> targetOffsets, Vector2d direction,
 129        ref WideAxis2d best, ref Signed320 bestGap, ref Signed320 bestVelocity)
 130    {
 126131        GetProjectionRange(sourceOrigin, sourceFrame, sourceOffsets, axis, out Signed320 sourceMin, out Signed320 source
 126132        GetProjectionRange(targetOrigin, targetFrame, targetOffsets, axis, out Signed320 targetMin, out Signed320 target
 126133        KeepSweepContactAxis(axis, sourceMin, sourceMax, targetMin, targetMax, direction, ref best, ref bestGap, ref bes
 126134    }
 135
 136    private static void KeepCoreSweepContactAxis(WideAxis2d axis, Vector2d center, Vector2d coreAxis, Fixed64 length,
 137        Vector2d targetOrigin, RotationFrame2d frame, ReadOnlySpan<Vector2d> targetOffsets, Vector2d direction,
 138        ref WideAxis2d best, ref Signed320 bestGap, ref Signed320 bestVelocity)
 139    {
 464140        GetSweepCoreRange(center, coreAxis, length, axis, out Signed320 sourceMin, out Signed320 sourceMax);
 464141        GetProjectionRange(targetOrigin, frame, targetOffsets, axis, out Signed320 targetMin, out Signed320 targetMax);
 464142        KeepSweepContactAxis(axis, sourceMin, sourceMax,
 464143            WideArithmetic.AddSigned320(targetMin, targetMin), WideArithmetic.AddSigned320(targetMax, targetMax), direct
 464144            ref best, ref bestGap, ref bestVelocity);
 464145    }
 146
 147    private static void GetSweepCoreRange(Vector2d center, Vector2d coreAxis, Fixed64 length,
 148        WideAxis2d axis, out Signed320 minimum, out Signed320 maximum)
 149    {
 1126150        Signed320 midpoint = WideArithmetic.AddProducts(WideArithmetic.Double(WideArithmetic.Scale(center.X)), axis.X,
 1126151            WideArithmetic.Double(WideArithmetic.Scale(center.Y)), axis.Y);
 1126152        Signed192 alignment = Signed192.NarrowValue(WideArithmetic.AddProducts(
 1126153            Signed192.Raw(coreAxis.X), axis.X, Signed192.Raw(coreAxis.Y), axis.Y));
 1379154        if (alignment.Sign < 0) alignment = WideArithmetic.Negate(alignment);
 1126155        Signed320 extent = WideArithmetic.MultiplySigned192(alignment, Signed192.Raw(length));
 1126156        minimum = WideArithmetic.SubtractSigned320(midpoint, extent);
 1126157        maximum = WideArithmetic.AddSigned320(midpoint, extent);
 1126158    }
 159
 160    private static void KeepSweepContactAxis(WideAxis2d axis, Signed320 sourceMin, Signed320 sourceMax,
 161        Signed320 targetMin, Signed320 targetMax, Vector2d direction,
 162        ref WideAxis2d best, ref Signed320 bestGap, ref Signed320 bestVelocity)
 163    {
 597164        Signed320 gap = WideArithmetic.SubtractSigned320(sourceMin, targetMax);
 597165        if (gap.Sign <= 0)
 166        {
 595167            axis = -axis;
 595168            gap = WideArithmetic.SubtractSigned320(targetMin, sourceMax);
 169        }
 597170        KeepSweepEntryAxis(axis, gap, direction, ref best, ref bestGap, ref bestVelocity);
 597171    }
 172
 173    private static void KeepSweepEntryAxis(WideAxis2d axis, Signed320 gap, Vector2d direction,
 174        ref WideAxis2d best, ref Signed320 bestGap, ref Signed320 bestVelocity)
 175    {
 3311176        if (gap.Sign <= 0) return;
 177        // Admission proves that every strict initial gap closes, so this
 178        // oriented axis has a strictly positive closing velocity.
 927179        Signed320 velocity = WideArithmetic.SubtractSigned320(default,
 927180            WideArithmetic.AddProducts(axis.X, Signed192.Raw(direction.X), axis.Y, Signed192.Raw(direction.Y)));
 181        // An admitted translational contact enters at the greatest axis-entry
 182        // gap/closing-speed ratio. Common distance scales cancel, including
 183        // authored chords. Product-scale frame coordinates and edge axes use
 184        // fewer than 100 bits each, so gaps use fewer than 202 bits and motion
 185        // projections fewer than 165. Their cross-products fit Signed576.
 186        // No rounded impact point participates in axis selection.
 927187        if (!best.IsZero && WideArithmetic.SubtractSigned576(
 927188                WideArithmetic.MultiplySigned320(gap, bestVelocity),
 1344189                WideArithmetic.MultiplySigned320(bestGap, velocity)).Sign <= 0) return;
 510190        best = axis;
 510191        bestGap = gap;
 510192        bestVelocity = velocity;
 510193    }
 194
 195    private static Vector2d ProjectSweepSupport(Signed192 pointX, Signed192 pointY, int pointScale,
 196        Vector2d targetOrigin, RotationFrame2d frame, Feature target,
 197        Vector2d direction, Signed320 gap, Signed320 velocity)
 198    {
 410199        GetTransformedEdge(frame, target.Start, target.End, out Signed192 edgeX, out Signed192 edgeY);
 410200        Signed320 edgeSquared = WideArithmetic.AddProducts(edgeX, edgeX, edgeY, edgeY);
 488201        if (edgeSquared.IsZero) return target.Start;
 332202        GetWorldPoint(targetOrigin, frame, target.Start, Vector2d.Zero, out Signed192 startX, out Signed192 startY);
 332203        Signed576 denominator = WideArithmetic.MultiplySigned320(edgeSquared, velocity);
 332204        if (pointScale == 2)
 205        {
 212206            startX = WideArithmetic.Double(startX);
 212207            startY = WideArithmetic.Double(startY);
 212208            denominator = WideArithmetic.AddSigned576(denominator, denominator);
 209        }
 210        // Evaluate the support at the exact gap/velocity event, not at its
 211        // rounded public distance. Relative coordinate numerators use fewer
 212        // than 268 bits; edge projections fit 370 bits and final coordinates
 213        // fit 435 bits, within Signed320, Signed576 and Signed832 respectively.
 332214        Signed320 relativeX = Signed320.NarrowValue(WideArithmetic.AddSigned576(
 332215            WideArithmetic.MultiplySigned320(Signed320.ExtendValue(WideArithmetic.SubtractSigned192(pointX, startX)), ve
 332216            WideArithmetic.MultiplySigned320(Signed320.ExtendValue(Signed192.Raw(direction.X)), gap)));
 332217        Signed320 relativeY = Signed320.NarrowValue(WideArithmetic.AddSigned576(
 332218            WideArithmetic.MultiplySigned320(Signed320.ExtendValue(WideArithmetic.SubtractSigned192(pointY, startY)), ve
 332219            WideArithmetic.MultiplySigned320(Signed320.ExtendValue(Signed192.Raw(direction.Y)), gap)));
 332220        Signed576 numerator = WideArithmetic.AddSigned576(
 332221            WideArithmetic.MultiplySigned320(relativeX, Signed320.ExtendValue(edgeX)),
 332222            WideArithmetic.MultiplySigned320(relativeY, Signed320.ExtendValue(edgeY)));
 334223        if (numerator.Sign < 0) numerator = default;
 332224        else if (WideArithmetic.SubtractSigned576(numerator, denominator).Sign > 0) numerator = denominator;
 332225        return new Vector2d(
 332226            GetSweepProjectedCoordinate(target.Start.X, target.End.X, numerator, denominator),
 332227            GetSweepProjectedCoordinate(target.Start.Y, target.End.Y, numerator, denominator));
 228    }
 229
 230    private static Fixed64 GetSweepProjectedCoordinate(Fixed64 start, Fixed64 end, Signed576 parameter, Signed576 denomi
 231    {
 698232        Signed832 numerator = WideArithmetic.AddSigned832(
 698233            WideArithmetic.MultiplySigned576ToSigned832(denominator, Signed320.ExtendValue(Signed192.Raw(start))),
 698234            WideArithmetic.MultiplySigned576ToSigned832(parameter, Signed320.ExtendValue(WideArithmetic.Difference(end, 
 235        // Clamped interpolation between representable local endpoints fits.
 698236        _ = Fixed64.TryGetSignedRawRatio(numerator, Signed832.ExtendValue(denominator), 0, out Fixed64 coordinate);
 698237        return coordinate;
 238    }
 239}

Methods/Properties

.ctor(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed832,FixedMathSharp.Signed832)
GetBoundaryFaceContacts(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.RationalSegmentInterval&,System.Span`1<FixedMathSharp.Geometry.FixedContactAnchors2d>,System.Boolean)
BoundaryIntervalsOverlap(FixedMathSharp.Geometry.RationalSegmentInterval&,FixedMathSharp.Geometry.RationalSegmentInterval&)
BoundaryWall(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
ClipBoundaryParameter(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
KeepBoundaryFacePoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,System.Boolean&,FixedMathSharp.Geometry.WideConvex2dRelations/BoundaryFacePoint&,FixedMathSharp.Geometry.WideConvex2dRelations/BoundaryFacePoint&)
InterpolateBoundaryValue(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
CompareBoundaryRatios(FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed832,FixedMathSharp.Signed576)
MaterializeBoundaryFace(FixedMathSharp.Geometry.WideConvex2dRelations/BoundaryFacePoint&,FixedMathSharp.Signed320,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.Boolean)
TryIntersectBoundarySegments(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Geometry.RationalSegmentInterval&,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Geometry.RationalSegmentInterval&,FixedMathSharp.Geometry.RationalSegmentInterval&)
WithinBoundaryInterval(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Geometry.RationalSegmentInterval&)
GetCapsuleBoundaryFaceContacts(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.RationalSegmentInterval&,System.Span`1<FixedMathSharp.Geometry.FixedContactAnchors2d>,System.Boolean)
HasContact(System.Boolean)
get_HasTwo()
Q(System.Int32)
Root(System.Int32)
.ctor(System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Span`1<System.UInt64>,FixedMathSharp.Signed320,FixedMathSharp.Geometry.RationalSegmentInterval&)
AddDisk(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576)
AddSides(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576)
Keep()
Copy(System.Int32,System.Int32)
SetRoot(FixedMathSharp.Signed576)
Integer(System.Int64)
Materialize(System.Int32,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector2d)
Coordinate(System.Int32,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Boolean)
TryGetBoundaryVertexContact(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.FixedPointAnchor2d&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,FixedMathSharp.Geometry.FixedContactAnchors2d&)
KeepBoundaryVertexAxis(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.FixedPointAnchor2d&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320,FixedMathSharp.Geometry.WideConvex2dRelations/PenetrationAxis&,FixedMathSharp.Vector2d&)
SupportsBoundaryFan(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Geometry.FixedPointAnchor2d&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.FixedPointAnchor2d>)
SupportsBoundaryFan(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.FixedPointAnchor2d&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.FixedPointAnchor2d>)
SameBoundaryPlane(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Vector2d)
LocateBoundaryPoint(FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Geometry.RationalSegmentInterval&)
get_IsZero()
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192)
op_UnaryNegation(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d)
get_IsPoint()
.ctor(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
.ctor(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed320,System.Boolean)
DoConvexesOverlap(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Boolean)
GetBoundsClippedToDomain(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetTransformedEdgeDirection(FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
GetRelativePointNumerators(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
IsStrictlyConvex(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetSupportOffset(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetSupportOffset(FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetClosestPointOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetClosestPointOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
GetSweptPointTargetContactOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetSweptPointTargetContactOffset(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
GetSweptAnchorTargetContactOffset(FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d)
ContainsPoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
ContainsPointUnrotated(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
ContainsDegeneratePoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
TryProjectAnchorOntoFeature(FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Boolean,FixedMathSharp.Vector2d&)
TryGetContactOffsets(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Span`1<FixedMathSharp.Vector2d>,System.Span`1<FixedMathSharp.Vector2d>,System.Int32&,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&,System.Boolean&)
TryGetAreaAndCentroid(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64&,FixedMathSharp.Vector2d&)
TryGetSignedDoubleAreaAndCentroid(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Signed320&,FixedMathSharp.Vector2d&)
TryKeepAxes(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Boolean,FixedMathSharp.Geometry.WideConvex2dRelations/PenetrationAxis&)
TryKeepAxis(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Boolean,FixedMathSharp.Geometry.WideConvex2dRelations/PenetrationAxis&)
TryGetEdgeCoverage(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.RationalSegmentInterval&,System.Int32&)
CoveragePoint(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
IntersectsSweptUprightCapsule(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Boolean)
HasPlanarSweepCoreOverlap(System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d>,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,System.Int32,System.Boolean)
IsSweepPointNearSegment(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320,System.Int32)
GetPlanarSweepWinding(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>)
IncludeSweepProjection(FixedMathSharp.Signed320,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
DoubleSweepOffset(FixedMathSharp.Vector2d)
SubtractSweepPoint(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d)
SweepCross(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d)
SweepDot(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d)
GetMinimumSupportFeature(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
GetSupportFeature(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,System.Boolean,FixedMathSharp.Geometry.WideConvex2dRelations/Feature&)
GetProjectionRange(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
GetProjection(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d)
GetSquaredDistance(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d)
AddProjectedEndpoint(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Geometry.WideConvex2dRelations/Feature,System.Boolean,System.Span`1<FixedMathSharp.Vector2d>,System.Span`1<FixedMathSharp.Vector2d>,System.Int32&)
TryProjectPointOntoFeature(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Boolean,FixedMathSharp.Vector2d&)
TryProjectPointOntoFeature(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Boolean,FixedMathSharp.Vector2d&,FixedMathSharp.Geometry.FixedPointAnchorTerm2d)
GetProjectedOffsetCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetDepth(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Fixed64&,System.Boolean&)
CorrectDepth(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Fixed64&)
CompareDepthToTwiceRaw(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192)
GetTransformedEdge(FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetWorldPoint(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetWorldPoint(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetRotatedOffset(FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetRotatedOffset(FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetDirection(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d&)
.cctor()
.ctor(FixedMathSharp.Fixed64)
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192)
GetSweptConvexContact(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryGetSweptCenteredAxisContact(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
KeepConvexSweepContactAxis(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
KeepCoreSweepContactAxis(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
GetSweepCoreRange(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
KeepSweepContactAxis(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
KeepSweepEntryAxis(FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d,FixedMathSharp.Signed320,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/WideAxis2d&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
ProjectSweepSupport(FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Int32,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideConvex2dRelations/RotationFrame2d,FixedMathSharp.Geometry.WideConvex2dRelations/Feature,FixedMathSharp.Vector2d,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetSweepProjectedCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed576,FixedMathSharp.Signed576)