< Summary

Information
Class: FixedMathSharp.Geometry.WideOrientedBox
Assembly: FixedMathSharp
File(s): File 1: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.AxisProjection.cs
File 2: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Box.cs
File 3: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Capsule.cs
File 4: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CapsuleEdges.cs
File 5: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CapsuleSlab.cs
File 6: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CircleSlab.cs
File 7: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CircleSlabProjection.cs
File 8: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CircleSlabSweep.cs
File 9: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHull.cs
File 10: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHullCapsule.cs
File 11: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHullCapsule.Support.cs
File 12: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHullPair.cs
File 13: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexPrism.cs
File 14: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.cs
File 15: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Cylinder.cs
File 16: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CylinderCapFace.cs
File 17: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Materialization.cs
File 18: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RationalSegmentSweep.cs
File 19: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Ray.cs
File 20: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RelativeBounds.cs
File 21: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RigidAxisRelations.cs
File 22: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RigidClosestCandidate.cs
File 23: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RigidFiniteAxisQuery.cs
File 24: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Sphere.cs
File 25: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Triangle.cs
File 26: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.TriangleCapsuleSlab.cs
File 27: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.TriangleCircleSlabSweep.cs
File 28: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.TrianglePrism.cs
Line coverage
100%
Covered lines: 10190
Uncovered lines: 0
Coverable lines: 10190
Total lines: 14783
Line coverage: 100%
Branch coverage
100%
Covered branches: 1294
Total branches: 1294
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: GetBoxProjectionRadiusNumerator(...)100%11100%
File 1: GetLocalBoxProjectionRadiusNumerator(...)100%11100%
File 1: GetRotatedLocalProjectionSign(...)100%11100%
File 1: GetRotatedLocalAxisNumerators(...)100%11100%
File 1: GetRelativeLocalPointNumerators(...)100%11100%
File 1: GetRelativeLocalPointNumerators(...)100%11100%
File 2: .ctor(...)100%11100%
File 2: TryGetContact(...)100%1818100%
File 2: TryKeepFirstFaceAxis(...)100%11100%
File 2: TryKeepSecondFaceAxis(...)100%11100%
File 2: TryKeepCrossAxis(...)100%22100%
File 2: TryKeepBoxPenetration(...)100%66100%
File 2: CompareBoxDepth(...)100%11100%
File 3: .ctor(...)100%11100%
File 3: TryGetCenteredCapsuleContact(...)100%44100%
File 3: CanOverlapCenteredCapsule(...)100%11100%
File 3: CanOverlapCenteredCapsule(...)100%11100%
File 3: TryGetCenteredCapsulePenetration(...)100%3030100%
File 3: GetLocalEdgeCenter(...)100%44100%
File 3: GetMatchedBoxSupportLocalPoint(...)100%11100%
File 3: GetMatchedBoxSupportLocalPoint(...)100%88100%
File 3: GetMatchedCapsuleSupportAnchor(...)100%22100%
File 3: GetMatchedSupportCoordinate(...)100%88100%
File 4: .ctor(...)100%11100%
File 4: get_IsZero()100%44100%
File 4: op_UnaryNegation(...)100%11100%
File 4: GetVertexToCapsuleAxis(...)100%44100%
File 4: GetLocalVertexToCapsuleAxis(...)100%44100%
File 4: GetCapsuleEndpointToBoxEdgeAxis(...)100%1212100%
File 4: GetLocalPointToCapsuleCenterAxis(...)100%11100%
File 4: GetLocalPointToCapsuleEndpointAxis(...)100%11100%
File 4: GetLocalEndpointComponent(...)100%22100%
File 4: GetScaledCapsuleAxisSquared(...)100%11100%
File 4: GetCapsuleCenterAxisProjection(...)100%11100%
File 4: GetCornerToAxisCenterAxis3D(...)100%11100%
File 4: GetCornerToAxisCenterComponent(...)100%11100%
File 4: GetPerpendicularAxis(...)100%11100%
File 4: GetPerpendicularComponent(...)100%11100%
File 4: TryKeepCapsuleAxis(...)100%1616100%
File 4: GetLocalCapsuleBoxRadius(...)100%11100%
File 4: GetLocalCapsuleCenterProjection(...)100%11100%
File 4: GetCapsuleBasisProjection(...)100%11100%
File 4: GetCapsuleAxisProjection(...)100%11100%
File 4: GetCapsuleSquaredLength(...)100%11100%
File 4: IsWideCapsuleRadicalAtLeastRational(...)100%11100%
File 4: GetWideCapsuleDepth(...)100%22100%
File 4: CompareWideCapsuleDepth(...)100%11100%
File 4: ToCapsuleAxis(...)100%11100%
File 5: TryGetCenteredCapsuleSlabContact(...)100%2828100%
File 5: TryKeepCapsuleSlabAxis(...)100%1414100%
File 5: GetPlanarAxisProjection(...)100%11100%
File 5: GetCornerToCapsuleEndpointAxis(...)100%11100%
File 5: GetCapsuleSlabSupportAnchor(...)100%22100%
File 6: TryGetCircleSlabContact(...)100%2020100%
File 6: GetCircleSlabBoxContactPoint(...)100%2222100%
File 6: TryKeepCircleSlabAxis(...)100%1414100%
File 6: IsRadicalAtLeastRatio(...)100%11100%
File 6: GetRadialDepth(...)100%22100%
File 6: GetCornerToOriginAxis(...)100%11100%
File 6: GetLocalOffsetNumerator(...)100%11100%
File 6: GetCircleSlabSupportAnchor(...)100%22100%
File 6: GetLocalPlanarSupportDirection(...)100%11100%
File 7: .ctor(...)100%11100%
File 7: .ctor(...)100%11100%
File 7: .ctor(...)100%11100%
File 7: .ctor(...)100%11100%
File 7: TryBuildCircleSlabProjectionConstraints(...)100%1414100%
File 7: AddBoxAxisConstraints(...)100%11100%
File 7: TryAddProjectionConstraint(...)100%44100%
File 7: BuildCircleSlabProjectionVertices(...)100%1818100%
File 7: GetSweepBoxCorner(...)100%11100%
File 7: TryAddPlaneIntersection(...)100%1212100%
File 7: AddUniqueSweepPoint(...)100%44100%
File 7: AreSameSweepPoint(...)100%22100%
File 8: .cctor()100%11100%
File 8: .ctor(...)100%11100%
File 8: TryGetCircleSlabSweepDistance(...)100%1616100%
File 8: GetCircleSlabSeparationLowerBound(...)100%2020100%
File 8: IsClosestProjectionOnConstraint(...)100%44100%
File 8: GetClosestProjectionVertexDistanceLowerBound(...)100%44100%
File 8: GetRationalPointDistance(...)100%11100%
File 8: CompareRationalPointDistances(...)100%11100%
File 8: GetRationalPointDistanceLowerBound(...)100%44100%
File 8: GetCircleSlabVerticalSeparationLowerBound(...)100%22100%
File 8: TryGetExpandedEdgeSweepDistance(...)100%1414100%
File 8: CompareExpandedEdgeAtHalf(...)100%11100%
File 8: CompareExpandedEdgeAt(...)100%22100%
File 8: IsRoundedEdgeFeatureValid(...)100%44100%
File 8: TryGetRationalPointSweepDistance(...)100%2020100%
File 8: GetHalfToEvenIncrement(...)100%11100%
File 8: CompareRationalPointAtHalf(...)100%11100%
File 8: CompareRationalPointAt(...)100%11100%
File 8: GetSweepProjection(...)100%11100%
File 9: TryGetConvexHullContact(...)100%1616100%
File 9: TryKeepPointSpanAxis(...)100%1212100%
File 10: TryGetConvexHullCenteredCapsuleContact(...)100%2222100%
File 10: TryKeepHullCapsuleCandidate(...)100%88100%
File 10: EvaluateHullCapsuleCandidate(...)100%88100%
File 10: BuildHullCapsuleCandidateAxis(...)100%66100%
File 10: GetCapsuleEndpointToHullEdgeAxis(...)100%66100%
File 11: .ctor(...)100%11100%
File 11: GetHullCapsuleProjectionInterval(...)100%66100%
File 11: BuildHullCapsuleLocalProjection(...)100%11100%
File 11: BuildHullCapsuleProjectionTerm(...)100%11100%
File 11: GetHullCapsuleCenterProjection(...)100%11100%
File 11: BuildHullCapsuleAxisSquared(...)100%11100%
File 11: GetMatchedHullCapsuleSupportAnchor(...)100%2222100%
File 11: IsHullCapsuleSupportPoint(...)100%11100%
File 11: GetHullCapsuleDepth(...)100%66100%
File 11: CompareHullCapsuleDepthToTwiceRaw(...)100%11100%
File 11: MultiplyHullCapsuleMagnitude(...)100%11100%
File 11: MultiplyHullCapsuleMagnitude(...)100%11100%
File 11: GetHullCapsuleMagnitude(...)100%11100%
File 11: GetHullCapsuleMagnitude(...)100%11100%
File 11: GetHullCapsuleMagnitude(...)100%11100%
File 11: GetHullCapsuleMagnitude(...)100%11100%
File 11: CompareHullCapsuleSignedMagnitudes(...)100%88100%
File 11: CombineHullCapsuleSignedMagnitudes(...)100%1616100%
File 12: ContainsConvexHullPoint(...)100%1010100%
File 12: TryGetConvexHullContact(...)100%1414100%
File 12: TryKeepHullFaceAxes(...)100%44100%
File 12: TryKeepHullPairAxis(...)100%1010100%
File 12: GetHullProjectionInterval(...)100%22100%
File 12: GetHullEdge(...)100%11100%
File 12: GetHullSupportLocalPoint(...)100%66100%
File 13: .ctor(...)100%11100%
File 13: ToWide()100%11100%
File 13: TryGetConvexPrismContact(...)100%2020100%
File 13: TryKeepConvexPrismAxis(...)100%2222100%
File 13: GetRotatedPlanarOffsetProjection(...)100%11100%
File 13: GetRotatedPlanarEdge(...)100%11100%
File 13: GetLocalAxisSupportPoint(...)100%66100%
File 13: GetPrismSupportOffset(...)100%1010100%
File 13: ShouldNegateCanonicalAxis(...)100%44100%
File 13: IsLexicographicallyEarlier(...)100%44100%
File 13: CrossWithUp(...)100%11100%
File 13: CrossWithPlanarEdge(...)100%11100%
File 14: .ctor(...)100%11100%
File 14: GetAxes(...)100%11100%
File 14: GetLocalSupportPoint(...)100%66100%
File 14: GetBoundsClippedToDomain(...)100%11100%
File 14: Contains(...)100%44100%
File 14: GetClosestPointAnchor(...)100%88100%
File 14: GetNearestFaceNormal(...)100%1212100%
File 14: TryMaterializeLocalPoint(...)100%22100%
File 14: TryMaterializeLocalPoint(...)100%22100%
File 14: TryTransformLocalOffset(...)100%11100%
File 14: TryGetRelativeOffset(...)100%22100%
File 14: TryGetSupportOffset(...)100%11100%
File 14: TryGetSupportDifference(...)100%22100%
File 14: TryGetSupportDifference(...)100%22100%
File 14: GetDirectionProjections(...)100%11100%
File 14: GetPointProjections(...)100%11100%
File 14: IsWithinExtent(...)100%11100%
File 14: GetClampedNumerator(...)100%22100%
File 14: GetSignedExtent(...)100%22100%
File 14: GetExtentNumerator(...)100%11100%
File 14: GetMagnitude(...)100%22100%
File 14: GetMagnitude(...)100%22100%
File 14: GetMagnitude(...)100%22100%
File 14: GetExtentNumerator(...)100%11100%
File 14: GetClippedEndpoint(...)100%1414100%
File 14: GetAxis(...)100%22100%
File 14: CompareSigned(...)100%44100%
File 14: CompareSigned(...)100%11100%
File 14: ToSigned576(...)100%11100%
File 15: .ctor(...)100%11100%
File 15: .ctor(...)100%11100%
File 15: TryGetCenteredCylinderContact(...)100%11100%
File 15: TryGetCenteredCylinderContact(...)100%2424100%
File 15: GetCenteredCylinderContactFeature(...)100%66100%
File 15: AreParallel(...)100%44100%
File 15: GetCornerToAxisEndpointAxis3D(...)100%11100%
File 15: GetCornerToAxisEndpointComponent(...)100%11100%
File 15: TryKeepCylinderAxis(...)100%1414100%
File 15: IsCylinderRadicalAtLeastRatio(...)100%11100%
File 15: GetCylinderDepth(...)100%22100%
File 16: .ctor(...)100%11100%
File 16: Equals(...)100%22100%
File 16: .cctor()100%11100%
File 16: GetCenteredCylinderCapFaceContacts(...)100%44100%
File 16: GetRationalLocalPoint(...)100%11100%
File 16: GetFaceCoordinates(...)100%44100%
File 16: KeepCapExtreme(...)100%1212100%
File 16: GetSignedFaceExtent(...)100%66100%
File 16: GetLocalCoordinates(...)100%44100%
File 16: ClampToExtent(...)100%44100%
File 17: GetRationalLocalPoint(...)100%11100%
File 17: TryMaterializeCoordinate(...)100%11100%
File 17: TryMaterializeCoordinate(...)100%11100%
File 17: TryMaterializeRationalOffset(...)100%22100%
File 17: TryMaterializeSupportDifferenceCoordinate(...)100%11100%
File 17: TryMaterializeBoxSupportDifferenceCoordinate(...)100%11100%
File 17: TryGetRelativeOffsetCoordinate(...)100%11100%
File 18: TryGetRationalSegmentSweepDistance(...)100%3838100%
File 18: CompareApproachingLineAt(...)100%11100%
File 18: CompareRationalSegmentLineAtHalf(...)100%11100%
File 18: CompareRationalSegmentLineAt(...)100%11100%
File 18: TryGetRationalSegmentParameter(...)100%44100%
File 18: GetEdgeSquaredMagnitude(...)100%11100%
File 18: GetCrossMagnitude(...)100%11100%
File 18: GetCrossMagnitude(...)100%11100%
File 18: GetCrossMagnitude(...)100%11100%
File 18: GetDotMagnitude(...)100%11100%
File 18: CombineSignedMagnitudes(...)100%1010100%
File 18: CopyMagnitude(...)100%11100%
File 19: .ctor(...)100%11100%
File 19: TryGetRayIntersectionInterval(...)100%66100%
File 19: TryClipRayAxis(...)100%1414100%
File 19: NormalizeRayBound(...)100%22100%
File 19: CompareRayBounds(...)100%11100%
File 19: RoundRayBound(...)100%11100%
File 20: GetRelativeRotatedBoundsClippedToDomain(...)100%11100%
File 20: GetRelativeBoundsCoordinate(...)100%11100%
File 20: GetRelativeEndpointNumerator(...)100%11100%
File 20: SelectEndpoint(...)100%22100%
File 20: GetRelativeEndpointClippedToDomain(...)100%1212100%
File 21: .ctor(...)100%11100%
File 21: DoCenteredRigidCapsulesOverlap(...)100%2222100%
File 21: ClampUnitRatio(...)100%44100%
File 21: SetRigidSegmentRatio(...)100%11100%
File 21: SetRigidSegmentProjectionRatio(...)100%11100%
File 21: IsRigidLinePairWithinRadius(...)100%11100%
File 21: IsRigidPointLineWithinRadius(...)100%11100%
File 21: IsRigidPointWithinRadius(...)100%11100%
File 21: GetRadiusThreshold(...)100%22100%
File 21: GetSquaredMagnitude(...)100%11100%
File 21: GetTripleProductMagnitude(...)100%11100%
File 21: GetProductDifference(...)100%11100%
File 21: GetProductDifference(...)100%11100%
File 21: DoubleMagnitude(...)100%22100%
File 21: DoubleProduct(...)100%11100%
File 21: GetRigidSegmentLowerDifference(...)100%11100%
File 21: GetRigidSegmentLowerDifference(...)100%11100%
File 21: AddRigidSegmentDisplacement(...)100%11100%
File 21: SubtractRigidSegmentDisplacement(...)100%11100%
File 21: Dot(...)100%11100%
File 21: Dot(...)100%11100%
File 22: TryKeepCenteredRigidCylinderCapsuleClosestAxis(...)100%11100%
File 22: TryKeepCenteredRigidCylinderCylinderClosestAxis(...)100%11100%
File 22: TryKeepCenteredRigidCylinderClosestAxis(...)100%2424100%
File 22: BuildRigidPointLineClosestComponent(...)100%11100%
File 22: BuildRigidLinePairClosestComponent(...)100%11100%
File 22: GetSignedMagnitude(...)100%11100%
File 22: RemoveCommonPowerOfTwo(...)100%22100%
File 22: GetTrailingZeroCount(...)100%66100%
File 22: ShiftRightMagnitude(...)100%88100%
File 23: .ctor(...)100%11100%
File 23: .ctor(...)100%11100%
File 23: TryGetRigidCapsuleDistanceInterval(...)100%44100%
File 23: TryGetRigidCylinderDistanceInterval(...)100%44100%
File 23: TryGetRigidConeDistanceInterval(...)100%44100%
File 23: GetRigidLocalRay(...)100%11100%
File 23: TryGetCardinalLocalYAxis(...)100%2424100%
File 23: ScaleRigidDimension(...)100%11100%
File 23: ScaleRigidDimensionSum(...)100%11100%
File 23: ScaleRigidDimensionWithDoubleExpansion(...)100%11100%
File 23: NarrowRigidQueryValue(...)100%11100%
File 23: GetRadialPolynomial(...)100%11100%
File 23: MergeRigidCapsuleCap(...)100%22100%
File 23: GetSpherePolynomial(...)100%11100%
File 23: GetConePolynomial(...)100%11100%
File 23: TryGetCenteredAxialBounds(...)100%11100%
File 23: TryGetLinearBounds(...)100%1414100%
File 23: NormalizeRigidBound(...)100%22100%
File 23: CompareRigidBounds(...)100%11100%
File 23: IsCylinderContained(...)100%1010100%
File 23: IsCapsuleContained(...)100%88100%
File 23: IsConeContained(...)100%1010100%
File 23: EvaluatePolynomialAtOne(...)100%11100%
File 23: AddRigidSquares(...)100%11100%
File 23: AddRigidSquares(...)100%11100%
File 23: AddRigidProducts(...)100%11100%
File 23: AddRigidProducts(...)100%11100%
File 23: MergeRigidInterval(...)100%88100%
File 24: TryGetSweptSphereIntersectionDistance(...)100%11100%
File 24: TryGetSphereContact(...)100%44100%
File 24: TryGetContainedSphereContact(...)100%2626100%
File 24: GetSphereSurfaceAnchor(...)100%22100%
File 24: GetProjectionNumerator(...)100%11100%
File 24: GetRationalLocalOffsetNumerators(...)100%11100%
File 24: GetRationalLocalOffsetNumerator(...)100%11100%
File 24: GetOriginRelativeNumerator(...)100%11100%
File 24: SumSquares(...)100%11100%
File 24: GetRoundedRadialDepth(...)100%11100%
File 24: CorrectRoundedRadialDepth(...)100%22100%
File 24: GetLowerMidpointAdjustment(...)100%11100%
File 24: GetUpperMidpointAdjustment(...)100%11100%
File 24: CompareRadialDepthToTwiceRaw(...)100%11100%
File 25: TryGetTriangleContact(...)100%1616100%
File 25: TryKeepTriangleEdgeAxes(...)100%44100%
File 25: TryKeepTriangleAxis(...)100%1010100%
File 25: GetTriangleSupportLocalPoint(...)100%44100%
File 25: GetTriangleFaceContacts(...)100%1818100%
File 25: GetParallelTriangleFaceAxis(...)100%88100%
File 25: GetDirectionProjection(...)100%11100%
File 25: IsParallel(...)100%11100%
File 26: TryGetTriangleCapsuleSlabContact(...)100%2626100%
File 26: TryKeepTriangleCapsuleSlabAxis(...)100%2424100%
File 26: DoesRadialOverlap(...)100%22100%
File 26: GetTriangleVertexToCapsuleEndpointAxis(...)100%11100%
File 27: .ctor(...)100%11100%
File 27: ToSweepPoint(...)100%11100%
File 27: .ctor(...)100%11100%
File 27: TryGetFiniteSlabProjectedCircleSweep(...)100%1818100%
File 27: TryGetTriangleProjectionInteriorPoint(...)100%1414100%
File 27: TryGetTriangleInteriorLocalCoordinate(...)100%11100%
File 27: GetTriangleSweepVertex(...)100%11100%
File 27: AreSameProjectedPoint(...)100%22100%
File 27: KeepTriangleEdgeSweep(...)100%88100%
File 27: GetClippedTriangleEdgeEndpoint(...)100%66100%
File 27: KeepTrianglePlaneEdgeSweep(...)100%22100%
File 27: TryAddTrianglePlaneIntersection(...)100%1010100%
File 27: GetTrianglePlaneIntersection(...)100%22100%
File 27: GetWeightedLocalPoint(...)100%11100%
File 27: AddUniqueTriangleSweepPoint(...)100%44100%
File 27: KeepTriangleSweepFeature(...)100%88100%
File 27: KeepTriangleSweepCandidate(...)100%66100%
File 27: ScaleReferenceYOffset(...)100%11100%
File 27: GetAbsoluteReferenceYOffset(...)100%22100%
File 28: TryGetTrianglePrismContact(...)100%2020100%
File 28: TryKeepTrianglePrismAxis(...)100%1818100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.AxisProjection.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.AxisProjection.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
 8namespace FixedMathSharp.Geometry;
 9
 10/// <content>
 11/// Provides wide-precision axis projection utilities for oriented boxes, including
 12/// rotated axis sign/numerator computation and relative local point coordinate
 13/// numerators used for high-precision separating axis and containment tests.
 14/// </content>
 15internal static partial class WideOrientedBox
 16{
 17    private static Signed576 GetBoxProjectionRadiusNumerator(
 18        in WideAxis3 axis,
 19        Vector3d halfExtents,
 20        in WideRationalBasis3d basis) =>
 2349221        WideArithmetic.AddSigned576(
 2349222            WideArithmetic.AddSigned576(
 2349223                WideArithmetic.MultiplySigned576(
 2349224                    GetMagnitude(WideRigidProjection.GetBasisAxisProjection(
 2349225                        axis,
 2349226                        basis.Xx,
 2349227                        basis.Xy,
 2349228                        basis.Xz)),
 2349229                    Signed192.Raw(halfExtents.X)),
 2349230                WideArithmetic.MultiplySigned576(
 2349231                    GetMagnitude(WideRigidProjection.GetBasisAxisProjection(
 2349232                        axis,
 2349233                        basis.Yx,
 2349234                        basis.Yy,
 2349235                        basis.Yz)),
 2349236                    Signed192.Raw(halfExtents.Y))),
 2349237            WideArithmetic.MultiplySigned576(
 2349238                GetMagnitude(WideRigidProjection.GetBasisAxisProjection(
 2349239                    axis,
 2349240                    basis.Zx,
 2349241                    basis.Zy,
 2349242                    basis.Zz)),
 2349243                Signed192.Raw(halfExtents.Z)));
 44
 45    private static Signed576 GetLocalBoxProjectionRadiusNumerator(
 46        in WideAxis3 axis,
 47        Vector3d halfExtents) =>
 558848        WideArithmetic.AddSigned576(
 558849            WideArithmetic.AddSigned576(
 558850                WideArithmetic.MultiplySigned576(
 558851                    Signed576.ExtendValue(GetMagnitude(axis.X)),
 558852                    halfExtents.X.m_rawValue),
 558853                WideArithmetic.MultiplySigned576(
 558854                    Signed576.ExtendValue(GetMagnitude(axis.Y)),
 558855                    halfExtents.Y.m_rawValue)),
 558856            WideArithmetic.MultiplySigned576(
 558857                Signed576.ExtendValue(GetMagnitude(axis.Z)),
 558858                halfExtents.Z.m_rawValue));
 59
 60    internal static int GetRotatedLocalProjectionSign(
 61        FixedQuaternion rotation,
 62        Vector3d localDirection,
 63        Vector3d worldDirection)
 64    {
 268565        WideRationalBasis3d basis = new(rotation);
 268566        WideAxis3 rotated = WideRigidProjection.TransformLocalAxis(
 268567            basis,
 268568            Signed192.Raw(localDirection.X),
 268569            Signed192.Raw(localDirection.Y),
 268570            Signed192.Raw(localDirection.Z));
 268571        return WideArithmetic.AddSigned576(
 268572            WideArithmetic.AddSigned576(
 268573                WideArithmetic.MultiplySigned320(
 268574                    rotated.X,
 268575                    Signed320.ExtendValue(
 268576                        Signed192.Raw(worldDirection.X))),
 268577                WideArithmetic.MultiplySigned320(
 268578                    rotated.Y,
 268579                    Signed320.ExtendValue(
 268580                        Signed192.Raw(worldDirection.Y)))),
 268581            WideArithmetic.MultiplySigned320(
 268582                rotated.Z,
 268583                Signed320.ExtendValue(
 268584                    Signed192.Raw(worldDirection.Z)))).Sign;
 85    }
 86
 87    internal static void GetRotatedLocalAxisNumerators(
 88        FixedQuaternion rotation,
 89        Vector3d localDirection,
 90        out Signed192 x,
 91        out Signed192 y,
 92        out Signed192 z,
 93        out Signed192 rotationDenominator)
 94    {
 706795        WideRationalBasis3d basis = new(rotation);
 706796        WideAxis3 rotated = WideRigidProjection.TransformLocalAxis(
 706797            basis,
 706798            Signed192.Raw(localDirection.X),
 706799            Signed192.Raw(localDirection.Y),
 7067100            Signed192.Raw(localDirection.Z));
 101        // A Q32.32 local component multiplied by a sum of quaternion products
 102        // remains strictly below the signed 192-bit range.
 7067103        _ = Signed192.TryNarrowSigned(rotated.X, out x);
 7067104        _ = Signed192.TryNarrowSigned(rotated.Y, out y);
 7067105        _ = Signed192.TryNarrowSigned(rotated.Z, out z);
 7067106        rotationDenominator = basis.Denominator;
 7067107    }
 108
 109    internal static void GetRelativeLocalPointNumerators(
 110        Vector3d point,
 111        Vector3d origin,
 112        FixedQuaternion rotation,
 113        out Signed192 x,
 114        out Signed192 y,
 115        out Signed192 z,
 116        out Signed192 rotationDenominator)
 117    {
 151118        WideRationalBasis3d basis = new(rotation);
 151119        GetRelativeLocalPointNumerators(
 151120            point,
 151121            origin,
 151122            basis,
 151123            out x,
 151124            out y,
 151125            out z);
 151126        rotationDenominator = basis.Denominator;
 151127    }
 128
 129    internal static void GetRelativeLocalPointNumerators(
 130        Vector3d point,
 131        Vector3d origin,
 132        in WideRationalBasis3d basis,
 133        out Signed192 x,
 134        out Signed192 y,
 135        out Signed192 z)
 136    {
 3401137        GetPointProjections(
 3401138            point,
 3401139            origin,
 3401140            basis,
 3401141            out Signed320 wideX,
 3401142            out Signed320 wideY,
 3401143            out Signed320 wideZ);
 144        // A full raw-domain point difference projected through a normalized
 145        // quaternion basis remains below the Signed192 limit.
 3401146        x = Signed192.NarrowProven(wideX);
 3401147        y = Signed192.NarrowProven(wideY);
 3401148        z = Signed192.NarrowProven(wideZ);
 3401149    }
 150}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Box.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.Box.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/// Implements oriented bounding box (OBB) vs OBB collision detection using the
 14/// separating axis theorem (SAT), computing contact anchor points on overlap.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    #region Nested Types
 19
 20    private readonly struct BoxPenetration
 21    {
 22        internal readonly int FirstAxisIndex;
 23        internal readonly int SecondAxisIndex;
 24        internal readonly bool Negate;
 25        internal readonly Signed576 Overlap;
 26        internal readonly Signed576 SquaredAxisLength;
 27
 28        internal BoxPenetration(
 29            int firstAxisIndex,
 30            int secondAxisIndex,
 31            bool negate,
 32            Signed576 overlap,
 33            Signed576 squaredAxisLength)
 34        {
 3035            FirstAxisIndex = firstAxisIndex;
 3036            SecondAxisIndex = secondAxisIndex;
 3037            Negate = negate;
 3038            Overlap = overlap;
 3039            SquaredAxisLength = squaredAxisLength;
 3040            HasValue = true;
 3041        }
 42
 43        internal bool HasValue { get; }
 44    }
 45
 46    #endregion
 47
 48    internal static bool TryGetContact(
 49        Vector3d firstCenter,
 50        FixedQuaternion firstOrientation,
 51        Vector3d firstHalfExtents,
 52        Vector3d secondCenter,
 53        FixedQuaternion secondOrientation,
 54        Vector3d secondHalfExtents,
 55        out FixedContactAnchors contact)
 56    {
 1457        WideRationalBasis3d firstBasis = new(firstOrientation);
 1458        WideRationalBasis3d secondBasis = new(secondOrientation);
 1459        WideRationalBasis3d relativeBasis =
 1460            WideRationalBasis3d.CreateRelative(firstBasis, secondBasis);
 1461        Signed320 commonDenominator =
 1462            Signed320.ExtendValue(relativeBasis.Denominator);
 1463        Span<Signed192> relative = stackalloc Signed192[9]
 1464        {
 1465            relativeBasis.Xx,
 1466            relativeBasis.Xy,
 1467            relativeBasis.Xz,
 1468            relativeBasis.Yx,
 1469            relativeBasis.Yy,
 1470            relativeBasis.Yz,
 1471            relativeBasis.Zx,
 1472            relativeBasis.Zy,
 1473            relativeBasis.Zz,
 1474        };
 1475        Span<Signed192> firstTranslation = stackalloc Signed192[3];
 1476        GetRelativeLocalPointNumerators(
 1477            secondCenter,
 1478            firstCenter,
 1479            firstBasis,
 1480            out firstTranslation[0],
 1481            out firstTranslation[1],
 1482            out firstTranslation[2]);
 1483        Span<Signed192> secondTranslation = stackalloc Signed192[3];
 1484        GetRelativeLocalPointNumerators(
 1485            secondCenter,
 1486            firstCenter,
 1487            secondBasis,
 1488            out secondTranslation[0],
 1489            out secondTranslation[1],
 1490            out secondTranslation[2]);
 91
 1492        var best = default(BoxPenetration);
 10093        for (int index = 0; index < 3; index++)
 94        {
 3895            if (!TryKeepFirstFaceAxis(
 3896                    index,
 3897                    firstHalfExtents,
 3898                    secondHalfExtents,
 3899                    relative,
 38100                    firstTranslation,
 38101                    firstBasis.Denominator,
 38102                    secondBasis.Denominator,
 38103                    relativeBasis.Denominator,
 38104                    ref best)
 38105                || !TryKeepSecondFaceAxis(
 38106                    index,
 38107                    firstHalfExtents,
 38108                    secondHalfExtents,
 38109                    relative,
 38110                    secondTranslation,
 38111                    firstBasis.Denominator,
 38112                    secondBasis.Denominator,
 38113                    relativeBasis.Denominator,
 38114                    ref best))
 115            {
 2116                contact = default;
 2117                return false;
 118            }
 119        }
 120
 90121        for (int firstIndex = 0; firstIndex < 3; firstIndex++)
 122        {
 266123            for (int secondIndex = 0; secondIndex < 3; secondIndex++)
 124            {
 100125                if (!TryKeepCrossAxis(
 100126                        firstIndex,
 100127                        secondIndex,
 100128                        firstHalfExtents,
 100129                        secondHalfExtents,
 100130                        relative,
 100131                        firstTranslation,
 100132                        firstBasis.Denominator,
 100133                        secondBasis.Denominator,
 100134                        ref best))
 135                {
 1136                    contact = default;
 1137                    return false;
 138                }
 139            }
 140        }
 141
 11142        Fixed64 depth =
 11143            WideArithmetic.GetRoundedNonNegativeNormalizedDepth(
 11144                best.Overlap,
 11145                best.SquaredAxisLength,
 11146                commonDenominator,
 11147                out bool depthIsClamped);
 11148        WideAxis3 axis = best.SecondAxisIndex < 0
 11149            ? firstBasis.GetAxis(best.FirstAxisIndex)
 11150            : best.FirstAxisIndex < 0
 11151                ? secondBasis.GetAxis(best.SecondAxisIndex)
 11152                : WideAxis3.Cross(
 11153                    firstBasis.GetAxis(best.FirstAxisIndex),
 11154                    secondBasis.GetAxis(best.SecondAxisIndex));
 11155        WideAxis3 orientedAxis = best.Negate ? -axis : axis;
 11156        Vector3d normal = WideNormalization.GetNormalized(
 11157            Signed576.ExtendValue(orientedAxis.X),
 11158            Signed576.ExtendValue(orientedAxis.Y),
 11159            Signed576.ExtendValue(orientedAxis.Z));
 11160        var secondOrigin = new FixedPointAnchor(
 11161            secondCenter,
 11162            FixedQuaternion.Identity,
 11163            Vector3d.Zero);
 11164        Vector3d firstLocalPoint = GetMatchedBoxSupportLocalPoint(
 11165            firstBasis,
 11166            firstHalfExtents,
 11167            firstCenter,
 11168            firstOrientation,
 11169            secondOrigin,
 11170            orientedAxis);
 11171        var firstAnchor = new FixedPointAnchor(
 11172            firstCenter,
 11173            firstOrientation,
 11174            firstLocalPoint);
 11175        Vector3d secondLocalPoint = GetMatchedBoxSupportLocalPoint(
 11176            secondBasis,
 11177            secondHalfExtents,
 11178            secondCenter,
 11179            secondOrientation,
 11180            firstAnchor,
 11181            -orientedAxis);
 11182        contact = new FixedContactAnchors(
 11183            firstAnchor,
 11184            new FixedPointAnchor(
 11185                secondCenter,
 11186                secondOrientation,
 11187                secondLocalPoint),
 11188            normal,
 11189            depth,
 11190            depthIsClamped);
 11191        return true;
 192    }
 193
 194    private static bool TryKeepFirstFaceAxis(
 195        int axisIndex,
 196        Vector3d firstHalfExtents,
 197        Vector3d secondHalfExtents,
 198        ReadOnlySpan<Signed192> relative,
 199        ReadOnlySpan<Signed192> firstTranslation,
 200        Signed192 firstDenominator,
 201        Signed192 secondDenominator,
 202        Signed192 relativeDenominator,
 203        ref BoxPenetration best)
 204    {
 38205        Signed320 radius = WideArithmetic.AddSigned320(
 38206            WideArithmetic.MultiplySigned192(
 38207                Signed192.Raw(firstHalfExtents[axisIndex]),
 38208                relativeDenominator),
 38209            GetExtentNumerator(
 38210                relative[axisIndex],
 38211                relative[3 + axisIndex],
 38212                relative[6 + axisIndex],
 38213                secondHalfExtents));
 214
 38215        Signed320 centerProjection = WideArithmetic.MultiplySigned192(
 38216            firstTranslation[axisIndex],
 38217            secondDenominator);
 38218        Signed320 overlap = WideArithmetic.SubtractSigned320(
 38219            radius,
 38220            GetMagnitude(centerProjection));
 38221        return TryKeepBoxPenetration(
 38222            axisIndex,
 38223            -1,
 38224            centerProjection.Sign < 0,
 38225            WideArithmetic.MultiplySigned320(overlap, firstDenominator),
 38226            Signed576.ExtendValue(
 38227                WideArithmetic.MultiplySigned192(
 38228                    firstDenominator,
 38229                    firstDenominator)),
 38230            ref best);
 231    }
 232
 233    private static bool TryKeepSecondFaceAxis(
 234        int axisIndex,
 235        Vector3d firstHalfExtents,
 236        Vector3d secondHalfExtents,
 237        ReadOnlySpan<Signed192> relative,
 238        ReadOnlySpan<Signed192> secondTranslation,
 239        Signed192 firstDenominator,
 240        Signed192 secondDenominator,
 241        Signed192 relativeDenominator,
 242        ref BoxPenetration best)
 243    {
 36244        int relativeOffset = axisIndex * 3;
 36245        Signed320 radius = WideArithmetic.AddSigned320(
 36246            WideArithmetic.MultiplySigned192(
 36247                Signed192.Raw(secondHalfExtents[axisIndex]),
 36248                relativeDenominator),
 36249            GetExtentNumerator(
 36250                relative[relativeOffset],
 36251                relative[relativeOffset + 1],
 36252                relative[relativeOffset + 2],
 36253                firstHalfExtents));
 254
 36255        Signed320 centerProjection = WideArithmetic.MultiplySigned192(
 36256            secondTranslation[axisIndex],
 36257            firstDenominator);
 36258        Signed320 overlap = WideArithmetic.SubtractSigned320(
 36259            radius,
 36260            GetMagnitude(centerProjection));
 36261        return TryKeepBoxPenetration(
 36262            -1,
 36263            axisIndex,
 36264            centerProjection.Sign < 0,
 36265            WideArithmetic.MultiplySigned320(overlap, secondDenominator),
 36266            Signed576.ExtendValue(
 36267                WideArithmetic.MultiplySigned192(
 36268                    secondDenominator,
 36269                    secondDenominator)),
 36270            ref best);
 271    }
 272
 273    private static bool TryKeepCrossAxis(
 274        int firstAxisIndex,
 275        int secondAxisIndex,
 276        Vector3d firstHalfExtents,
 277        Vector3d secondHalfExtents,
 278        ReadOnlySpan<Signed192> relative,
 279        ReadOnlySpan<Signed192> firstTranslation,
 280        Signed192 firstDenominator,
 281        Signed192 secondDenominator,
 282        ref BoxPenetration best)
 283    {
 100284        int firstNext = (firstAxisIndex + 1) % 3;
 100285        int firstLast = (firstAxisIndex + 2) % 3;
 100286        int secondNext = (secondAxisIndex + 1) % 3;
 100287        int secondLast = (secondAxisIndex + 2) % 3;
 100288        int secondOffset = secondAxisIndex * 3;
 100289        Signed192 firstComponent = relative[secondOffset + firstNext];
 100290        Signed192 secondComponent = relative[secondOffset + firstLast];
 100291        Signed320 squaredAxisLength = WideArithmetic.AddSigned320(
 100292            WideArithmetic.MultiplySigned192(
 100293                firstComponent,
 100294                firstComponent),
 100295            WideArithmetic.MultiplySigned192(
 100296                secondComponent,
 100297                secondComponent));
 100298        if (squaredAxisLength.IsZero)
 19299            return true;
 300
 81301        Signed320 radius = WideArithmetic.AddSigned320(
 81302            WideArithmetic.MultiplySigned192(
 81303                Signed192.Raw(firstHalfExtents[firstNext]),
 81304                GetMagnitude(secondComponent)),
 81305            WideArithmetic.MultiplySigned192(
 81306                Signed192.Raw(firstHalfExtents[firstLast]),
 81307                GetMagnitude(firstComponent)));
 81308        radius = WideArithmetic.AddSigned320(
 81309            radius,
 81310            WideArithmetic.AddSigned320(
 81311                WideArithmetic.MultiplySigned192(
 81312                    Signed192.Raw(secondHalfExtents[secondNext]),
 81313                    GetMagnitude(relative[(secondLast * 3) + firstAxisIndex])),
 81314                WideArithmetic.MultiplySigned192(
 81315                    Signed192.Raw(secondHalfExtents[secondLast]),
 81316                    GetMagnitude(relative[(secondNext * 3) + firstAxisIndex]))));
 81317        Signed320 centerProjection = WideArithmetic.SubtractSigned320(
 81318            WideArithmetic.MultiplySigned192(
 81319                firstTranslation[firstLast],
 81320                firstComponent),
 81321            WideArithmetic.MultiplySigned192(
 81322                firstTranslation[firstNext],
 81323                secondComponent));
 81324        Signed576 overlap = WideArithmetic.SubtractSigned576(
 81325            WideArithmetic.MultiplySigned320(radius, firstDenominator),
 81326            Signed576.ExtendValue(GetMagnitude(centerProjection)));
 81327        return TryKeepBoxPenetration(
 81328            firstAxisIndex,
 81329            secondAxisIndex,
 81330            centerProjection.Sign < 0,
 81331            WideArithmetic.MultiplySigned576(overlap, secondDenominator),
 81332            Signed576.ExtendValue(squaredAxisLength),
 81333            ref best);
 334    }
 335
 336    private static bool TryKeepBoxPenetration(
 337        int firstAxisIndex,
 338        int secondAxisIndex,
 339        bool negate,
 340        Signed576 overlap,
 341        Signed576 squaredAxisLength,
 342        ref BoxPenetration best)
 343    {
 155344        if (overlap.Sign < 0)
 3345            return false;
 346
 152347        if (!best.HasValue
 152348            || CompareBoxDepth(
 152349                overlap,
 152350                squaredAxisLength,
 152351                best.Overlap,
 152352                best.SquaredAxisLength) < 0)
 353        {
 30354            best = new BoxPenetration(
 30355                firstAxisIndex,
 30356                secondAxisIndex,
 30357                negate,
 30358                overlap,
 30359                squaredAxisLength);
 360        }
 152361        return true;
 362    }
 363
 364    private static int CompareBoxDepth(
 365        Signed576 candidateOverlap,
 366        Signed576 candidateSquaredAxisLength,
 367        Signed576 currentOverlap,
 368        Signed576 currentSquaredAxisLength)
 369    {
 140370        Span<ulong> candidate = stackalloc ulong[9];
 140371        Span<ulong> current = stackalloc ulong[9];
 140372        Span<ulong> candidateAxis = stackalloc ulong[9];
 140373        Span<ulong> currentAxis = stackalloc ulong[9];
 140374        Span<ulong> candidateSquared = stackalloc ulong[18];
 140375        Span<ulong> currentSquared = stackalloc ulong[18];
 140376        Span<ulong> candidateScaled =
 140377            stackalloc ulong[TriangleSweepMagnitudeWords];
 140378        Span<ulong> currentScaled =
 140379            stackalloc ulong[TriangleSweepMagnitudeWords];
 140380        WideArithmetic.GetMagnitude(candidateOverlap, candidate);
 140381        WideArithmetic.GetMagnitude(currentOverlap, current);
 140382        WideArithmetic.GetMagnitude(
 140383            candidateSquaredAxisLength,
 140384            candidateAxis);
 140385        WideArithmetic.GetMagnitude(
 140386            currentSquaredAxisLength,
 140387            currentAxis);
 140388        WideArithmetic.MultiplyMagnitudes(candidate, candidate, candidateSquared);
 140389        WideArithmetic.MultiplyMagnitudes(current, current, currentSquared);
 140390        WideArithmetic.MultiplyMagnitudes(
 140391            candidateSquared,
 140392            currentAxis,
 140393            candidateScaled);
 140394        WideArithmetic.MultiplyMagnitudes(
 140395            currentSquared,
 140396            candidateAxis,
 140397            currentScaled);
 140398        return WideArithmetic.CompareMagnitudeEqualLength(candidateScaled, currentScaled);
 399    }
 400}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Capsule.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.Capsule.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/// Contains oriented-box vs capsule contact generation logic using wide (extended-precision) arithmetic.
 14/// </content>
 15internal static partial class WideOrientedBox
 16{
 17    #region Nested Types
 18
 19    private readonly struct CapsulePenetration
 20    {
 21        internal readonly CapsuleAxis3 Axis;
 22        internal readonly bool Negate;
 23        internal readonly Signed704 WideRational;
 24        internal readonly Signed832 WideSquaredAxisLength;
 25        internal readonly int FeatureRank;
 26
 27        internal CapsulePenetration(
 28            CapsuleAxis3 axis,
 29            bool negate,
 30            Signed704 rational,
 31            Signed832 squaredAxisLength,
 32            int featureRank)
 33        {
 225134            Axis = axis;
 225135            Negate = negate;
 225136            WideRational = rational;
 225137            WideSquaredAxisLength = squaredAxisLength;
 225138            FeatureRank = featureRank;
 225139            HasValue = true;
 225140        }
 41
 42        internal bool HasValue { get; }
 43    }
 44
 45    #endregion
 46
 47    internal static bool TryGetCenteredCapsuleContact(
 48        Vector3d center,
 49        FixedQuaternion orientation,
 50        Vector3d halfExtents,
 51        Vector3d capsuleCenter,
 52        FixedQuaternion capsuleRotation,
 53        Vector3d localCapsuleAxisDirection,
 54        Fixed64 capsuleAxisLength,
 55        Fixed64 capsuleRadius,
 56        out FixedContactAnchors contact)
 57    {
 6858        WideRationalBasis3d boxBasis = new(orientation);
 6859        WideRationalBasis3d capsuleBasis = new(capsuleRotation);
 6860        WideRationalBasis3d relativeBasis =
 6861            WideRationalBasis3d.CreateRelative(boxBasis, capsuleBasis);
 6862        WideAxis3 capsuleAxis = WideRigidProjection.TransformLocalAxis(
 6863            relativeBasis,
 6864            Signed192.Raw(localCapsuleAxisDirection.X),
 6865            Signed192.Raw(localCapsuleAxisDirection.Y),
 6866            Signed192.Raw(localCapsuleAxisDirection.Z));
 6867        if (!TryGetCenteredCapsulePenetration(
 6868                center,
 6869                halfExtents,
 6870                capsuleCenter,
 6871                boxBasis,
 6872                capsuleBasis.Denominator,
 6873                capsuleAxis,
 6874                relativeBasis.Denominator,
 6875                GetScaledCapsuleAxisSquared(
 6876                    localCapsuleAxisDirection,
 6877                    capsuleBasis.Denominator),
 6878                GetCapsuleCenterAxisProjection(
 6879                    boxBasis.Denominator,
 6880                    center,
 6881                    capsuleCenter,
 6882                    capsuleBasis,
 6883                    localCapsuleAxisDirection),
 6884                capsuleAxisLength,
 6885                capsuleRadius,
 6886                out Signed192 commonDenominator,
 6887                out CapsulePenetration best))
 88        {
 389            contact = default;
 390            return false;
 91        }
 92
 6593        GetWideCapsuleDepth(
 6594            best.WideRational,
 6595            best.WideSquaredAxisLength,
 6596            commonDenominator,
 6597            capsuleRadius,
 6598            out Fixed64 depth,
 6599            out bool depthIsClamped);
 65100        CapsuleAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 65101        Signed576 worldX = Signed576.NarrowValue(
 65102            GetCapsuleBasisProjection(
 65103                orientedAxis,
 65104                boxBasis.Xx,
 65105                boxBasis.Yx,
 65106                boxBasis.Zx));
 65107        Signed576 worldY = Signed576.NarrowValue(
 65108            GetCapsuleBasisProjection(
 65109                orientedAxis,
 65110                boxBasis.Xy,
 65111                boxBasis.Yy,
 65112                boxBasis.Zy));
 65113        Signed576 worldZ = Signed576.NarrowValue(
 65114            GetCapsuleBasisProjection(
 65115                orientedAxis,
 65116                boxBasis.Xz,
 65117                boxBasis.Yz,
 65118                boxBasis.Zz));
 65119        Vector3d normal = WideNormalization.GetNormalized(
 65120            worldX,
 65121            worldY,
 65122            worldZ);
 65123        FixedPointAnchor capsuleAnchor = GetMatchedCapsuleSupportAnchor(
 65124            center,
 65125            capsuleCenter,
 65126            capsuleRotation,
 65127            localCapsuleAxisDirection,
 65128            capsuleAxisLength,
 65129            capsuleRadius,
 65130            normal,
 65131            !GetCapsuleAxisProjection(orientedAxis, capsuleAxis).IsZero);
 65132        Vector3d boxLocalPoint = GetMatchedBoxSupportLocalPoint(
 65133            boxBasis,
 65134            halfExtents,
 65135            center,
 65136            orientation,
 65137            capsuleAnchor,
 65138            orientedAxis.X,
 65139            orientedAxis.Y,
 65140            orientedAxis.Z);
 65141        contact = new FixedContactAnchors(
 65142            new FixedPointAnchor(
 65143                center,
 65144                orientation,
 65145                boxLocalPoint),
 65146            capsuleAnchor,
 65147            normal,
 65148            depth,
 65149            depthIsClamped);
 65150        return true;
 151    }
 152
 153    /// <summary>
 154    /// Returns whether the exact SAT admits a possible box/capsule overlap.
 155    /// Unrepresentable edge-axis witnesses are conservatively treated as
 156    /// inconclusive rather than as separation.
 157    /// </summary>
 158    internal static bool CanOverlapCenteredCapsule(
 159        Vector3d center,
 160        FixedQuaternion orientation,
 161        Vector3d halfExtents,
 162        Vector3d capsuleCenter,
 163        Vector3d capsuleAxisDirection,
 164        Fixed64 capsuleAxisLength,
 165        Fixed64 capsuleRadius)
 166    {
 3167        WideRationalBasis3d boxBasis = new(orientation);
 3168        GetDirectionProjections(
 3169            capsuleAxisDirection,
 3170            boxBasis,
 3171            out Signed320 capsuleAxisX,
 3172            out Signed320 capsuleAxisY,
 3173            out Signed320 capsuleAxisZ);
 3174        var authoredCapsuleAxis = new WideAxis3(
 3175            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.X)),
 3176            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.Y)),
 3177            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.Z)));
 3178        return TryGetCenteredCapsulePenetration(
 3179            center,
 3180            halfExtents,
 3181            capsuleCenter,
 3182            boxBasis,
 3183            Signed192.Signed(1L),
 3184            new WideAxis3(
 3185                capsuleAxisX,
 3186                capsuleAxisY,
 3187                capsuleAxisZ),
 3188            boxBasis.Denominator,
 3189            authoredCapsuleAxis.SquaredLength,
 3190            WideArithmetic.MultiplySigned576(
 3191                WideRigidProjection.GetWorldOriginDifferenceProjection(
 3192                    capsuleCenter,
 3193                    center,
 3194                    authoredCapsuleAxis),
 3195                boxBasis.Denominator),
 3196            capsuleAxisLength,
 3197            capsuleRadius,
 3198            out _,
 3199            out _);
 200    }
 201
 202    internal static bool CanOverlapCenteredCapsule(
 203        Vector3d center,
 204        FixedQuaternion orientation,
 205        Vector3d halfExtents,
 206        Vector3d capsuleCenter,
 207        FixedQuaternion capsuleRotation,
 208        Vector3d localCapsuleAxisDirection,
 209        Fixed64 capsuleAxisLength,
 210        Fixed64 capsuleRadius)
 211    {
 1026212        WideRationalBasis3d boxBasis = new(orientation);
 1026213        WideRationalBasis3d capsuleBasis = new(capsuleRotation);
 1026214        WideRationalBasis3d relativeBasis =
 1026215            WideRationalBasis3d.CreateRelative(boxBasis, capsuleBasis);
 1026216        WideAxis3 capsuleAxis = WideRigidProjection.TransformLocalAxis(
 1026217            relativeBasis,
 1026218            Signed192.Raw(localCapsuleAxisDirection.X),
 1026219            Signed192.Raw(localCapsuleAxisDirection.Y),
 1026220            Signed192.Raw(localCapsuleAxisDirection.Z));
 1026221        return TryGetCenteredCapsulePenetration(
 1026222            center,
 1026223            halfExtents,
 1026224            capsuleCenter,
 1026225            boxBasis,
 1026226            capsuleBasis.Denominator,
 1026227            capsuleAxis,
 1026228            relativeBasis.Denominator,
 1026229            GetScaledCapsuleAxisSquared(
 1026230                localCapsuleAxisDirection,
 1026231                capsuleBasis.Denominator),
 1026232            GetCapsuleCenterAxisProjection(
 1026233                boxBasis.Denominator,
 1026234                center,
 1026235                capsuleCenter,
 1026236                capsuleBasis,
 1026237                localCapsuleAxisDirection),
 1026238            capsuleAxisLength,
 1026239            capsuleRadius,
 1026240            out _,
 1026241            out _);
 242    }
 243
 244    private static bool TryGetCenteredCapsulePenetration(
 245        Vector3d boxCenter,
 246        Vector3d halfExtents,
 247        Vector3d capsuleCenter,
 248        in WideRationalBasis3d boxBasis,
 249        Signed192 translationScale,
 250        in WideAxis3 capsuleAxis,
 251        Signed192 capsuleAxisDenominator,
 252        Signed576 capsuleAxisSquared,
 253        Signed576 capsuleCenterAxisProjection,
 254        Fixed64 capsuleAxisLength,
 255        Fixed64 capsuleRadius,
 256        out Signed192 commonDenominator,
 257        out CapsulePenetration best)
 258    {
 1097259        Signed320 commonDenominatorWide = WideArithmetic.MultiplySigned192(
 1097260            capsuleAxisDenominator,
 1097261            Signed192.Raw(Fixed64.Two));
 1097262        commonDenominator = Signed192.NarrowProven(commonDenominatorWide);
 1097263        GetRelativeLocalPointNumerators(
 1097264            capsuleCenter,
 1097265            boxCenter,
 1097266            boxBasis,
 1097267            out Signed192 translationX,
 1097268            out Signed192 translationY,
 1097269            out Signed192 translationZ);
 1097270        var translation = new WideAxis3(
 1097271            Signed320.ExtendValue(translationX),
 1097272            Signed320.ExtendValue(translationY),
 1097273            Signed320.ExtendValue(translationZ));
 1097274        Signed320 centerScale = WideArithmetic.MultiplySigned192(
 1097275            translationScale,
 1097276            Signed192.Raw(Fixed64.Two));
 1097277        Signed320 axialScale = Signed320.ExtendValue(
 1097278            Signed192.Raw(capsuleAxisLength));
 1097279        var twiceTranslation = new WideAxis3(
 1097280            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 1097281                translation.X,
 1097282                centerScale)),
 1097283            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 1097284                translation.Y,
 1097285                centerScale)),
 1097286            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 1097287                translation.Z,
 1097288                centerScale)));
 1097289        var scaledExtents = new WideAxis3(
 1097290            WideArithmetic.MultiplySigned192(
 1097291                Signed192.Raw(halfExtents.X),
 1097292                commonDenominator),
 1097293            WideArithmetic.MultiplySigned192(
 1097294                Signed192.Raw(halfExtents.Y),
 1097295                commonDenominator),
 1097296            WideArithmetic.MultiplySigned192(
 1097297                Signed192.Raw(halfExtents.Z),
 1097298                commonDenominator));
 1097299        Signed704 vertexCapBound =
 1097300            WideArithmetic.MultiplySigned576ToSigned704(
 1097301                capsuleAxisSquared,
 1097302                WideArithmetic.MultiplySigned192(
 1097303                    boxBasis.Denominator,
 1097304                    Signed192.Raw(capsuleAxisLength)));
 1097305        Signed320 unit = Signed320.One;
 1097306        Span<WideAxis3> boxAxes = stackalloc WideAxis3[3]
 1097307        {
 1097308            new(default, default, unit),
 1097309            new(default, unit, default),
 1097310            new(unit, default, default),
 1097311        };
 1097312        best = default;
 8748313        for (int index = 0; index < boxAxes.Length; index++)
 314        {
 3282315            if (!TryKeepCapsuleAxis(
 3282316                    ToCapsuleAxis(boxAxes[index]),
 3282317                    scaledExtents,
 3282318                    twiceTranslation,
 3282319                    commonDenominator,
 3282320                    capsuleAxis,
 3282321                    axialScale,
 3282322                    capsuleRadius,
 3282323                    0,
 3282324                    ref best)
 3282325                || !TryKeepCapsuleAxis(
 3282326                    ToCapsuleAxis(WideAxis3.Cross(
 3282327                        boxAxes[index],
 3282328                        capsuleAxis)),
 3282329                    scaledExtents,
 3282330                    twiceTranslation,
 3282331                    commonDenominator,
 3282332                    capsuleAxis,
 3282333                    axialScale,
 3282334                    capsuleRadius,
 3282335                    1,
 3282336                    ref best))
 337            {
 5338                return false;
 339            }
 340        }
 341
 1092342        for (int vertexIndex = 0;
 9820343            vertexIndex < FixedOrientedBox.CornerCount;
 8728344            vertexIndex++)
 345        {
 8730346            Vector3d localVertex = new(
 8730347                (vertexIndex & 1) == 0
 8730348                    ? -halfExtents.X
 8730349                    : halfExtents.X,
 8730350                (vertexIndex & 2) == 0
 8730351                    ? -halfExtents.Y
 8730352                    : halfExtents.Y,
 8730353                (vertexIndex & 4) == 0
 8730354                    ? -halfExtents.Z
 8730355                    : halfExtents.Z);
 8730356            if (!TryKeepCapsuleAxis(
 8730357                    GetLocalVertexToCapsuleAxis(
 8730358                        translation,
 8730359                        boxBasis.Denominator,
 8730360                        localVertex,
 8730361                        capsuleAxis,
 8730362                        capsuleAxisSquared,
 8730363                        capsuleCenterAxisProjection,
 8730364                        centerScale,
 8730365                        axialScale,
 8730366                        vertexCapBound),
 8730367                    scaledExtents,
 8730368                    twiceTranslation,
 8730369                    commonDenominator,
 8730370                    capsuleAxis,
 8730371                    axialScale,
 8730372                    capsuleRadius,
 8730373                    1,
 8730374                    ref best))
 375            {
 2376                return false;
 377            }
 378        }
 379
 8718380        for (int edgeAxisIndex = 0; edgeAxisIndex < 3; edgeAxisIndex++)
 381        {
 19616382            for (int firstSign = -1; firstSign <= 1; firstSign += 2)
 383            {
 6539384                for (int secondSign = -1;
 19615385                    secondSign <= 1;
 13076386                    secondSign += 2)
 387                {
 13077388                    Vector3d localEdgeCenter = GetLocalEdgeCenter(
 13077389                        halfExtents,
 13077390                        edgeAxisIndex,
 13077391                        firstSign,
 13077392                        secondSign);
 13077393                    WideAxis3 edgeDifference =
 13077394                        GetLocalPointToCapsuleCenterAxis(
 13077395                            translation,
 13077396                            boxBasis.Denominator,
 13077397                            localEdgeCenter);
 13077398                    Signed320 edgeBound = edgeAxisIndex switch
 13077399                    {
 4360400                        0 => scaledExtents.X,
 4360401                        1 => scaledExtents.Y,
 4357402                        _ => scaledExtents.Z,
 13077403                    };
 13077404                    for (int endpointSign = -1;
 39229405                        endpointSign <= 1;
 26152406                        endpointSign += 2)
 407                    {
 26153408                        if (!TryKeepCapsuleAxis(
 26153409                                GetCapsuleEndpointToBoxEdgeAxis(
 26153410                                    edgeDifference,
 26153411                                    centerScale,
 26153412                                    axialScale,
 26153413                                    edgeAxisIndex,
 26153414                                    endpointSign,
 26153415                                    capsuleAxis,
 26153416                                    edgeBound),
 26153417                                scaledExtents,
 26153418                                twiceTranslation,
 26153419                                commonDenominator,
 26153420                                capsuleAxis,
 26153421                                axialScale,
 26153422                                capsuleRadius,
 26153423                                1,
 26153424                                ref best))
 425                        {
 1426                            return false;
 427                        }
 428                    }
 429                }
 430            }
 431        }
 432
 1089433        return true;
 434    }
 435
 436    private static Vector3d GetLocalEdgeCenter(
 437        Vector3d halfExtents,
 438        int edgeAxisIndex,
 439        int firstSign,
 440        int secondSign) =>
 13077441        edgeAxisIndex switch
 13077442        {
 4360443            0 => new Vector3d(
 4360444                Fixed64.Zero,
 4360445                firstSign * halfExtents.Y,
 4360446                secondSign * halfExtents.Z),
 4360447            1 => new Vector3d(
 4360448                firstSign * halfExtents.X,
 4360449                Fixed64.Zero,
 4360450                secondSign * halfExtents.Z),
 4357451            _ => new Vector3d(
 4357452                firstSign * halfExtents.X,
 4357453                secondSign * halfExtents.Y,
 4357454                Fixed64.Zero),
 13077455        };
 456
 457    private static Vector3d GetMatchedBoxSupportLocalPoint(
 458        WideRationalBasis3d basis,
 459        Vector3d halfExtents,
 460        Vector3d boxCenter,
 461        FixedQuaternion boxRotation,
 462        in FixedPointAnchor otherAnchor,
 463        WideAxis3 featureAxis)
 22464        => GetMatchedBoxSupportLocalPoint(
 22465            basis,
 22466            halfExtents,
 22467            boxCenter,
 22468            boxRotation,
 22469            otherAnchor,
 22470            WideRigidProjection.GetBasisAxisProjection(
 22471                featureAxis,
 22472                basis.Xx,
 22473                basis.Xy,
 22474                basis.Xz),
 22475            WideRigidProjection.GetBasisAxisProjection(
 22476                featureAxis,
 22477                basis.Yx,
 22478                basis.Yy,
 22479                basis.Yz),
 22480            WideRigidProjection.GetBasisAxisProjection(
 22481                featureAxis,
 22482                basis.Zx,
 22483                basis.Zy,
 22484                basis.Zz));
 485
 486    private static Vector3d GetMatchedBoxSupportLocalPoint(
 487        WideRationalBasis3d basis,
 488        Vector3d halfExtents,
 489        Vector3d boxCenter,
 490        FixedQuaternion boxRotation,
 491        in FixedPointAnchor otherAnchor,
 492        Signed576 xProjection,
 493        Signed576 yProjection,
 494        Signed576 zProjection)
 495    {
 87496        var boxOrigin = new FixedPointAnchor(
 87497            boxCenter,
 87498            FixedQuaternion.Identity,
 87499            Vector3d.Zero);
 87500        bool hasTargetLocalPoint = otherAnchor.TryGetLocalPointIn(
 87501            boxCenter,
 87502            boxRotation,
 87503            out Vector3d targetLocalPoint);
 87504        Fixed64 localX = GetMatchedSupportCoordinate(
 87505            otherAnchor,
 87506            boxOrigin,
 87507            GetAxis(
 87508                basis.Xx,
 87509                basis.Xy,
 87510                basis.Xz,
 87511                basis.Denominator,
 87512                false),
 87513            halfExtents.X,
 87514            xProjection);
 87515        Fixed64 localY = GetMatchedSupportCoordinate(
 87516            otherAnchor,
 87517            boxOrigin,
 87518            GetAxis(
 87519                basis.Yx,
 87520                basis.Yy,
 87521                basis.Yz,
 87522                basis.Denominator,
 87523                false),
 87524            halfExtents.Y,
 87525            yProjection);
 87526        Fixed64 localZ = GetMatchedSupportCoordinate(
 87527            otherAnchor,
 87528            boxOrigin,
 87529            GetAxis(
 87530                basis.Zx,
 87531                basis.Zy,
 87532                basis.Zz,
 87533                basis.Denominator,
 87534                false),
 87535            halfExtents.Z,
 87536            zProjection);
 87537        if (!hasTargetLocalPoint)
 1538            return new Vector3d(localX, localY, localZ);
 86539        if (xProjection.IsZero)
 540        {
 20541            localX = FixedMath.Clamp(
 20542                targetLocalPoint.X,
 20543                -halfExtents.X,
 20544                halfExtents.X);
 545        }
 86546        if (yProjection.IsZero)
 547        {
 68548            localY = FixedMath.Clamp(
 68549                targetLocalPoint.Y,
 68550                -halfExtents.Y,
 68551                halfExtents.Y);
 552        }
 86553        if (zProjection.IsZero)
 554        {
 65555            localZ = FixedMath.Clamp(
 65556                targetLocalPoint.Z,
 65557                -halfExtents.Z,
 65558                halfExtents.Z);
 559        }
 86560        return new Vector3d(localX, localY, localZ);
 561    }
 562
 563    private static FixedPointAnchor GetMatchedCapsuleSupportAnchor(
 564        Vector3d boxCenter,
 565        Vector3d capsuleCenter,
 566        FixedQuaternion capsuleRotation,
 567        Vector3d localCapsuleAxisDirection,
 568        Fixed64 capsuleAxisLength,
 569        Fixed64 capsuleRadius,
 570        Vector3d boxToCapsuleNormal,
 571        bool hasAxialProjection)
 572    {
 65573        if (hasAxialProjection)
 574        {
 44575            return WideGeometry.GetCenteredCapsuleSupportAnchor(
 44576                capsuleCenter,
 44577                capsuleRotation,
 44578                localCapsuleAxisDirection,
 44579                capsuleAxisLength,
 44580                capsuleRadius,
 44581                -boxToCapsuleNormal);
 582        }
 583
 21584        Vector3d localNormal = WideNormalization.GetNormalized(
 21585            capsuleRotation.Inverse().Rotate(-boxToCapsuleNormal));
 21586        return FixedSegment.GetSurfaceAnchorOnCenteredCapsule(
 21587            boxCenter,
 21588            capsuleCenter,
 21589            capsuleRotation,
 21590            localCapsuleAxisDirection,
 21591            capsuleAxisLength,
 21592            capsuleRadius,
 21593            localNormal);
 594    }
 595
 596    private static Fixed64 GetMatchedSupportCoordinate(
 597        in FixedPointAnchor targetAnchor,
 598        in FixedPointAnchor boxOrigin,
 599        Vector3d boxAxis,
 600        Fixed64 extent,
 601        Signed576 directionProjection)
 602    {
 261603        bool isFree = directionProjection.IsZero;
 261604        if (!isFree && directionProjection.Sign > 0)
 92605            return extent;
 169606        if (!isFree && directionProjection.Sign < 0)
 14607            return -extent;
 608
 155609        WidePointAnchor3d.GetProjectedOffsetRatio(
 155610            targetAnchor,
 155611            boxOrigin,
 155612            boxAxis,
 155613            out Signed704 numerator,
 155614            out Signed704 denominator);
 615        // A free coordinate belongs to the retained SAT feature. If its
 616        // matched capsule point lay outside this box slab, the corresponding
 617        // cross or endpoint-edge candidate would replace that feature.
 155618        _ = Fixed64.TryGetSignedRawRatio(
 155619            numerator,
 155620            denominator,
 155621            out Fixed64 target);
 155622        return FixedMath.Clamp(target, -extent, extent);
 623    }
 624
 625}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CapsuleEdges.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.CapsuleEdges.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/// Handles wide-precision capsule edge tests against oriented boxes,
 14/// including axis projection and containment calculations.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    #region Nested Types
 19
 20    private readonly struct CapsuleAxis3
 21    {
 22        internal readonly Signed576 X;
 23        internal readonly Signed576 Y;
 24        internal readonly Signed576 Z;
 25
 26        internal CapsuleAxis3(Signed576 x, Signed576 y, Signed576 z)
 27        {
 7062528            X = x;
 7062529            Y = y;
 7062530            Z = z;
 7062531        }
 32
 4444833        internal bool IsZero => X.IsZero && Y.IsZero && Z.IsZero;
 34
 35        public static CapsuleAxis3 operator -(CapsuleAxis3 value) =>
 2436            new(
 2437                WideArithmetic.SubtractSigned576(default, value.X),
 2438                WideArithmetic.SubtractSigned576(default, value.Y),
 2439                WideArithmetic.SubtractSigned576(default, value.Z));
 40    }
 41
 42    #endregion
 43
 44    private static CapsuleAxis3 GetVertexToCapsuleAxis(
 45        Vector3d boxCenter,
 46        Vector3d capsuleCenter,
 47        WideRationalBasis3d basis,
 48        Vector3d localVertex,
 49        WideAxis3 capsuleAxis,
 50        Signed192 capsuleAxisDenominator,
 51        Fixed64 capsuleAxisLength)
 52    {
 25653        WideAxis3 centerAxis = GetCornerToAxisCenterAxis3D(
 25654            boxCenter,
 25655            capsuleCenter,
 25656            basis,
 25657            localVertex,
 25658            capsuleAxisDenominator);
 25659        Signed576 projection = WideAxis3.Dot(
 25660            centerAxis,
 25661            capsuleAxis);
 25662        Signed576 capsuleSquared = capsuleAxis.SquaredLength;
 25663        Signed576 projectionAtHalfLength = WideArithmetic.MultiplySigned576(
 25664            GetMagnitude(projection),
 25665            Signed192.Raw(Fixed64.Two));
 25666        Signed576 capBound = WideArithmetic.MultiplySigned576(
 25667            WideArithmetic.MultiplySigned576(
 25668                capsuleSquared,
 25669                Signed192.Raw(capsuleAxisLength)),
 25670            basis.Denominator);
 25671        if (WideArithmetic.CompareNonNegative(
 25672                projectionAtHalfLength,
 25673                capBound) >= 0)
 74        {
 25275            int endpointSign = projection.Sign > 0 ? -1 : 1;
 25276            return ToCapsuleAxis(GetCornerToAxisEndpointAxis3D(
 25277                boxCenter,
 25278                capsuleCenter,
 25279                basis,
 25280                localVertex,
 25281                capsuleAxis,
 25282                capsuleAxisDenominator,
 25283                capsuleAxisLength,
 25284                endpointSign));
 85        }
 86
 487        return GetPerpendicularAxis(
 488            centerAxis,
 489            capsuleAxis,
 490            capsuleSquared,
 491            projection);
 92    }
 93
 94    private static CapsuleAxis3 GetLocalVertexToCapsuleAxis(
 95        in WideAxis3 translation,
 96        Signed192 boxDenominator,
 97        Vector3d localVertex,
 98        in WideAxis3 capsuleAxis,
 99        in Signed576 capsuleAxisSquared,
 100        in Signed576 capsuleCenterAxisProjection,
 101        in Signed320 centerScale,
 102        in Signed320 axialScale,
 103        in Signed704 capBound)
 104    {
 8730105        WideAxis3 difference = GetLocalPointToCapsuleCenterAxis(
 8730106            translation,
 8730107            boxDenominator,
 8730108            localVertex);
 8730109        var localVertexAxis = new WideAxis3(
 8730110            Signed320.ExtendValue(Signed192.Raw(localVertex.X)),
 8730111            Signed320.ExtendValue(Signed192.Raw(localVertex.Y)),
 8730112            Signed320.ExtendValue(Signed192.Raw(localVertex.Z)));
 8730113        Signed576 projection = WideArithmetic.SubtractSigned576(
 8730114            capsuleCenterAxisProjection,
 8730115            WideAxis3.Dot(localVertexAxis, capsuleAxis));
 8730116        Signed704 projectionAtHalfLength =
 8730117            WideArithmetic.MultiplySigned576ToSigned704(
 8730118                GetMagnitude(projection),
 8730119                centerScale);
 8730120        if (WideArithmetic.CompareNonNegative(
 8730121                projectionAtHalfLength,
 8730122                capBound) >= 0)
 123        {
 4440124            return GetLocalPointToCapsuleEndpointAxis(
 4440125                difference,
 4440126                centerScale,
 4440127                axialScale,
 4440128                capsuleAxis,
 4440129                projection.Sign > 0 ? -1 : 1);
 130        }
 131
 4290132        var scaledDifference = new WideAxis3(
 4290133            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 4290134                difference.X,
 4290135                Signed320.ExtendValue(boxDenominator))),
 4290136            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 4290137                difference.Y,
 4290138                Signed320.ExtendValue(boxDenominator))),
 4290139            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 4290140                difference.Z,
 4290141                Signed320.ExtendValue(boxDenominator))));
 4290142        return GetPerpendicularAxis(
 4290143            scaledDifference,
 4290144            capsuleAxis,
 4290145            capsuleAxisSquared,
 4290146            projection);
 147    }
 148
 149    private static CapsuleAxis3 GetCapsuleEndpointToBoxEdgeAxis(
 150        in WideAxis3 edgeDifference,
 151        in Signed320 centerScale,
 152        in Signed320 axialScale,
 153        int edgeAxisIndex,
 154        int endpointSign,
 155        in WideAxis3 capsuleAxis,
 156        in Signed320 edgeBound)
 157    {
 26153158        CapsuleAxis3 endpointAxis = GetLocalPointToCapsuleEndpointAxis(
 26153159            edgeDifference,
 26153160            centerScale,
 26153161            axialScale,
 26153162            capsuleAxis,
 26153163            endpointSign);
 26153164        Signed576 projection = edgeAxisIndex switch
 26153165        {
 8720166            0 => endpointAxis.X,
 8720167            1 => endpointAxis.Y,
 8713168            _ => endpointAxis.Z,
 26153169        };
 26153170        Signed576 wideEdgeBound = Signed576.ExtendValue(edgeBound);
 26153171        Signed576 edgeComponent = default;
 26153172        if (WideArithmetic.CompareNonNegative(
 26153173                GetMagnitude(projection),
 26153174                wideEdgeBound) >= 0)
 175        {
 4556176            edgeComponent = projection.Sign < 0
 4556177                ? WideArithmetic.AddSigned576(projection, wideEdgeBound)
 4556178                : WideArithmetic.SubtractSigned576(projection, wideEdgeBound);
 179        }
 180
 26153181        return edgeAxisIndex switch
 26153182        {
 8720183            0 => new CapsuleAxis3(
 8720184                edgeComponent,
 8720185                endpointAxis.Y,
 8720186                endpointAxis.Z),
 8720187            1 => new CapsuleAxis3(
 8720188                endpointAxis.X,
 8720189                edgeComponent,
 8720190                endpointAxis.Z),
 8713191            _ => new CapsuleAxis3(
 8713192                endpointAxis.X,
 8713193                endpointAxis.Y,
 8713194                edgeComponent),
 26153195        };
 196    }
 197
 198    private static WideAxis3 GetLocalPointToCapsuleCenterAxis(
 199        in WideAxis3 translation,
 200        Signed192 boxDenominator,
 201        Vector3d localPoint) =>
 21807202        new(
 21807203            WideArithmetic.SubtractSigned320(
 21807204                translation.X,
 21807205                WideArithmetic.MultiplySigned192(
 21807206                    Signed192.Raw(localPoint.X),
 21807207                    boxDenominator)),
 21807208            WideArithmetic.SubtractSigned320(
 21807209                translation.Y,
 21807210                WideArithmetic.MultiplySigned192(
 21807211                    Signed192.Raw(localPoint.Y),
 21807212                    boxDenominator)),
 21807213            WideArithmetic.SubtractSigned320(
 21807214                translation.Z,
 21807215                WideArithmetic.MultiplySigned192(
 21807216                    Signed192.Raw(localPoint.Z),
 21807217                    boxDenominator)));
 218
 219    private static CapsuleAxis3 GetLocalPointToCapsuleEndpointAxis(
 220        in WideAxis3 difference,
 221        in Signed320 centerScale,
 222        in Signed320 axialScale,
 223        in WideAxis3 capsuleAxis,
 224        int endpointSign)
 225    {
 30593226        return new CapsuleAxis3(
 30593227            GetLocalEndpointComponent(
 30593228                difference.X,
 30593229                capsuleAxis.X,
 30593230                centerScale,
 30593231                axialScale,
 30593232                endpointSign),
 30593233            GetLocalEndpointComponent(
 30593234                difference.Y,
 30593235                capsuleAxis.Y,
 30593236                centerScale,
 30593237                axialScale,
 30593238                endpointSign),
 30593239            GetLocalEndpointComponent(
 30593240                difference.Z,
 30593241                capsuleAxis.Z,
 30593242                centerScale,
 30593243                axialScale,
 30593244                endpointSign));
 245    }
 246
 247    private static Signed576 GetLocalEndpointComponent(
 248        in Signed320 difference,
 249        in Signed320 axis,
 250        in Signed320 centerScale,
 251        in Signed320 axialScale,
 252        int endpointSign)
 253    {
 91779254        Signed576 center = WideArithmetic.MultiplySigned320(
 91779255            difference,
 91779256            centerScale);
 91779257        Signed576 axial = WideArithmetic.MultiplySigned320(
 91779258            axis,
 91779259            axialScale);
 91779260        return endpointSign < 0
 91779261            ? WideArithmetic.SubtractSigned576(center, axial)
 91779262            : WideArithmetic.AddSigned576(center, axial);
 263    }
 264
 265    private static Signed576 GetScaledCapsuleAxisSquared(
 266        Vector3d localAxis,
 267        Signed192 basisDenominator)
 268    {
 1094269        var rawAxis = new WideAxis3(
 1094270            Signed320.ExtendValue(Signed192.Raw(localAxis.X)),
 1094271            Signed320.ExtendValue(Signed192.Raw(localAxis.Y)),
 1094272            Signed320.ExtendValue(Signed192.Raw(localAxis.Z)));
 1094273        Signed320 denominatorSquared = WideArithmetic.MultiplySigned192(
 1094274            basisDenominator,
 1094275            basisDenominator);
 276        // Rotation preserves length, so |C*u|^2 = Dc^2*|u|^2. A validated
 277        // Q32.32 unit axis and normalized-quaternion denominator keep this
 278        // exact product below 196 bits.
 1094279        return Signed576.NarrowValue(
 1094280            WideArithmetic.MultiplySigned576ToSigned704(
 1094281                rawAxis.SquaredLength,
 1094282                denominatorSquared));
 283    }
 284
 285    private static Signed576 GetCapsuleCenterAxisProjection(
 286        Signed192 boxDenominator,
 287        Vector3d boxCenter,
 288        Vector3d capsuleCenter,
 289        in WideRationalBasis3d capsuleBasis,
 290        Vector3d localCapsuleAxis)
 291    {
 1094292        GetRelativeLocalPointNumerators(
 1094293            capsuleCenter,
 1094294            boxCenter,
 1094295            capsuleBasis,
 1094296            out Signed192 translationX,
 1094297            out Signed192 translationY,
 1094298            out Signed192 translationZ);
 1094299        var capsuleTranslation = new WideAxis3(
 1094300            Signed320.ExtendValue(translationX),
 1094301            Signed320.ExtendValue(translationY),
 1094302            Signed320.ExtendValue(translationZ));
 1094303        var rawAxis = new WideAxis3(
 1094304            Signed320.ExtendValue(Signed192.Raw(localCapsuleAxis.X)),
 1094305            Signed320.ExtendValue(Signed192.Raw(localCapsuleAxis.Y)),
 1094306            Signed320.ExtendValue(Signed192.Raw(localCapsuleAxis.Z)));
 307        // (C^T*delta) dot u = delta dot (C*u). Multiplying by Db gives
 308        // the same reduced scalar as each old world vertex projection,
 309        // without constructing either world vector per vertex.
 1094310        return WideArithmetic.MultiplySigned576(
 1094311            WideAxis3.Dot(capsuleTranslation, rawAxis),
 1094312            boxDenominator);
 313    }
 314
 315    private static WideAxis3 GetCornerToAxisCenterAxis3D(
 316        Vector3d boxCenter,
 317        Vector3d axisCenter,
 318        WideRationalBasis3d basis,
 319        Vector3d localCorner,
 320        Signed192 axisDenominator) =>
 256321        new(
 256322            GetCornerToAxisCenterComponent(
 256323                boxCenter.X,
 256324                axisCenter.X,
 256325                basis.Xx,
 256326                basis.Yx,
 256327                basis.Zx,
 256328                basis.Denominator,
 256329                localCorner,
 256330                axisDenominator),
 256331            GetCornerToAxisCenterComponent(
 256332                boxCenter.Y,
 256333                axisCenter.Y,
 256334                basis.Xy,
 256335                basis.Yy,
 256336                basis.Zy,
 256337                basis.Denominator,
 256338                localCorner,
 256339                axisDenominator),
 256340            GetCornerToAxisCenterComponent(
 256341                boxCenter.Z,
 256342                axisCenter.Z,
 256343                basis.Xz,
 256344                basis.Yz,
 256345                basis.Zz,
 256346                basis.Denominator,
 256347                localCorner,
 256348                axisDenominator));
 349
 350    private static Signed320 GetCornerToAxisCenterComponent(
 351        Fixed64 boxCenter,
 352        Fixed64 axisCenter,
 353        Signed192 basisX,
 354        Signed192 basisY,
 355        Signed192 basisZ,
 356        Signed192 basisDenominator,
 357        Vector3d localCorner,
 358        Signed192 axisDenominator)
 359    {
 768360        Signed320 corner = GetLocalOffsetNumerator(
 768361            basisX,
 768362            basisY,
 768363            basisZ,
 768364            localCorner);
 768365        Signed576 center = WideArithmetic.MultiplySigned320(
 768366            WideArithmetic.MultiplySigned192(
 768367                WideArithmetic.SubtractSigned192(
 768368                    Signed192.Raw(axisCenter),
 768369                    Signed192.Raw(boxCenter)),
 768370                basisDenominator),
 768371            Signed320.ExtendValue(axisDenominator));
 768372        Signed576 cornerWide = WideArithmetic.MultiplySigned320(
 768373            corner,
 768374            Signed320.ExtendValue(axisDenominator));
 375        // The 65-bit center delta and at-most-134-bit rotated corner each
 376        // retain both at-most-68-bit rigid denominators. Their difference
 377        // needs at most 203 signed bits and therefore fits Signed320 exactly.
 768378        return Signed320.NarrowValue(WideArithmetic.SubtractSigned576(center, cornerWide));
 379    }
 380
 381    private static CapsuleAxis3 GetPerpendicularAxis(
 382        in WideAxis3 difference,
 383        in WideAxis3 lineAxis,
 384        in Signed576 lineSquared,
 385        in Signed576 projection) =>
 4567386        new(
 4567387            GetPerpendicularComponent(
 4567388                difference.X,
 4567389                lineAxis.X,
 4567390                lineSquared,
 4567391                projection),
 4567392            GetPerpendicularComponent(
 4567393                difference.Y,
 4567394                lineAxis.Y,
 4567395                lineSquared,
 4567396                projection),
 4567397            GetPerpendicularComponent(
 4567398                difference.Z,
 4567399                lineAxis.Z,
 4567400                lineSquared,
 4567401                projection));
 402
 403    private static Signed576 GetPerpendicularComponent(
 404        in Signed320 difference,
 405        in Signed320 line,
 406        in Signed576 lineSquared,
 407        in Signed576 projection)
 408    {
 13701409        Signed704 first = WideArithmetic.MultiplySigned576ToSigned704(
 13701410            lineSquared,
 13701411            difference);
 13701412        Signed704 second = WideArithmetic.MultiplySigned576ToSigned704(
 13701413            projection,
 13701414            line);
 415        // Vertex-to-axis terms need at most 411 signed bits; endpoint-to-edge
 416        // terms need at most 377. Their difference therefore fits Signed576
 417        // exactly before it becomes a candidate separating axis.
 13701418        return Signed576.NarrowValue(
 13701419            WideArithmetic.SubtractSigned704(first, second));
 420    }
 421
 422    private static bool TryKeepCapsuleAxis(
 423        in CapsuleAxis3 axis,
 424        in WideAxis3 scaledExtents,
 425        in WideAxis3 twiceTranslation,
 426        Signed192 commonDenominator,
 427        in WideAxis3 capsuleAxis,
 428        in Signed320 axialScale,
 429        Fixed64 capsuleRadius,
 430        int featureRank,
 431        ref CapsulePenetration best)
 432    {
 41445433        if (axis.IsZero)
 1047434            return true;
 435
 40398436        Signed704 boxRadius = GetLocalCapsuleBoxRadius(
 40398437            axis,
 40398438            scaledExtents);
 40398439        Signed704 centerProjection = GetLocalCapsuleCenterProjection(
 40398440            axis,
 40398441            twiceTranslation);
 40398442        bool negate = centerProjection.Sign < 0;
 40398443        Signed704 rational = WideArithmetic.SubtractSigned704(
 40398444            boxRadius,
 40398445            negate
 40398446                ? WideArithmetic.SubtractSigned704(
 40398447                    default,
 40398448                    centerProjection)
 40398449                : centerProjection);
 450        // Every candidate norm is strictly below 2^411. Normalized quaternion
 451        // denominators are below 2^65, so the relative-axis norm
 452        // |A| = Db*Dc*|u| is below 2^163 for a validated Q32.32 unit axis.
 453        // Cauchy therefore bounds |candidate dot A| below 2^574, inside the
 454        // positive 575-bit magnitude of Signed576. This correlated norm bound
 455        // is tighter than summing independent component-width maxima.
 40398456        Signed576 alignment = Signed576.NarrowValue(
 40398457            GetCapsuleAxisProjection(axis, capsuleAxis));
 40398458        Signed704 axial = WideArithmetic.MultiplySigned576ToSigned704(
 40398459            GetMagnitude(alignment),
 40398460            axialScale);
 40398461        rational = WideArithmetic.AddSigned704(rational, axial);
 462
 40398463        Signed832 squaredAxisLength = GetCapsuleSquaredLength(axis);
 40398464        if (rational.Sign < 0
 40398465            && !IsWideCapsuleRadicalAtLeastRational(
 40398466                squaredAxisLength,
 40398467                commonDenominator,
 40398468                capsuleRadius,
 40398469                rational))
 470        {
 8471            return false;
 472        }
 473
 40390474        bool shouldReplace = !best.HasValue;
 40390475        if (best.HasValue)
 476        {
 39295477            int comparison = CompareWideCapsuleDepth(
 39295478                rational,
 39295479                squaredAxisLength,
 39295480                best.WideRational,
 39295481                best.WideSquaredAxisLength);
 39295482            shouldReplace = comparison < 0
 39295483                || (comparison == 0 && featureRank < best.FeatureRank);
 484        }
 40390485        if (shouldReplace)
 486        {
 2251487            best = new CapsulePenetration(
 2251488                axis,
 2251489                negate,
 2251490                rational,
 2251491                squaredAxisLength,
 2251492                featureRank);
 493        }
 40390494        return true;
 495    }
 496
 497    private static Signed704 GetLocalCapsuleBoxRadius(
 498        in CapsuleAxis3 axis,
 499        in WideAxis3 scaledExtents) =>
 40398500        WideArithmetic.AddSigned704(
 40398501            WideArithmetic.AddSigned704(
 40398502                WideArithmetic.MultiplySigned576ToSigned704(
 40398503                    GetMagnitude(axis.X),
 40398504                    scaledExtents.X),
 40398505                WideArithmetic.MultiplySigned576ToSigned704(
 40398506                    GetMagnitude(axis.Y),
 40398507                    scaledExtents.Y)),
 40398508            WideArithmetic.MultiplySigned576ToSigned704(
 40398509                GetMagnitude(axis.Z),
 40398510                scaledExtents.Z));
 511
 512    private static Signed704 GetLocalCapsuleCenterProjection(
 513        in CapsuleAxis3 axis,
 514        in WideAxis3 twiceTranslation) =>
 40398515        WideArithmetic.AddSigned704(
 40398516            WideArithmetic.AddSigned704(
 40398517                WideArithmetic.MultiplySigned576ToSigned704(
 40398518                    axis.X,
 40398519                    twiceTranslation.X),
 40398520                WideArithmetic.MultiplySigned576ToSigned704(
 40398521                    axis.Y,
 40398522                    twiceTranslation.Y)),
 40398523            WideArithmetic.MultiplySigned576ToSigned704(
 40398524                axis.Z,
 40398525                twiceTranslation.Z));
 526
 527    private static Signed704 GetCapsuleBasisProjection(
 528        in CapsuleAxis3 axis,
 529        Signed192 x,
 530        Signed192 y,
 531        Signed192 z) =>
 72387532        WideArithmetic.AddSigned704(
 72387533            WideArithmetic.AddSigned704(
 72387534                WideArithmetic.MultiplySigned576ToSigned704(
 72387535                    axis.X,
 72387536                    Signed320.ExtendValue(x)),
 72387537                WideArithmetic.MultiplySigned576ToSigned704(
 72387538                    axis.Y,
 72387539                    Signed320.ExtendValue(y))),
 72387540            WideArithmetic.MultiplySigned576ToSigned704(
 72387541                axis.Z,
 72387542                Signed320.ExtendValue(z)));
 543
 544    private static Signed704 GetCapsuleAxisProjection(
 545        in CapsuleAxis3 axis,
 546        in WideAxis3 direction) =>
 43376547        WideArithmetic.AddSigned704(
 43376548            WideArithmetic.AddSigned704(
 43376549                WideArithmetic.MultiplySigned576ToSigned704(
 43376550                    axis.X,
 43376551                    direction.X),
 43376552                WideArithmetic.MultiplySigned576ToSigned704(
 43376553                    axis.Y,
 43376554                    direction.Y)),
 43376555            WideArithmetic.MultiplySigned576ToSigned704(
 43376556                axis.Z,
 43376557                direction.Z));
 558
 559    private static Signed832 GetCapsuleSquaredLength(
 560        in CapsuleAxis3 axis) =>
 40398561        WideArithmetic.AddSigned832(
 40398562            WideArithmetic.AddSigned832(
 40398563                WideArithmetic.MultiplySigned576ToSigned832(
 40398564                    axis.X,
 40398565                    axis.X),
 40398566                WideArithmetic.MultiplySigned576ToSigned832(
 40398567                    axis.Y,
 40398568                    axis.Y)),
 40398569            WideArithmetic.MultiplySigned576ToSigned832(
 40398570                axis.Z,
 40398571                axis.Z));
 572
 573    private static bool IsWideCapsuleRadicalAtLeastRational(
 574        Signed832 squaredAxisLength,
 575        Signed192 commonDenominator,
 576        Fixed64 radius,
 577        Signed704 rational)
 578    {
 379579        Span<ulong> axis = stackalloc ulong[13];
 379580        Span<ulong> coefficient = stackalloc ulong[5];
 379581        Span<ulong> coefficientSquared = stackalloc ulong[10];
 379582        Span<ulong> rationalMagnitude = stackalloc ulong[11];
 379583        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 379584        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 379585        WideArithmetic.GetMagnitude(squaredAxisLength, axis);
 379586        Signed320 coefficientValue = WideArithmetic.MultiplySigned192(
 379587            commonDenominator,
 379588            Signed192.Raw(radius));
 379589        WideArithmetic.GetMagnitude(
 379590            coefficientValue,
 379591            out coefficient[4],
 379592            out coefficient[3],
 379593            out coefficient[2],
 379594            out coefficient[1],
 379595            out coefficient[0]);
 379596        WideArithmetic.MultiplyMagnitudes(
 379597            coefficient,
 379598            coefficient,
 379599            coefficientSquared);
 379600        WideArithmetic.MultiplyMagnitudes(coefficientSquared, axis, left);
 379601        WideArithmetic.GetMagnitude(rational, rationalMagnitude);
 379602        WideArithmetic.MultiplyMagnitudes(
 379603            rationalMagnitude,
 379604            rationalMagnitude,
 379605            right);
 379606        return WideArithmetic.CompareMagnitudeEqualLength(left, right) >= 0;
 607    }
 608
 609    private static void GetWideCapsuleDepth(
 610        Signed704 rational,
 611        Signed832 squaredAxisLength,
 612        Signed192 commonDenominator,
 613        Fixed64 radius,
 614        out Fixed64 depth,
 615        out bool depthIsClamped)
 616    {
 65617        Signed576 axisLength = WideArithmetic.GetFloorSquareRootOfProduct(
 65618            squaredAxisLength,
 65619            Signed192.Signed(1L));
 65620        Signed704 denominator = WideArithmetic.MultiplySigned576ToSigned704(
 65621            axisLength,
 65622            Signed320.ExtendValue(commonDenominator));
 65623        Signed320 radialScale = WideArithmetic.MultiplySigned192(
 65624            commonDenominator,
 65625            Signed192.Raw(radius));
 626        // Rigid basis axes have an exact integer length. Every other capsule
 627        // candidate retains both rigid Q32.32 denominators, so flooring its
 628        // radical is still finer than one Q32.32 quotient rounding interval.
 65629        Signed704 numerator = WideArithmetic.AddSigned704(
 65630            rational,
 65631            WideArithmetic.MultiplySigned576ToSigned704(
 65632                axisLength,
 65633                radialScale));
 65634        if (!Fixed64.TryGetSignedRawRatio(numerator, denominator, out depth))
 635        {
 3636            depth = Fixed64.MaxValue;
 3637            depthIsClamped = true;
 3638            return;
 639        }
 640
 62641        depthIsClamped = false;
 62642    }
 643
 644    private static int CompareWideCapsuleDepth(
 645        Signed704 candidateRational,
 646        Signed832 candidateSquaredAxisLength,
 647        Signed704 currentRational,
 648        Signed832 currentSquaredAxisLength)
 649    {
 39295650        int candidateSign = candidateRational.Sign;
 39295651        int currentSign = currentRational.Sign;
 39295652        Span<ulong> candidate = stackalloc ulong[11];
 39295653        Span<ulong> current = stackalloc ulong[11];
 39295654        Span<ulong> candidateAxis = stackalloc ulong[13];
 39295655        Span<ulong> currentAxis = stackalloc ulong[13];
 39295656        WideArithmetic.GetMagnitude(candidateRational, candidate);
 39295657        WideArithmetic.GetMagnitude(currentRational, current);
 39295658        WideArithmetic.GetMagnitude(
 39295659            candidateSquaredAxisLength,
 39295660            candidateAxis);
 39295661        WideArithmetic.GetMagnitude(
 39295662            currentSquaredAxisLength,
 39295663            currentAxis);
 39295664        return WideArithmetic.CompareSignedNormalizedMagnitudes(
 39295665            candidate,
 39295666            candidateSign,
 39295667            candidateAxis,
 39295668            current,
 39295669            currentSign,
 39295670            currentAxis);
 671    }
 672
 673    private static CapsuleAxis3 ToCapsuleAxis(in WideAxis3 axis) =>
 9288674        new(
 9288675            Signed576.ExtendValue(axis.X),
 9288676            Signed576.ExtendValue(axis.Y),
 9288677            Signed576.ExtendValue(axis.Z));
 678}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CapsuleSlab.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.CapsuleSlab.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/// Wide-precision contact generation between an oriented box and a capsule-slab pair.
 14/// </content>
 15internal static partial class WideOrientedBox
 16{
 17    internal static bool TryGetCenteredCapsuleSlabContact(
 18        Vector3d center,
 19        FixedQuaternion orientation,
 20        Vector3d halfExtents,
 21        Vector3d slabCenter,
 22        Fixed64 capsuleFrameRotation,
 23        Vector2d localCapsuleAxisDirection,
 24        Fixed64 capsuleAxisLength,
 25        Fixed64 capsuleRadius,
 26        Fixed64 slabHalfThickness,
 27        out FixedContactAnchors contact)
 28    {
 1229        _ = Vector2d.TryRotate(
 1230            localCapsuleAxisDirection,
 1231            capsuleFrameRotation,
 1232            out Vector2d capsuleAxisDirection);
 1233        WideRationalBasis3d basis = new(orientation);
 1234        Signed320 commonDenominatorWide = WideArithmetic.MultiplySigned192(
 1235            basis.Denominator,
 1236            Signed192.Raw(Fixed64.Two));
 37        // A normalized quaternion bounds the squared-component sum to roughly
 38        // 2^64 raw units; applying the Q32.32 factor for two remains below 100
 39        // signed bits.
 1240        Signed192 commonDenominator = new(
 1241            commonDenominatorWide.Word2,
 1242            commonDenominatorWide.Word1,
 1243            commonDenominatorWide.Word0);
 1244        var best = default(RadialPenetration);
 1245        WideAxis3 up = new(default, Signed320.One, default);
 1246        if (!TryKeepCapsuleSlabAxis(
 1247                up,
 1248                center,
 1249                halfExtents,
 1250                basis,
 1251                commonDenominator,
 1252                slabCenter,
 1253                capsuleAxisDirection,
 1254                capsuleAxisLength,
 1255                capsuleRadius,
 1256                slabHalfThickness,
 1257                ref best))
 58        {
 159            contact = default;
 160            return false;
 61        }
 62
 1163        Span<RationalAxis3> boxAxes = stackalloc RationalAxis3[3]
 1164        {
 1165            new(basis.Xx, basis.Xy, basis.Xz),
 1166            new(basis.Yx, basis.Yy, basis.Yz),
 1167            new(basis.Zx, basis.Zy, basis.Zz),
 1168        };
 1169        WideAxis3 capsuleAxis = new(
 1170            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.X)),
 1171            default,
 1172            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.Y)));
 1173        WideAxis3 capsuleNormal = new(
 1174            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.Y)),
 1175            default,
 1176            Signed320.ExtendValue(
 1177                WideArithmetic.SubtractSigned192(
 1178                    default,
 1179                    Signed192.Raw(capsuleAxisDirection.X))));
 1180        if (!TryKeepCapsuleSlabAxis(
 1181                capsuleAxis,
 1182                center,
 1183                halfExtents,
 1184                basis,
 1185                commonDenominator,
 1186                slabCenter,
 1187                capsuleAxisDirection,
 1188                capsuleAxisLength,
 1189                capsuleRadius,
 1190                slabHalfThickness,
 1191                ref best)
 1192            || !TryKeepCapsuleSlabAxis(
 1193                capsuleNormal,
 1194                center,
 1195                halfExtents,
 1196                basis,
 1197                commonDenominator,
 1198                slabCenter,
 1199                capsuleAxisDirection,
 11100                capsuleAxisLength,
 11101                capsuleRadius,
 11102                slabHalfThickness,
 11103                ref best))
 104        {
 2105            contact = default;
 2106            return false;
 107        }
 108
 56109        for (int index = 0; index < boxAxes.Length; index++)
 110        {
 22111            WideAxis3 boxAxis = boxAxes[index].ToWide();
 22112            if (!TryKeepCapsuleSlabAxis(
 22113                    boxAxis,
 22114                    center,
 22115                    halfExtents,
 22116                    basis,
 22117                    commonDenominator,
 22118                    slabCenter,
 22119                    capsuleAxisDirection,
 22120                    capsuleAxisLength,
 22121                    capsuleRadius,
 22122                    slabHalfThickness,
 22123                    ref best))
 124            {
 1125                contact = default;
 1126                return false;
 127            }
 21128            if (!TryKeepCapsuleSlabAxis(
 21129                    CrossWithUp(boxAxis),
 21130                    center,
 21131                    halfExtents,
 21132                    basis,
 21133                    commonDenominator,
 21134                    slabCenter,
 21135                    capsuleAxisDirection,
 21136                    capsuleAxisLength,
 21137                    capsuleRadius,
 21138                    slabHalfThickness,
 21139                    ref best))
 140            {
 1141                contact = default;
 1142                return false;
 143            }
 20144            if (!TryKeepCapsuleSlabAxis(
 20145                    CrossWithPlanarEdge(
 20146                        boxAxes[index],
 20147                        Signed192.Raw(capsuleAxisDirection.X),
 20148                        Signed192.Raw(capsuleAxisDirection.Y)),
 20149                    center,
 20150                    halfExtents,
 20151                    basis,
 20152                    commonDenominator,
 20153                    slabCenter,
 20154                    capsuleAxisDirection,
 20155                    capsuleAxisLength,
 20156                    capsuleRadius,
 20157                    slabHalfThickness,
 20158                    ref best))
 159            {
 1160                contact = default;
 1161                return false;
 162            }
 163        }
 164
 6165        for (int cornerIndex = 0;
 46166            cornerIndex < FixedOrientedBox.CornerCount;
 40167            cornerIndex++)
 168        {
 41169            Vector3d localCorner = new(
 41170                (cornerIndex & 1) == 0 ? -halfExtents.X : halfExtents.X,
 41171                (cornerIndex & 2) == 0 ? -halfExtents.Y : halfExtents.Y,
 41172                (cornerIndex & 4) == 0 ? -halfExtents.Z : halfExtents.Z);
 242173            for (int endpointSign = -1; endpointSign <= 1; endpointSign += 2)
 174            {
 81175                WideAxis3 endpointAxis = GetCornerToCapsuleEndpointAxis(
 81176                    center,
 81177                    slabCenter,
 81178                    basis,
 81179                    localCorner,
 81180                    capsuleAxisDirection,
 81181                    capsuleAxisLength,
 81182                    endpointSign);
 81183                if (!TryKeepCapsuleSlabAxis(
 81184                        endpointAxis,
 81185                        center,
 81186                        halfExtents,
 81187                        basis,
 81188                        commonDenominator,
 81189                        slabCenter,
 81190                        capsuleAxisDirection,
 81191                        capsuleAxisLength,
 81192                        capsuleRadius,
 81193                        slabHalfThickness,
 81194                        ref best))
 195                {
 1196                    contact = default;
 1197                    return false;
 198                }
 199            }
 200        }
 201
 5202        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 5203        Vector3d normal = WideNormalization.GetNormalized(
 5204            Signed576.ExtendValue(orientedAxis.X),
 5205            Signed576.ExtendValue(orientedAxis.Y),
 5206            Signed576.ExtendValue(orientedAxis.Z));
 5207        Vector3d boxLocalPoint =
 5208            GetLocalAxisSupportPoint(basis, halfExtents, orientedAxis);
 5209        FixedPointAnchor slabAnchor = GetCapsuleSlabSupportAnchor(
 5210            slabCenter,
 5211            capsuleFrameRotation,
 5212            localCapsuleAxisDirection,
 5213            orientedAxis,
 5214            capsuleAxisLength,
 5215            capsuleRadius,
 5216            slabHalfThickness);
 5217        contact = new FixedContactAnchors(
 5218            new FixedPointAnchor(center, orientation, boxLocalPoint),
 5219            slabAnchor,
 5220            normal,
 5221            best.Depth,
 5222            best.DepthIsClamped);
 5223        return true;
 224    }
 225
 226    private static bool TryKeepCapsuleSlabAxis(
 227        WideAxis3 axis,
 228        Vector3d boxCenter,
 229        Vector3d halfExtents,
 230        WideRationalBasis3d basis,
 231        Signed192 commonDenominator,
 232        Vector3d slabCenter,
 233        Vector2d capsuleAxisDirection,
 234        Fixed64 capsuleAxisLength,
 235        Fixed64 capsuleRadius,
 236        Fixed64 slabHalfThickness,
 237        ref RadialPenetration best)
 238    {
 177239        if (axis.IsZero)
 13240            return true;
 241
 164242        Signed576 boxRadius = GetBoxProjectionRadiusNumerator(
 164243            axis,
 164244            halfExtents,
 164245            basis);
 164246        Signed576 centerProjection = WideRigidProjection.GetWorldOriginDifferenceProjection(
 164247            slabCenter,
 164248            boxCenter,
 164249            axis);
 164250        bool negate = centerProjection.Sign < 0;
 164251        Signed576 centerMagnitude = GetMagnitude(centerProjection);
 164252        Signed576 verticalRadius = WideArithmetic.MultiplySigned576(
 164253            Signed576.ExtendValue(GetMagnitude(axis.Y)),
 164254            Signed192.Raw(slabHalfThickness));
 164255        Signed576 baseRational = WideArithmetic.AddSigned576(
 164256            boxRadius,
 164257            WideArithmetic.MultiplySigned576(
 164258                WideArithmetic.SubtractSigned576(
 164259                    verticalRadius,
 164260                    centerMagnitude),
 164261                basis.Denominator));
 164262        Signed576 rational = WideArithmetic.MultiplySigned576(
 164263            baseRational,
 164264            Signed192.Raw(Fixed64.Two));
 164265        Signed576 alignment = GetMagnitude(
 164266            GetPlanarAxisProjection(axis, capsuleAxisDirection));
 164267        rational = WideArithmetic.AddSigned576(
 164268            rational,
 164269            WideArithmetic.MultiplySigned576(
 164270                WideArithmetic.MultiplySigned576(
 164271                    alignment,
 164272                    Signed192.Raw(capsuleAxisLength)),
 164273                basis.Denominator));
 274
 164275        Signed576 planarSquared = WideArithmetic.AddSigned576(
 164276            WideArithmetic.MultiplySigned320(axis.X, axis.X),
 164277            WideArithmetic.MultiplySigned320(axis.Z, axis.Z));
 164278        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 164279            Signed192.Raw(capsuleRadius),
 164280            Signed192.Raw(capsuleRadius));
 164281        Signed832 radialSquared = WideArithmetic.MultiplySigned576ToSigned832(
 164282            Signed576.ExtendValue(radiusSquared),
 164283            planarSquared);
 164284        if (rational.Sign < 0
 164285            && !IsRadicalAtLeastRatio(
 164286                radialSquared,
 164287                WideArithmetic.SubtractSigned576(default, rational),
 164288                commonDenominator))
 289        {
 7290            return false;
 291        }
 292
 157293        Signed576 squaredAxisLength = axis.SquaredLength;
 157294        GetRadialDepth(
 157295            rational,
 157296            radialSquared,
 157297            squaredAxisLength,
 157298            commonDenominator,
 157299            out Fixed64 depth,
 157300            out bool depthIsClamped);
 157301        if (!best.HasValue
 157302            || depth < best.Depth
 157303            || (depth == best.Depth
 157304                && WideArithmetic.CompareRadialProjectionDepths(
 157305                    rational,
 157306                    radialSquared,
 157307                    ToSigned576(Signed192.Signed(1L)),
 157308                    squaredAxisLength,
 157309                    best.Rational,
 157310                    best.RadialNumerator,
 157311                    best.RadialDenominator,
 157312                    best.AxisSquared,
 157313                    commonDenominator) < 0))
 314        {
 19315            best = new RadialPenetration(
 19316                axis,
 19317                negate,
 19318                depth,
 19319                depthIsClamped,
 19320                rational,
 19321                radialSquared,
 19322                ToSigned576(Signed192.Signed(1L)),
 19323                squaredAxisLength);
 324        }
 157325        return true;
 326    }
 327
 328    private static Signed576 GetPlanarAxisProjection(
 329        WideAxis3 axis,
 330        Vector2d planarDirection) =>
 1191331        WideArithmetic.AddSigned576(
 1191332            WideArithmetic.MultiplySigned576(
 1191333                Signed576.ExtendValue(axis.X),
 1191334                Signed192.Raw(planarDirection.X)),
 1191335            WideArithmetic.MultiplySigned576(
 1191336                Signed576.ExtendValue(axis.Z),
 1191337                Signed192.Raw(planarDirection.Y)));
 338
 339    private static WideAxis3 GetCornerToCapsuleEndpointAxis(
 340        Vector3d boxCenter,
 341        Vector3d capsuleCenter,
 342        WideRationalBasis3d basis,
 343        Vector3d localCorner,
 344        Vector2d capsuleAxisDirection,
 345        Fixed64 capsuleAxisLength,
 346        int endpointSign)
 347    {
 81348        Signed320 cornerX = GetLocalOffsetNumerator(
 81349            basis.Xx,
 81350            basis.Yx,
 81351            basis.Zx,
 81352            localCorner);
 81353        Signed320 cornerZ = GetLocalOffsetNumerator(
 81354            basis.Xz,
 81355            basis.Yz,
 81356            basis.Zz,
 81357            localCorner);
 81358        Signed192 twiceScale = Signed192.Raw(Fixed64.Two);
 81359        Signed576 centerX = WideArithmetic.MultiplySigned576(
 81360            Signed576.ExtendValue(
 81361                WideArithmetic.MultiplySigned192(
 81362                    WideArithmetic.SubtractSigned192(
 81363                        Signed192.Raw(capsuleCenter.X),
 81364                        Signed192.Raw(boxCenter.X)),
 81365                    basis.Denominator)),
 81366            twiceScale);
 81367        Signed576 centerZ = WideArithmetic.MultiplySigned576(
 81368            Signed576.ExtendValue(
 81369                WideArithmetic.MultiplySigned192(
 81370                    WideArithmetic.SubtractSigned192(
 81371                        Signed192.Raw(capsuleCenter.Z),
 81372                        Signed192.Raw(boxCenter.Z)),
 81373                    basis.Denominator)),
 81374            twiceScale);
 81375        Signed576 endpointX = WideArithmetic.MultiplySigned576(
 81376            WideArithmetic.MultiplySigned576(
 81377                Signed576.ExtendValue(
 81378                    Signed320.ExtendValue(
 81379                        Signed192.Raw(capsuleAxisDirection.X))),
 81380                Signed192.Signed(
 81381                    endpointSign * capsuleAxisLength.m_rawValue)),
 81382            basis.Denominator);
 81383        Signed576 endpointZ = WideArithmetic.MultiplySigned576(
 81384            WideArithmetic.MultiplySigned576(
 81385                Signed576.ExtendValue(
 81386                    Signed320.ExtendValue(
 81387                        Signed192.Raw(capsuleAxisDirection.Y))),
 81388                Signed192.Signed(
 81389                    endpointSign * capsuleAxisLength.m_rawValue)),
 81390            basis.Denominator);
 81391        Signed576 cornerXWide = WideArithmetic.MultiplySigned576(
 81392            Signed576.ExtendValue(cornerX),
 81393            twiceScale);
 81394        Signed576 cornerZWide = WideArithmetic.MultiplySigned576(
 81395            Signed576.ExtendValue(cornerZ),
 81396            twiceScale);
 397        // A full-domain center difference multiplied by a normalized quaternion
 398        // basis and the Q32.32 factor for two uses at most 165 signed bits.
 81399        return new WideAxis3(
 81400            Signed320.NarrowValue(WideArithmetic.SubtractSigned576(
 81401                WideArithmetic.AddSigned576(centerX, endpointX),
 81402                cornerXWide)),
 81403            default,
 81404            Signed320.NarrowValue(WideArithmetic.SubtractSigned576(
 81405                WideArithmetic.AddSigned576(centerZ, endpointZ),
 81406                cornerZWide)));
 407    }
 408
 409    private static FixedPointAnchor GetCapsuleSlabSupportAnchor(
 410        Vector3d slabCenter,
 411        Fixed64 capsuleFrameRotation,
 412        Vector2d localCapsuleAxisDirection,
 413        WideAxis3 boxToSlabAxis,
 414        Fixed64 capsuleAxisLength,
 415        Fixed64 capsuleRadius,
 416        Fixed64 slabHalfThickness)
 417    {
 79418        Vector2d localTowardBox = GetLocalPlanarSupportDirection(
 79419            boxToSlabAxis,
 79420            capsuleFrameRotation);
 79421        FixedPointAnchor2d planar =
 79422            FixedSegment2d.GetCenteredCapsuleSupportAnchor(
 79423                Vector2d.Zero,
 79424                capsuleFrameRotation,
 79425                localCapsuleAxisDirection,
 79426                capsuleAxisLength,
 79427                capsuleRadius,
 79428                localTowardBox);
 79429        return new FixedPointAnchor(
 79430            slabCenter,
 79431            FixedQuaternion.FromAxisAngle(
 79432                Vector3d.Up,
 79433                -capsuleFrameRotation),
 79434            new Vector3d(
 79435                planar.LocalPoint.X,
 79436                boxToSlabAxis.Y.Sign >= 0
 79437                    ? -slabHalfThickness
 79438                    : slabHalfThickness,
 79439                planar.LocalPoint.Y),
 79440            new Vector3d(
 79441                planar.LocalDisplacement.X,
 79442                Fixed64.Zero,
 79443                planar.LocalDisplacement.Y),
 79444            FixedPointAnchorTerm3d.LiftPlanarXZ(
 79445                planar.ExactLocalTerm));
 446    }
 447}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CircleSlab.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.CircleSlab.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 SIMD-friendly separating-axis tests for detecting contact between
 14/// an oriented box and a circle constrained to a slab (thickened plane).
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    internal static bool TryGetCircleSlabContact(
 19        Vector3d center,
 20        FixedQuaternion orientation,
 21        Vector3d halfExtents,
 22        Vector3d slabCenter,
 23        Fixed64 circleFrameRotation,
 24        Fixed64 slabHalfThickness,
 25        Fixed64 radius,
 26        out FixedContactAnchors contact)
 27    {
 16128        WideRationalBasis3d basis = new(orientation);
 16129        var best = default(RadialPenetration);
 16130        WideAxis3 up = new(default, Signed320.One, default);
 16131        if (!TryKeepCircleSlabAxis(
 16132                up,
 16133                center,
 16134                halfExtents,
 16135                basis,
 16136                slabCenter,
 16137                slabHalfThickness,
 16138                radius,
 16139                ref best))
 40        {
 241            contact = default;
 242            return false;
 43        }
 44
 15945        Span<WideAxis3> boxAxes = stackalloc WideAxis3[3]
 15946        {
 15947            new(
 15948                Signed320.ExtendValue(basis.Xx),
 15949                Signed320.ExtendValue(basis.Xy),
 15950                Signed320.ExtendValue(basis.Xz)),
 15951            new(
 15952                Signed320.ExtendValue(basis.Yx),
 15953                Signed320.ExtendValue(basis.Yy),
 15954                Signed320.ExtendValue(basis.Yz)),
 15955            new(
 15956                Signed320.ExtendValue(basis.Zx),
 15957                Signed320.ExtendValue(basis.Zy),
 15958                Signed320.ExtendValue(basis.Zz)),
 15959        };
 43260        for (int index = 0; index < boxAxes.Length; index++)
 61        {
 19762            if (!TryKeepCircleSlabAxis(
 19763                    boxAxes[index],
 19764                    center,
 19765                    halfExtents,
 19766                    basis,
 19767                    slabCenter,
 19768                    slabHalfThickness,
 19769                    radius,
 19770                    ref best)
 19771                || !TryKeepCircleSlabAxis(
 19772                    CrossWithUp(boxAxes[index]),
 19773                    center,
 19774                    halfExtents,
 19775                    basis,
 19776                    slabCenter,
 19777                    slabHalfThickness,
 19778                    radius,
 19779                    ref best))
 80            {
 14081                contact = default;
 14082                return false;
 83            }
 84        }
 85
 31086        for (int cornerIndex = 0; cornerIndex < FixedOrientedBox.CornerCount; cornerIndex++)
 87        {
 13888            Vector3d localCorner = new(
 13889                (cornerIndex & 1) == 0 ? -halfExtents.X : halfExtents.X,
 13890                (cornerIndex & 2) == 0 ? -halfExtents.Y : halfExtents.Y,
 13891                (cornerIndex & 4) == 0 ? -halfExtents.Z : halfExtents.Z);
 13892            WideAxis3 cornerAxis = GetCornerToOriginAxis(
 13893                center,
 13894                slabCenter,
 13895                basis,
 13896                localCorner);
 13897            if (!TryKeepCircleSlabAxis(
 13898                    cornerAxis,
 13899                    center,
 138100                    halfExtents,
 138101                    basis,
 138102                    slabCenter,
 138103                    slabHalfThickness,
 138104                    radius,
 138105                    ref best))
 106            {
 2107                contact = default;
 2108                return false;
 109            }
 110        }
 111
 17112        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 17113        Vector3d normal = WideNormalization.GetNormalized(
 17114            Signed576.ExtendValue(orientedAxis.X),
 17115            Signed576.ExtendValue(orientedAxis.Y),
 17116            Signed576.ExtendValue(orientedAxis.Z));
 17117        Vector3d boxLocalPoint = GetCircleSlabBoxContactPoint(
 17118            center,
 17119            orientation,
 17120            halfExtents,
 17121            slabCenter,
 17122            basis,
 17123            orientedAxis);
 17124        FixedPointAnchor slabAnchor = GetCircleSlabSupportAnchor(
 17125            slabCenter,
 17126            orientedAxis,
 17127            circleFrameRotation,
 17128            slabHalfThickness,
 17129            radius);
 17130        contact = new FixedContactAnchors(
 17131            new FixedPointAnchor(center, orientation, boxLocalPoint),
 17132            slabAnchor,
 17133            normal,
 17134            best.Depth,
 17135            best.DepthIsClamped);
 17136        return true;
 137    }
 138
 139    private static Vector3d GetCircleSlabBoxContactPoint(
 140        Vector3d boxCenter,
 141        FixedQuaternion boxOrientation,
 142        Vector3d halfExtents,
 143        Vector3d slabCenter,
 144        WideRationalBasis3d basis,
 145        WideAxis3 boxToSlabAxis)
 146    {
 17147        var slabCenterAnchor = new FixedPointAnchor(
 17148            slabCenter,
 17149            FixedQuaternion.Identity,
 17150            Vector3d.Zero);
 17151        if (!slabCenterAnchor.TryGetLocalPointIn(
 17152                boxCenter,
 17153                boxOrientation,
 17154                out Vector3d localCenter))
 155        {
 1156            return GetLocalAxisSupportPoint(
 1157                basis,
 1158                halfExtents,
 1159                boxToSlabAxis);
 160        }
 161
 16162        bool outsideX = localCenter.X < -halfExtents.X
 16163            || localCenter.X > halfExtents.X;
 16164        bool outsideY = localCenter.Y < -halfExtents.Y
 16165            || localCenter.Y > halfExtents.Y;
 16166        bool outsideZ = localCenter.Z < -halfExtents.Z
 16167            || localCenter.Z > halfExtents.Z;
 16168        Vector3d closest = new(
 16169            FixedMath.Clamp(
 16170                localCenter.X,
 16171                -halfExtents.X,
 16172                halfExtents.X),
 16173            FixedMath.Clamp(
 16174                localCenter.Y,
 16175                -halfExtents.Y,
 16176                halfExtents.Y),
 16177            FixedMath.Clamp(
 16178                localCenter.Z,
 16179                -halfExtents.Z,
 16180                halfExtents.Z));
 16181        if (outsideX || outsideY || outsideZ)
 9182            return closest;
 183
 7184        Signed576 localNormalX = WideRigidProjection.GetBasisAxisProjection(
 7185            boxToSlabAxis,
 7186            basis.Xx,
 7187            basis.Xy,
 7188            basis.Xz);
 7189        Signed576 localNormalY = WideRigidProjection.GetBasisAxisProjection(
 7190            boxToSlabAxis,
 7191            basis.Yx,
 7192            basis.Yy,
 7193            basis.Yz);
 7194        Signed576 localNormalZ = WideRigidProjection.GetBasisAxisProjection(
 7195            boxToSlabAxis,
 7196            basis.Zx,
 7197            basis.Zy,
 7198            basis.Zz);
 7199        Signed576 magnitudeX = GetMagnitude(localNormalX);
 7200        Signed576 magnitudeY = GetMagnitude(localNormalY);
 7201        Signed576 magnitudeZ = GetMagnitude(localNormalZ);
 7202        if (CompareSigned(magnitudeX, magnitudeY) >= 0
 7203            && CompareSigned(magnitudeX, magnitudeZ) >= 0)
 204        {
 2205            closest.X = localNormalX.Sign < 0
 2206                ? -halfExtents.X
 2207                : halfExtents.X;
 208        }
 5209        else if (CompareSigned(magnitudeY, magnitudeZ) >= 0)
 210        {
 3211            closest.Y = localNormalY.Sign < 0
 3212                ? -halfExtents.Y
 3213                : halfExtents.Y;
 214        }
 215        else
 216        {
 2217            closest.Z = localNormalZ.Sign < 0
 2218                ? -halfExtents.Z
 2219                : halfExtents.Z;
 220        }
 221
 7222        return closest;
 223    }
 224
 225    private static bool TryKeepCircleSlabAxis(
 226        WideAxis3 axis,
 227        Vector3d boxCenter,
 228        Vector3d halfExtents,
 229        WideRationalBasis3d basis,
 230        Vector3d slabCenter,
 231        Fixed64 slabHalfThickness,
 232        Fixed64 radius,
 233        ref RadialPenetration best)
 234    {
 554235        if (axis.IsZero)
 18236            return true;
 237
 536238        Signed576 boxRadius = GetBoxProjectionRadiusNumerator(
 536239            axis,
 536240            halfExtents,
 536241            basis);
 536242        Signed576 centerProjection = WideRigidProjection.GetWorldOriginDifferenceProjection(
 536243            slabCenter,
 536244            boxCenter,
 536245            axis);
 536246        bool negate = centerProjection.Sign < 0;
 536247        Signed576 centerMagnitude = GetMagnitude(centerProjection);
 536248        Signed576 verticalRadius = WideArithmetic.MultiplySigned576(
 536249            Signed576.ExtendValue(GetMagnitude(axis.Y)),
 536250            Signed192.Raw(slabHalfThickness));
 536251        Signed576 rational = WideArithmetic.AddSigned576(
 536252            boxRadius,
 536253            WideArithmetic.MultiplySigned576(
 536254                WideArithmetic.SubtractSigned576(
 536255                    verticalRadius,
 536256                    centerMagnitude),
 536257                basis.Denominator));
 536258        Signed576 planarSquared = WideArithmetic.AddSigned576(
 536259            WideArithmetic.MultiplySigned320(axis.X, axis.X),
 536260            WideArithmetic.MultiplySigned320(axis.Z, axis.Z));
 536261        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 536262            Signed192.Raw(radius),
 536263            Signed192.Raw(radius));
 536264        Signed832 radialSquared = WideArithmetic.MultiplySigned576ToSigned832(
 536265            Signed576.ExtendValue(radiusSquared),
 536266            planarSquared);
 536267        if (rational.Sign < 0
 536268            && !IsRadicalAtLeastRatio(
 536269                radialSquared,
 536270                WideArithmetic.SubtractSigned576(default, rational),
 536271                basis.Denominator))
 272        {
 144273            return false;
 274        }
 275
 392276        Signed576 squaredAxisLength = axis.SquaredLength;
 392277        GetRadialDepth(
 392278            rational,
 392279            radialSquared,
 392280            squaredAxisLength,
 392281            basis.Denominator,
 392282            out Fixed64 depth,
 392283            out bool depthIsClamped);
 392284        if (!best.HasValue
 392285            || depth < best.Depth
 392286            || (depth == best.Depth
 392287                && WideArithmetic.CompareRadialProjectionDepths(
 392288                    rational,
 392289                    radialSquared,
 392290                    ToSigned576(Signed192.Signed(1L)),
 392291                    squaredAxisLength,
 392292                    best.Rational,
 392293                    best.RadialNumerator,
 392294                    best.RadialDenominator,
 392295                    best.AxisSquared,
 392296                    basis.Denominator) < 0))
 297        {
 180298            best = new RadialPenetration(
 180299                axis,
 180300                negate,
 180301                depth,
 180302                depthIsClamped,
 180303                rational,
 180304                radialSquared,
 180305                ToSigned576(Signed192.Signed(1L)),
 180306                squaredAxisLength);
 307        }
 392308        return true;
 309    }
 310
 311    private static bool IsRadicalAtLeastRatio(
 312        Signed832 radicalSquared,
 313        Signed576 ratioNumerator,
 314        Signed192 ratioDenominator)
 315    {
 748316        Span<ulong> radicalMagnitude = stackalloc ulong[13];
 748317        Span<ulong> denominatorMagnitude = stackalloc ulong[3];
 748318        Span<ulong> denominatorSquared = stackalloc ulong[6];
 748319        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 748320        Span<ulong> numeratorMagnitude = stackalloc ulong[9];
 748321        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 748322        WideArithmetic.GetMagnitude(radicalSquared, radicalMagnitude);
 748323        WideArithmetic.GetMagnitude(
 748324            ratioDenominator,
 748325            out denominatorMagnitude[2],
 748326            out denominatorMagnitude[1],
 748327            out denominatorMagnitude[0]);
 748328        WideArithmetic.MultiplyMagnitudes(
 748329            denominatorMagnitude,
 748330            denominatorMagnitude,
 748331            denominatorSquared);
 748332        WideArithmetic.MultiplyMagnitudes(
 748333            radicalMagnitude,
 748334            denominatorSquared,
 748335            left);
 748336        WideArithmetic.GetMagnitude(
 748337            ratioNumerator,
 748338            numeratorMagnitude);
 748339        WideArithmetic.MultiplyMagnitudes(
 748340            numeratorMagnitude,
 748341            numeratorMagnitude,
 748342            right);
 748343        return WideArithmetic.CompareMagnitudeEqualLength(left, right) >= 0;
 344    }
 345
 346    private static void GetRadialDepth(
 347        Signed576 rational,
 348        Signed832 radialSquared,
 349        Signed576 squaredAxisLength,
 350        Signed192 basisDenominator,
 351        out Fixed64 depth,
 352        out bool depthIsClamped)
 353    {
 2589354        Signed576 radial = WideArithmetic.GetFloorSquareRootOfProduct(
 2589355            radialSquared,
 2589356            Signed192.Signed(1L));
 2589357        Signed576 numerator = WideArithmetic.AddSigned576(
 2589358            rational,
 2589359            WideArithmetic.MultiplySigned576(radial, basisDenominator));
 2589360        numerator = WideArithmetic.ClampToNonNegative(numerator);
 2589361        Signed576 axisLength = WideArithmetic.GetFloorSquareRoot(
 2589362            Signed704.ExtendValue(squaredAxisLength));
 2589363        Signed576 denominator = WideArithmetic.MultiplySigned576(
 2589364            axisLength,
 2589365            basisDenominator);
 2589366        if (!Fixed64.TryGetSignedRawRatio(numerator, denominator, out depth))
 367        {
 68368            depth = Fixed64.MaxValue;
 68369            depthIsClamped = true;
 68370            return;
 371        }
 372
 2521373        depthIsClamped = false;
 2521374    }
 375
 376    private static WideAxis3 GetCornerToOriginAxis(
 377        Vector3d boxCenter,
 378        Vector3d otherOrigin,
 379        WideRationalBasis3d basis,
 380        Vector3d localCorner)
 381    {
 138382        Signed320 cornerX = GetLocalOffsetNumerator(
 138383            basis.Xx,
 138384            basis.Yx,
 138385            basis.Zx,
 138386            localCorner);
 138387        Signed320 cornerZ = GetLocalOffsetNumerator(
 138388            basis.Xz,
 138389            basis.Yz,
 138390            basis.Zz,
 138391            localCorner);
 138392        return new WideAxis3(
 138393            WideArithmetic.SubtractSigned320(
 138394                WideArithmetic.MultiplySigned192(
 138395                    WideArithmetic.SubtractSigned192(
 138396                        Signed192.Raw(otherOrigin.X),
 138397                        Signed192.Raw(boxCenter.X)),
 138398                    basis.Denominator),
 138399                cornerX),
 138400            default,
 138401            WideArithmetic.SubtractSigned320(
 138402                WideArithmetic.MultiplySigned192(
 138403                    WideArithmetic.SubtractSigned192(
 138404                        Signed192.Raw(otherOrigin.Z),
 138405                        Signed192.Raw(boxCenter.Z)),
 138406                    basis.Denominator),
 138407                cornerZ));
 408    }
 409
 410    private static Signed320 GetLocalOffsetNumerator(
 411        Signed192 axisX,
 412        Signed192 axisY,
 413        Signed192 axisZ,
 414        Vector3d localOffset) =>
 58065415        WideArithmetic.AddSigned320(
 58065416            WideArithmetic.AddSigned320(
 58065417                WideArithmetic.MultiplySigned192(
 58065418                    Signed192.Raw(localOffset.X),
 58065419                    axisX),
 58065420                WideArithmetic.MultiplySigned192(
 58065421                    Signed192.Raw(localOffset.Y),
 58065422                    axisY)),
 58065423            WideArithmetic.MultiplySigned192(
 58065424                Signed192.Raw(localOffset.Z),
 58065425                axisZ));
 426
 427    private static FixedPointAnchor GetCircleSlabSupportAnchor(
 428        Vector3d slabCenter,
 429        WideAxis3 boxToSlabAxis,
 430        Fixed64 circleFrameRotation,
 431        Fixed64 halfThickness,
 432        Fixed64 radius)
 433    {
 17434        Vector2d localTowardBox = GetLocalPlanarSupportDirection(
 17435            boxToSlabAxis,
 17436            circleFrameRotation);
 17437        Vector3d localRadialDirection = new(
 17438            localTowardBox.X,
 17439            Fixed64.Zero,
 17440            localTowardBox.Y);
 17441        Vector3d roundedRadialOffset =
 17442            localRadialDirection * radius;
 17443        Vector3d localPoint = new(
 17444            Fixed64.Zero,
 17445            boxToSlabAxis.Y.Sign >= 0 ? -halfThickness : halfThickness,
 17446            Fixed64.Zero);
 17447        return new FixedPointAnchor(
 17448            slabCenter,
 17449            FixedQuaternion.FromAxisAngle(
 17450                Vector3d.Up,
 17451                -circleFrameRotation),
 17452            localPoint,
 17453            roundedRadialOffset,
 17454            FixedPointAnchorTerm3d.CreateRadialSupport(
 17455                localRadialDirection,
 17456                radius,
 17457                roundedRadialOffset));
 458    }
 459
 460    private static Vector2d GetLocalPlanarSupportDirection(
 461        WideAxis3 boxToSlabAxis,
 462        Fixed64 frameRotation)
 463    {
 96464        Signed576 worldX = WideArithmetic.SubtractSigned576(
 96465            default,
 96466            Signed576.ExtendValue(boxToSlabAxis.X));
 96467        Signed576 worldY = WideArithmetic.SubtractSigned576(
 96468            default,
 96469            Signed576.ExtendValue(boxToSlabAxis.Z));
 96470        Signed192 cosine = Signed192.Raw(FixedMath.Cos(frameRotation));
 96471        Signed192 sine = Signed192.Raw(FixedMath.Sin(frameRotation));
 96472        Signed576 localX = WideArithmetic.AddSigned576(
 96473            WideArithmetic.MultiplySigned576(worldX, cosine),
 96474            WideArithmetic.MultiplySigned576(worldY, sine));
 96475        Signed576 localY = WideArithmetic.SubtractSigned576(
 96476            WideArithmetic.MultiplySigned576(worldY, cosine),
 96477            WideArithmetic.MultiplySigned576(worldX, sine));
 96478        return WideNormalization.GetNormalized(localX, localY);
 479    }
 480}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CircleSlabProjection.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.CircleSlabProjection.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/// Contains high-precision circle/slab projection logic used for continuous
 14/// collision sweep tests against oriented boxes, including the rational
 15/// arithmetic types used to represent spatial and planar constraints.
 16/// </content>
 17internal static partial class WideOrientedBox
 18{
 19    #region Nested Types
 20
 21    private readonly struct SweepSpatialConstraint
 22    {
 23        internal readonly Signed192 A;
 24        internal readonly Signed192 B;
 25        internal readonly Signed192 C;
 26        internal readonly Signed320 K;
 27
 28        internal SweepSpatialConstraint(
 29            Signed192 a,
 30            Signed192 b,
 31            Signed192 c,
 32            Signed320 k)
 33        {
 119234            A = a;
 119235            B = b;
 119236            C = c;
 119237            K = k;
 119238        }
 39    }
 40
 41    private readonly struct SweepPlanarConstraint
 42    {
 43        internal readonly Signed320 A;
 44        internal readonly Signed320 C;
 45        internal readonly Signed576 K;
 46
 47        internal SweepPlanarConstraint(
 48            Signed320 a,
 49            Signed320 c,
 50            Signed576 k)
 51        {
 221952            A = a;
 221953            C = c;
 221954            K = k;
 221955        }
 56    }
 57
 58    private readonly struct SweepBoxCorner
 59    {
 60        internal readonly Signed320 X;
 61        internal readonly Signed320 Y;
 62        internal readonly Signed320 Z;
 63
 64        internal SweepBoxCorner(
 65            Signed320 x,
 66            Signed320 y,
 67            Signed320 z)
 68        {
 114469            X = x;
 114470            Y = y;
 114471            Z = z;
 114472        }
 73    }
 74
 75    private readonly struct SweepRationalPoint
 76    {
 77        internal readonly Signed576 X;
 78        internal readonly Signed576 Z;
 79        internal readonly Signed576 Denominator;
 80
 81        internal SweepRationalPoint(
 82            Signed576 x,
 83            Signed576 z,
 84            Signed576 denominator)
 85        {
 189486            X = x;
 189487            Z = z;
 189488            Denominator = denominator;
 189489        }
 90    }
 91
 92    #endregion
 93
 94    private static bool TryBuildCircleSlabProjectionConstraints(
 95        Vector3d center,
 96        Vector3d halfExtents,
 97        WideRationalBasis3d basis,
 98        Signed192 lowerY,
 99        Signed192 upperY,
 100        Span<SweepPlanarConstraint> constraints,
 101        out int count)
 102    {
 149103        Span<SweepSpatialConstraint> spatial =
 149104            stackalloc SweepSpatialConstraint[8];
 149105        int spatialCount = 0;
 149106        AddBoxAxisConstraints(
 149107            center,
 149108            halfExtents.X,
 149109            basis.Denominator,
 149110            basis.Xx,
 149111            basis.Xy,
 149112            basis.Xz,
 149113            spatial,
 149114            ref spatialCount);
 149115        AddBoxAxisConstraints(
 149116            center,
 149117            halfExtents.Y,
 149118            basis.Denominator,
 149119            basis.Yx,
 149120            basis.Yy,
 149121            basis.Yz,
 149122            spatial,
 149123            ref spatialCount);
 149124        AddBoxAxisConstraints(
 149125            center,
 149126            halfExtents.Z,
 149127            basis.Denominator,
 149128            basis.Zx,
 149129            basis.Zy,
 149130            basis.Zz,
 149131            spatial,
 149132            ref spatialCount);
 149133        spatial[spatialCount++] = new SweepSpatialConstraint(
 149134            default,
 149135            SweepOneCoefficient,
 149136            default,
 149137            Signed320.ExtendValue(upperY));
 149138        spatial[spatialCount++] = new SweepSpatialConstraint(
 149139            default,
 149140            WideArithmetic.SubtractSigned192(
 149141                default,
 149142                SweepOneCoefficient),
 149143            default,
 149144            Signed320.ExtendValue(
 149145                WideArithmetic.SubtractSigned192(default, lowerY)));
 146
 149147        count = 0;
 2682148        for (int index = 0; index < spatialCount; index++)
 149        {
 1192150            if (!spatial[index].B.IsZero)
 151                continue;
 152
 80153            constraints[count++] = new SweepPlanarConstraint(
 80154                Signed320.ExtendValue(spatial[index].A),
 80155                Signed320.ExtendValue(spatial[index].C),
 80156                Signed576.ExtendValue(spatial[index].K));
 157        }
 158
 2654159        for (int positive = 0; positive < spatialCount; positive++)
 160        {
 1181161            if (spatial[positive].B.Sign <= 0)
 162                continue;
 163
 9958164            for (int negative = 0; negative < spatialCount; negative++)
 165            {
 4428166                if (spatial[negative].B.Sign >= 0)
 167                    continue;
 168
 2139169                Signed320 a = WideArithmetic.SubtractSigned320(
 2139170                    WideArithmetic.MultiplySigned192(
 2139171                        spatial[positive].B,
 2139172                        spatial[negative].A),
 2139173                    WideArithmetic.MultiplySigned192(
 2139174                        spatial[negative].B,
 2139175                        spatial[positive].A));
 2139176                Signed320 c = WideArithmetic.SubtractSigned320(
 2139177                    WideArithmetic.MultiplySigned192(
 2139178                        spatial[positive].B,
 2139179                        spatial[negative].C),
 2139180                    WideArithmetic.MultiplySigned192(
 2139181                        spatial[negative].B,
 2139182                        spatial[positive].C));
 2139183                Signed576 k = WideArithmetic.SubtractSigned576(
 2139184                    WideArithmetic.MultiplySigned320(
 2139185                        Signed320.ExtendValue(
 2139186                            spatial[positive].B),
 2139187                        spatial[negative].K),
 2139188                    WideArithmetic.MultiplySigned320(
 2139189                        Signed320.ExtendValue(
 2139190                            spatial[negative].B),
 2139191                        spatial[positive].K));
 2139192                if (!TryAddProjectionConstraint(
 2139193                        new SweepPlanarConstraint(a, c, k),
 2139194                        constraints,
 2139195                        ref count))
 196                {
 3197                    return false;
 198                }
 199            }
 200        }
 201
 146202        return count > 0;
 203    }
 204
 205    private static void AddBoxAxisConstraints(
 206        Vector3d center,
 207        Fixed64 extent,
 208        Signed192 denominator,
 209        Signed192 axisX,
 210        Signed192 axisY,
 211        Signed192 axisZ,
 212        Span<SweepSpatialConstraint> constraints,
 213        ref int count)
 214    {
 447215        Signed320 centerProjection = WideArithmetic.AddSigned320(
 447216            WideArithmetic.AddSigned320(
 447217                WideArithmetic.MultiplySigned192(Signed192.Raw(center.X), axisX),
 447218                WideArithmetic.MultiplySigned192(Signed192.Raw(center.Y), axisY)),
 447219            WideArithmetic.MultiplySigned192(Signed192.Raw(center.Z), axisZ));
 447220        Signed320 extentNumerator =
 447221            WideArithmetic.MultiplySigned192(Signed192.Raw(extent), denominator);
 447222        constraints[count++] = new SweepSpatialConstraint(
 447223            axisX,
 447224            axisY,
 447225            axisZ,
 447226            WideArithmetic.AddSigned320(
 447227                extentNumerator,
 447228                centerProjection));
 447229        constraints[count++] = new SweepSpatialConstraint(
 447230            WideArithmetic.SubtractSigned192(default, axisX),
 447231            WideArithmetic.SubtractSigned192(default, axisY),
 447232            WideArithmetic.SubtractSigned192(default, axisZ),
 447233            WideArithmetic.SubtractSigned320(
 447234                extentNumerator,
 447235                centerProjection));
 447236    }
 237
 238    private static bool TryAddProjectionConstraint(
 239        SweepPlanarConstraint constraint,
 240        Span<SweepPlanarConstraint> constraints,
 241        ref int count)
 242    {
 2139243        if (constraint.A.IsZero && constraint.C.IsZero)
 591244            return constraint.K.Sign >= 0;
 245
 1548246        constraints[count++] = constraint;
 1548247        return true;
 248    }
 249
 250    private static void BuildCircleSlabProjectionVertices(
 251        Vector3d center,
 252        Vector3d halfExtents,
 253        WideRationalBasis3d basis,
 254        Signed192 lowerY,
 255        Signed192 upperY,
 256        Span<SweepRationalPoint> vertices,
 257        out int count)
 258    {
 143259        Span<SweepBoxCorner> corners = stackalloc SweepBoxCorner[8];
 143260        Signed320 lowerNumerator =
 143261            WideArithmetic.MultiplySigned192(lowerY, basis.Denominator);
 143262        Signed320 upperNumerator =
 143263            WideArithmetic.MultiplySigned192(upperY, basis.Denominator);
 143264        count = 0;
 2574265        for (int index = 0; index < corners.Length; index++)
 266        {
 1144267            Vector3d local = new(
 1144268                (index & 1) == 0 ? -halfExtents.X : halfExtents.X,
 1144269                (index & 2) == 0 ? -halfExtents.Y : halfExtents.Y,
 1144270                (index & 4) == 0 ? -halfExtents.Z : halfExtents.Z);
 1144271            corners[index] = GetSweepBoxCorner(center, basis, local);
 1144272            if (CompareSigned(corners[index].Y, lowerNumerator) >= 0
 1144273                && CompareSigned(corners[index].Y, upperNumerator) <= 0)
 274            {
 112275                AddUniqueSweepPoint(
 112276                    new SweepRationalPoint(
 112277                        Signed576.ExtendValue(corners[index].X),
 112278                        Signed576.ExtendValue(corners[index].Z),
 112279                        Signed576.ExtendValue(
 112280                            Signed320.ExtendValue(
 112281                                basis.Denominator))),
 112282                    vertices,
 112283                    ref count);
 284            }
 285        }
 286
 2574287        for (int index = 0; index < corners.Length; index++)
 288        {
 9152289            for (int bit = 1; bit <= 4; bit <<= 1)
 290            {
 3432291                if ((index & bit) != 0)
 292                    continue;
 293
 1716294                TryAddPlaneIntersection(
 1716295                    corners[index],
 1716296                    corners[index | bit],
 1716297                    lowerNumerator,
 1716298                    basis.Denominator,
 1716299                    vertices,
 1716300                    ref count);
 1716301                TryAddPlaneIntersection(
 1716302                    corners[index],
 1716303                    corners[index | bit],
 1716304                    upperNumerator,
 1716305                    basis.Denominator,
 1716306                    vertices,
 1716307                    ref count);
 308            }
 309        }
 143310    }
 311
 312    private static SweepBoxCorner GetSweepBoxCorner(
 313        Vector3d center,
 314        WideRationalBasis3d basis,
 315        Vector3d local) =>
 1144316        new(
 1144317            WideArithmetic.AddSigned320(
 1144318                WideArithmetic.MultiplySigned192(
 1144319                    Signed192.Raw(center.X),
 1144320                    basis.Denominator),
 1144321                GetLocalOffsetNumerator(
 1144322                    basis.Xx,
 1144323                    basis.Yx,
 1144324                    basis.Zx,
 1144325                    local)),
 1144326            WideArithmetic.AddSigned320(
 1144327                WideArithmetic.MultiplySigned192(
 1144328                    Signed192.Raw(center.Y),
 1144329                    basis.Denominator),
 1144330                GetLocalOffsetNumerator(
 1144331                    basis.Xy,
 1144332                    basis.Yy,
 1144333                    basis.Zy,
 1144334                    local)),
 1144335            WideArithmetic.AddSigned320(
 1144336                WideArithmetic.MultiplySigned192(
 1144337                    Signed192.Raw(center.Z),
 1144338                    basis.Denominator),
 1144339                GetLocalOffsetNumerator(
 1144340                    basis.Xz,
 1144341                    basis.Yz,
 1144342                    basis.Zz,
 1144343                    local)));
 344
 345    private static void TryAddPlaneIntersection(
 346        SweepBoxCorner first,
 347        SweepBoxCorner second,
 348        Signed320 planeNumerator,
 349        Signed192 basisDenominator,
 350        Span<SweepRationalPoint> vertices,
 351        ref int count)
 352    {
 3432353        Signed320 minimum = CompareSigned(first.Y, second.Y) <= 0
 3432354            ? first.Y
 3432355            : second.Y;
 3432356        Signed320 maximum = CompareSigned(first.Y, second.Y) <= 0
 3432357            ? second.Y
 3432358            : first.Y;
 3432359        if (CompareSigned(planeNumerator, minimum) < 0
 3432360            || CompareSigned(planeNumerator, maximum) > 0)
 361        {
 2192362            return;
 363        }
 364
 1240365        Signed320 deltaY =
 1240366            WideArithmetic.SubtractSigned320(second.Y, first.Y);
 1240367        if (deltaY.IsZero)
 104368            return;
 369
 1136370        Signed320 firstWeight =
 1136371            WideArithmetic.SubtractSigned320(second.Y, planeNumerator);
 1136372        Signed320 secondWeight =
 1136373            WideArithmetic.SubtractSigned320(planeNumerator, first.Y);
 1136374        Signed576 x = WideArithmetic.AddSigned576(
 1136375            WideArithmetic.MultiplySigned320(first.X, firstWeight),
 1136376            WideArithmetic.MultiplySigned320(second.X, secondWeight));
 1136377        Signed576 z = WideArithmetic.AddSigned576(
 1136378            WideArithmetic.MultiplySigned320(first.Z, firstWeight),
 1136379            WideArithmetic.MultiplySigned320(second.Z, secondWeight));
 1136380        Signed576 denominator = WideArithmetic.MultiplySigned320(
 1136381            Signed320.ExtendValue(basisDenominator),
 1136382            deltaY);
 1136383        if (denominator.Sign < 0)
 384        {
 8385            x = WideArithmetic.SubtractSigned576(default, x);
 8386            z = WideArithmetic.SubtractSigned576(default, z);
 8387            denominator =
 8388                WideArithmetic.SubtractSigned576(default, denominator);
 389        }
 390
 1136391        AddUniqueSweepPoint(
 1136392            new SweepRationalPoint(x, z, denominator),
 1136393            vertices,
 1136394            ref count);
 1136395    }
 396
 397    private static void AddUniqueSweepPoint(
 398        SweepRationalPoint point,
 399        Span<SweepRationalPoint> vertices,
 400        ref int count)
 401    {
 10368402        for (int index = 0; index < count; index++)
 403        {
 4096404            if (AreSameSweepPoint(vertices[index], point))
 160405                return;
 406        }
 407
 1088408        vertices[count++] = point;
 1088409    }
 410
 411    private static bool AreSameSweepPoint(
 412        SweepRationalPoint first,
 413        SweepRationalPoint second) =>
 4738414        WideArithmetic.SubtractSigned832(
 4738415            WideArithmetic.MultiplySigned576ToSigned832(
 4738416                first.X,
 4738417                second.Denominator),
 4738418            WideArithmetic.MultiplySigned576ToSigned832(
 4738419                second.X,
 4738420                first.Denominator)).IsZero
 4738421        && WideArithmetic.SubtractSigned832(
 4738422            WideArithmetic.MultiplySigned576ToSigned832(
 4738423                first.Z,
 4738424                second.Denominator),
 4738425            WideArithmetic.MultiplySigned576ToSigned832(
 4738426                second.Z,
 4738427                first.Denominator)).IsZero;
 428}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CircleSlabSweep.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.CircleSlabSweep.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/// High-precision sweep tests between a circle and an oriented box slab,
 14/// using wide fixed-point arithmetic to avoid overflow and precision loss.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 118    private static readonly Signed192 SweepRawScale = Signed192.Signed(FixedMath.ONE_L);
 119    private static readonly Signed192 SweepDoubleRawScale = Signed192.Signed(FixedMath.ONE_L * 2L);
 120    private static readonly Signed192 SweepOneCoefficient = Signed192.Signed(1L);
 21
 22    #region Nested Types
 23
 24    private readonly struct RationalPointDistance
 25    {
 26        internal readonly Signed576 Denominator;
 27        internal readonly Signed832 SquaredDistance;
 28
 29        internal RationalPointDistance(
 30            Signed576 denominator,
 31            Signed832 squaredDistance)
 32        {
 1633            Denominator = denominator;
 1634            SquaredDistance = squaredDistance;
 1635        }
 36    }
 37
 38    #endregion
 39
 40    internal static bool TryGetCircleSlabSweepDistance(
 41        Vector3d center,
 42        FixedQuaternion orientation,
 43        Vector3d halfExtents,
 44        Vector3d slabStartCenter,
 45        Vector2d normalizedDirection,
 46        Fixed64 maxDistance,
 47        Fixed64 slabHalfThickness,
 48        Fixed64 radius,
 49        out Fixed64 distance)
 50    {
 14251        if (TryGetCircleSlabContact(
 14252                center,
 14253                orientation,
 14254                halfExtents,
 14255                slabStartCenter,
 14256                Fixed64.Zero,
 14257                slabHalfThickness,
 14258                radius,
 14259                out _))
 60        {
 161            distance = Fixed64.Zero;
 162            return true;
 63        }
 64
 14165        if (maxDistance == Fixed64.Zero)
 66        {
 167            distance = default;
 168            return false;
 69        }
 70
 14071        WideRationalBasis3d basis = new(orientation);
 14072        Signed192 lowerY = WideArithmetic.SubtractSigned192(
 14073            Signed192.Raw(slabStartCenter.Y),
 14074            Signed192.Raw(slabHalfThickness));
 14075        Signed192 upperY = WideArithmetic.AddSigned192(
 14076            Signed192.Raw(slabStartCenter.Y),
 14077            Signed192.Raw(slabHalfThickness));
 14078        Span<SweepPlanarConstraint> constraints =
 14079            stackalloc SweepPlanarConstraint[16];
 14080        if (!TryBuildCircleSlabProjectionConstraints(
 14081                center,
 14082                halfExtents,
 14083                basis,
 14084                lowerY,
 14085                upperY,
 14086                constraints,
 14087                out int constraintCount))
 88        {
 189            distance = default;
 190            return false;
 91        }
 92
 13993        Span<SweepRationalPoint> vertices =
 13994            stackalloc SweepRationalPoint[32];
 13995        BuildCircleSlabProjectionVertices(
 13996            center,
 13997            halfExtents,
 13998            basis,
 13999            lowerY,
 139100            upperY,
 139101            vertices,
 139102            out int vertexCount);
 139103        Vector2d planarStart = new(slabStartCenter.X, slabStartCenter.Z);
 139104        bool found = false;
 139105        Fixed64 best = Fixed64.MaxValue;
 3454106        for (int index = 0; index < constraintCount; index++)
 107        {
 1588108            if (!TryGetExpandedEdgeSweepDistance(
 1588109                    constraints,
 1588110                    constraintCount,
 1588111                    index,
 1588112                    planarStart,
 1588113                    normalizedDirection,
 1588114                    maxDistance,
 1588115                    radius,
 1588116                    out Fixed64 candidate))
 117            {
 118                continue;
 119            }
 134120            best = FixedMath.Min(best, candidate);
 134121            found = true;
 122        }
 123
 2422124        for (int index = 0; index < vertexCount; index++)
 125        {
 1072126            if (!TryGetRationalPointSweepDistance(
 1072127                    vertices[index],
 1072128                    planarStart,
 1072129                    normalizedDirection,
 1072130                    maxDistance,
 1072131                    radius,
 1072132                    out Fixed64 candidate))
 133            {
 134                continue;
 135            }
 136
 4137            best = FixedMath.Min(best, candidate);
 4138            found = true;
 139        }
 140
 139141        distance = found ? best : default;
 139142        return found;
 143    }
 144
 145    internal static Fixed64 GetCircleSlabSeparationLowerBound(
 146        Vector3d center,
 147        FixedQuaternion orientation,
 148        Vector3d halfExtents,
 149        Vector3d slabCenter,
 150        Fixed64 slabHalfThickness,
 151        Fixed64 radius)
 152    {
 9153        WideRationalBasis3d basis = new(orientation);
 9154        Signed192 lowerY = WideArithmetic.SubtractSigned192(
 9155            Signed192.Raw(slabCenter.Y),
 9156            Signed192.Raw(slabHalfThickness));
 9157        Signed192 upperY = WideArithmetic.AddSigned192(
 9158            Signed192.Raw(slabCenter.Y),
 9159            Signed192.Raw(slabHalfThickness));
 9160        Span<SweepPlanarConstraint> constraints =
 9161            stackalloc SweepPlanarConstraint[16];
 9162        if (!TryBuildCircleSlabProjectionConstraints(
 9163                center,
 9164                halfExtents,
 9165                basis,
 9166                lowerY,
 9167                upperY,
 9168                constraints,
 9169                out int count))
 170        {
 2171            return GetCircleSlabVerticalSeparationLowerBound(
 2172                center,
 2173                halfExtents,
 2174                basis,
 2175                lowerY,
 2176                upperY);
 177        }
 178
 7179        Vector2d planarCenter = new(slabCenter.X, slabCenter.Z);
 7180        Fixed64 lowerBound = Fixed64.Zero;
 7181        bool hasPlanarViolation = false;
 7182        bool hasClosestEdgeFeature = false;
 54183        for (int index = 0; index < count; index++)
 184        {
 22185            SweepPlanarConstraint constraint = constraints[index];
 22186            Signed576 violation = WideArithmetic.SubtractSigned576(
 22187                GetSweepProjection(constraint, planarCenter),
 22188                constraint.K);
 22189            if (violation.Sign <= 0)
 190                continue;
 191
 10192            hasPlanarViolation = true;
 10193            Signed576 normalSquared = WideArithmetic.AddSigned576(
 10194                WideArithmetic.MultiplySigned320(
 10195                    constraint.A,
 10196                    constraint.A),
 10197                WideArithmetic.MultiplySigned320(
 10198                    constraint.C,
 10199                    constraint.C));
 10200            Signed576 normalFloor = WideArithmetic.GetFloorSquareRoot(
 10201                Signed704.ExtendValue(normalSquared));
 10202            Signed832 floorSquared =
 10203                WideArithmetic.MultiplySigned576ToSigned832(
 10204                    normalFloor,
 10205                    normalFloor);
 10206            Signed832 remainderSign = WideArithmetic.SubtractSigned832(
 10207                floorSquared,
 10208                Signed832.ExtendValue(normalSquared));
 10209            long ceilingIncrementRaw =
 10210                (long)(remainderSign.Word12 >> 63);
 10211            normalFloor = WideArithmetic.AddSigned576(
 10212                normalFloor,
 10213                Signed576.ExtendValue(
 10214                    Signed320.ExtendValue(
 10215                        Signed192.Signed(
 10216                            ceilingIncrementRaw))));
 217
 10218            Fixed64 axisDistance = Fixed64.GetNonNegativeRawRatioFloor(
 10219                Signed704.ExtendValue(violation),
 10220                Signed704.ExtendValue(normalFloor));
 10221            Fixed64 candidate = axisDistance > radius
 10222                ? axisDistance - radius
 10223                : Fixed64.Zero;
 10224            if (candidate > lowerBound)
 6225                lowerBound = candidate;
 226
 10227            if (IsClosestProjectionOnConstraint(
 10228                    constraints,
 10229                    count,
 10230                    index,
 10231                    planarCenter,
 10232                    violation,
 10233                    Signed320.NarrowValue(normalSquared)))
 234            {
 2235                hasClosestEdgeFeature = true;
 236                // This valid orthogonal projection is the closest point of
 237                // the convex projection. Every remaining half-space distance
 238                // is therefore bounded by the candidate already retained.
 2239                break;
 240            }
 241        }
 242
 7243        if (hasPlanarViolation && !hasClosestEdgeFeature)
 244        {
 4245            Fixed64 vertexDistance =
 4246                GetClosestProjectionVertexDistanceLowerBound(
 4247                    center,
 4248                    halfExtents,
 4249                    basis,
 4250                    lowerY,
 4251                    upperY,
 4252                    planarCenter);
 4253            Fixed64 vertexGap = vertexDistance > radius
 4254                ? vertexDistance - radius
 4255                : Fixed64.Zero;
 4256            if (vertexGap > lowerBound)
 3257                lowerBound = vertexGap;
 258        }
 259
 7260        return lowerBound;
 261    }
 262
 263    private static bool IsClosestProjectionOnConstraint(
 264        ReadOnlySpan<SweepPlanarConstraint> constraints,
 265        int constraintCount,
 266        int constraintIndex,
 267        Vector2d point,
 268        Signed576 violation,
 269        Signed320 normalSquared)
 270    {
 10271        SweepPlanarConstraint constraint = constraints[constraintIndex];
 52272        for (int index = 0; index < constraintCount; index++)
 273        {
 24274            SweepPlanarConstraint candidate = constraints[index];
 24275            Signed576 candidateViolation =
 24276                WideArithmetic.SubtractSigned576(
 24277                    GetSweepProjection(candidate, point),
 24278                    candidate.K);
 24279            Signed320 normalDot = Signed320.NarrowValue(
 24280                WideArithmetic.AddSigned576(
 24281                    WideArithmetic.MultiplySigned320(
 24282                        candidate.A,
 24283                        constraint.A),
 24284                    WideArithmetic.MultiplySigned320(
 24285                        candidate.C,
 24286                        constraint.C)));
 24287            Signed704 projectedViolation =
 24288                WideArithmetic.SubtractSigned704(
 24289                    WideArithmetic.MultiplySigned576ToSigned704(
 24290                        candidateViolation,
 24291                        normalSquared),
 24292                    WideArithmetic.MultiplySigned576ToSigned704(
 24293                        violation,
 24294                        normalDot));
 24295            if (projectedViolation.Sign > 0)
 8296                return false;
 297        }
 298
 2299        return true;
 300    }
 301
 302    private static Fixed64 GetClosestProjectionVertexDistanceLowerBound(
 303        Vector3d center,
 304        Vector3d halfExtents,
 305        WideRationalBasis3d basis,
 306        Signed192 lowerY,
 307        Signed192 upperY,
 308        Vector2d point)
 309    {
 4310        Span<SweepRationalPoint> vertices =
 4311            stackalloc SweepRationalPoint[32];
 4312        BuildCircleSlabProjectionVertices(
 4313            center,
 4314            halfExtents,
 4315            basis,
 4316            lowerY,
 4317            upperY,
 4318            vertices,
 4319            out int vertexCount);
 320        // The caller already proved that the finite box/slab intersection is
 321        // nonempty, so its compact planar projection has at least one vertex.
 4322        RationalPointDistance closest =
 4323            GetRationalPointDistance(vertices[0], point);
 32324        for (int index = 1; index < vertexCount; index++)
 325        {
 12326            RationalPointDistance candidate =
 12327                GetRationalPointDistance(vertices[index], point);
 12328            if (CompareRationalPointDistances(candidate, closest) < 0)
 8329                closest = candidate;
 330        }
 331
 4332        return GetRationalPointDistanceLowerBound(closest);
 333    }
 334
 335    private static RationalPointDistance GetRationalPointDistance(
 336        SweepRationalPoint point,
 337        Vector2d reference)
 338    {
 16339        Signed576 deltaX = WideArithmetic.SubtractSigned576(
 16340            WideArithmetic.MultiplySigned576(
 16341                point.Denominator,
 16342                Signed192.Raw(reference.X)),
 16343            point.X);
 16344        Signed576 deltaZ = WideArithmetic.SubtractSigned576(
 16345            WideArithmetic.MultiplySigned576(
 16346                point.Denominator,
 16347                Signed192.Raw(reference.Y)),
 16348            point.Z);
 16349        Signed832 squaredDistance = WideArithmetic.AddSigned832(
 16350            WideArithmetic.MultiplySigned576ToSigned832(deltaX, deltaX),
 16351            WideArithmetic.MultiplySigned576ToSigned832(deltaZ, deltaZ));
 16352        return new RationalPointDistance(
 16353            point.Denominator,
 16354            squaredDistance);
 355    }
 356
 357    private static int CompareRationalPointDistances(
 358        RationalPointDistance first,
 359        RationalPointDistance second)
 360    {
 12361        Signed832 firstDenominatorSquared =
 12362            WideArithmetic.MultiplySigned576ToSigned832(
 12363                first.Denominator,
 12364                first.Denominator);
 12365        Signed832 secondDenominatorSquared =
 12366            WideArithmetic.MultiplySigned576ToSigned832(
 12367                second.Denominator,
 12368                second.Denominator);
 12369        Span<ulong> firstSquaredMagnitude = stackalloc ulong[13];
 12370        Span<ulong> secondSquaredMagnitude = stackalloc ulong[13];
 12371        Span<ulong> firstDenominatorMagnitude = stackalloc ulong[13];
 12372        Span<ulong> secondDenominatorMagnitude = stackalloc ulong[13];
 12373        WideArithmetic.GetMagnitude(
 12374            first.SquaredDistance,
 12375            firstSquaredMagnitude);
 12376        WideArithmetic.GetMagnitude(
 12377            second.SquaredDistance,
 12378            secondSquaredMagnitude);
 12379        WideArithmetic.GetMagnitude(
 12380            firstDenominatorSquared,
 12381            firstDenominatorMagnitude);
 12382        WideArithmetic.GetMagnitude(
 12383            secondDenominatorSquared,
 12384            secondDenominatorMagnitude);
 12385        Span<ulong> left =
 12386            stackalloc ulong[TriangleSweepMagnitudeWords];
 12387        Span<ulong> right =
 12388            stackalloc ulong[TriangleSweepMagnitudeWords];
 12389        WideArithmetic.MultiplyMagnitudes(
 12390            firstSquaredMagnitude,
 12391            secondDenominatorMagnitude,
 12392            left);
 12393        WideArithmetic.MultiplyMagnitudes(
 12394            secondSquaredMagnitude,
 12395            firstDenominatorMagnitude,
 12396            right);
 12397        return WideArithmetic.CompareMagnitudeEqualLength(left, right);
 398    }
 399
 400    private static Fixed64 GetRationalPointDistanceLowerBound(
 401        RationalPointDistance distance)
 402    {
 4403        long low = 0L;
 4404        long high = Fixed64.MaxValue.m_rawValue;
 256405        while (low < high)
 406        {
 252407            long difference = high - low;
 252408            long middle =
 252409                low + (difference >> 1) + (difference & 1L);
 252410            Signed576 scaledDistance = WideArithmetic.MultiplySigned576(
 252411                distance.Denominator,
 252412                Signed192.Signed(middle));
 252413            Signed832 squaredCandidate =
 252414                WideArithmetic.MultiplySigned576ToSigned832(
 252415                    scaledDistance,
 252416                    scaledDistance);
 252417            if (WideArithmetic.SubtractSigned832(
 252418                    squaredCandidate,
 252419                    distance.SquaredDistance).Sign <= 0)
 420            {
 58421                low = middle;
 422            }
 423            else
 424            {
 194425                high = middle - 1L;
 426            }
 427        }
 428
 4429        return Fixed64.FromRaw(low);
 430    }
 431
 432    private static Fixed64 GetCircleSlabVerticalSeparationLowerBound(
 433        Vector3d center,
 434        Vector3d halfExtents,
 435        WideRationalBasis3d basis,
 436        Signed192 lowerY,
 437        Signed192 upperY)
 438    {
 2439        Signed320 boxRadius = GetExtentNumerator(
 2440            basis.Xy,
 2441            basis.Yy,
 2442            basis.Zy,
 2443            halfExtents);
 2444        Signed320 boxCenter = WideArithmetic.MultiplySigned192(
 2445            Signed192.Raw(center.Y),
 2446            basis.Denominator);
 2447        Signed320 boxMinimum =
 2448            WideArithmetic.SubtractSigned320(boxCenter, boxRadius);
 2449        Signed320 boxMaximum =
 2450            WideArithmetic.AddSigned320(boxCenter, boxRadius);
 2451        Signed320 slabMinimum =
 2452            WideArithmetic.MultiplySigned192(lowerY, basis.Denominator);
 2453        Signed320 slabMaximum =
 2454            WideArithmetic.MultiplySigned192(upperY, basis.Denominator);
 2455        Signed320 gap = CompareSigned(boxMaximum, slabMinimum) < 0
 2456            ? WideArithmetic.SubtractSigned320(slabMinimum, boxMaximum)
 2457            : WideArithmetic.SubtractSigned320(boxMinimum, slabMaximum);
 2458        return Fixed64.GetNonNegativeRawRatioFloor(
 2459            Signed704.ExtendValue(
 2460                Signed576.ExtendValue(gap)),
 2461            Signed704.ExtendValue(
 2462                Signed576.ExtendValue(
 2463                    Signed320.ExtendValue(
 2464                        basis.Denominator))));
 465    }
 466
 467    private static bool TryGetExpandedEdgeSweepDistance(
 468        ReadOnlySpan<SweepPlanarConstraint> constraints,
 469        int constraintCount,
 470        int constraintIndex,
 471        Vector2d start,
 472        Vector2d direction,
 473        Fixed64 maxDistance,
 474        Fixed64 radius,
 475        out Fixed64 distance)
 476    {
 1588477        SweepPlanarConstraint edge = constraints[constraintIndex];
 1588478        Signed576 startViolation = WideArithmetic.SubtractSigned576(
 1588479            GetSweepProjection(edge, start),
 1588480            edge.K);
 1588481        if (startViolation.Sign <= 0)
 482        {
 930483            distance = default;
 930484            return false;
 485        }
 486
 658487        Signed576 normalSquared = WideArithmetic.AddSigned576(
 658488            WideArithmetic.MultiplySigned320(edge.A, edge.A),
 658489            WideArithmetic.MultiplySigned320(edge.C, edge.C));
 658490        Signed320 radiusSquared =
 658491            WideArithmetic.MultiplySigned192(Signed192.Raw(radius), Signed192.Raw(radius));
 658492        Signed832 expandedSquared =
 658493            WideArithmetic.MultiplyNonNegativeToSigned832(
 658494                Signed832.ExtendValue(
 658495                    Signed576.ExtendValue(radiusSquared)),
 658496                Signed320.NarrowValue(normalSquared));
 658497        Signed832 startSquared =
 658498            WideArithmetic.MultiplySigned576ToSigned832(
 658499                startViolation,
 658500                startViolation);
 658501        if (WideArithmetic.SubtractSigned832(
 658502                startSquared,
 658503                expandedSquared).Sign <= 0)
 504        {
 4505            distance = default;
 4506            return false;
 507        }
 508
 654509        Signed576 velocity = GetSweepProjection(edge, direction);
 654510        if (velocity.Sign >= 0
 654511            || CompareExpandedEdgeAt(
 654512                startViolation,
 654513                velocity,
 654514                normalSquared,
 654515                radius,
 654516                Signed192.Signed(maxDistance.m_rawValue),
 654517                SweepRawScale) > 0)
 518        {
 2519            distance = default;
 2520            return false;
 521        }
 522
 652523        long maxRaw = maxDistance.m_rawValue;
 524        // The public contract has already rejected a zero maximum distance.
 652525        long high = maxRaw - 1L;
 652526        if (CompareExpandedEdgeAtHalf(
 652527                startViolation,
 652528                velocity,
 652529                normalSquared,
 652530                radius,
 652531                high) > 0)
 532        {
 1533            distance = maxDistance;
 534        }
 535        else
 536        {
 651537            long low = 0L;
 24076538            while (low < high)
 539            {
 23425540                long middle = low + ((high - low) >> 1);
 23425541                if (CompareExpandedEdgeAtHalf(
 23425542                        startViolation,
 23425543                        velocity,
 23425544                        normalSquared,
 23425545                        radius,
 23425546                        middle) <= 0)
 547                {
 12368548                    high = middle;
 549                }
 550                else
 551                {
 11057552                    low = middle + 1L;
 553                }
 554            }
 555
 651556            int midpointComparison = CompareExpandedEdgeAtHalf(
 651557                startViolation,
 651558                velocity,
 651559                normalSquared,
 651560                radius,
 651561                low);
 651562            distance = Fixed64.FromRaw(
 651563                low + GetHalfToEvenIncrement(midpointComparison, low));
 564        }
 565
 652566        return IsRoundedEdgeFeatureValid(
 652567            constraints,
 652568            constraintCount,
 652569            constraintIndex,
 652570            start,
 652571            direction,
 652572            distance,
 652573            radius);
 574    }
 575
 576    private static int CompareExpandedEdgeAtHalf(
 577        Signed576 startViolation,
 578        Signed576 velocity,
 579        Signed576 normalSquared,
 580        Fixed64 radius,
 581        long lowerRaw)
 582    {
 24728583        Signed192 lower = Signed192.Signed(lowerRaw);
 24728584        Signed192 midpoint = WideArithmetic.AddSigned192(
 24728585            WideArithmetic.AddSigned192(lower, lower),
 24728586            SweepOneCoefficient);
 24728587        return CompareExpandedEdgeAt(
 24728588            startViolation,
 24728589            velocity,
 24728590            normalSquared,
 24728591            radius,
 24728592            midpoint,
 24728593            SweepDoubleRawScale);
 594    }
 595
 596    private static int CompareExpandedEdgeAt(
 597        Signed576 startViolation,
 598        Signed576 velocity,
 599        Signed576 normalSquared,
 600        Fixed64 radius,
 601        Signed192 timeNumerator,
 602        Signed192 timeDenominator)
 603    {
 25380604        Signed576 left = WideArithmetic.AddSigned576(
 25380605            WideArithmetic.MultiplySigned576(
 25380606                startViolation,
 25380607                timeDenominator),
 25380608            WideArithmetic.MultiplySigned576(
 25380609                velocity,
 25380610                timeNumerator));
 25380611        if (left.Sign <= 0)
 3025612            return -1;
 613
 22355614        Signed832 leftSquared =
 22355615            WideArithmetic.MultiplySigned576ToSigned832(left, left);
 22355616        Signed320 scaledRadius = WideArithmetic.MultiplySigned192(
 22355617            Signed192.Raw(radius),
 22355618            timeDenominator);
 22355619        Signed832 rightSquared =
 22355620            WideArithmetic.MultiplyNonNegativeToSigned832(
 22355621                Signed832.ExtendValue(
 22355622                    WideArithmetic.MultiplySigned320(
 22355623                        scaledRadius,
 22355624                        scaledRadius)),
 22355625                Signed320.NarrowValue(normalSquared));
 22355626        return WideArithmetic.SubtractSigned832(
 22355627            leftSquared,
 22355628            rightSquared).Sign;
 629    }
 630
 631    private static bool IsRoundedEdgeFeatureValid(
 632        ReadOnlySpan<SweepPlanarConstraint> constraints,
 633        int constraintCount,
 634        int constraintIndex,
 635        Vector2d start,
 636        Vector2d direction,
 637        Fixed64 distance,
 638        Fixed64 radius)
 639    {
 652640        SweepPlanarConstraint edge = constraints[constraintIndex];
 652641        Vector2d normal = WideNormalization.GetNormalized(
 652642            Signed576.ExtendValue(edge.A),
 652643            Signed576.ExtendValue(edge.C));
 652644        Vector2d radial = normal * radius;
 9080645        for (int index = 0; index < constraintCount; index++)
 646        {
 4406647            SweepPlanarConstraint candidate = constraints[index];
 4406648            Signed576 startViolation = WideArithmetic.SubtractSigned576(
 4406649                WideArithmetic.SubtractSigned576(
 4406650                    GetSweepProjection(candidate, start),
 4406651                    GetSweepProjection(candidate, radial)),
 4406652                candidate.K);
 4406653            Signed576 violation = WideArithmetic.AddSigned576(
 4406654                WideArithmetic.MultiplySigned576(
 4406655                    startViolation,
 4406656                    SweepRawScale),
 4406657                WideArithmetic.MultiplySigned576(
 4406658                    GetSweepProjection(candidate, direction),
 4406659                    Signed192.Raw(distance)));
 4406660            Signed320 coefficientMagnitude = WideArithmetic.AddSigned320(
 4406661                GetMagnitude(candidate.A),
 4406662                GetMagnitude(candidate.C));
 4406663            Signed576 oneRawTolerance = WideArithmetic.MultiplySigned576(
 4406664                WideArithmetic.MultiplySigned320(
 4406665                    coefficientMagnitude,
 4406666                    Signed320.ExtendValue(
 4406667                        Signed192.Raw(Fixed64.MinIncrement))),
 4406668                SweepRawScale);
 4406669            if (CompareSigned(violation, oneRawTolerance) > 0)
 518670                return false;
 671        }
 672
 134673        return true;
 674    }
 675
 676    private static bool TryGetRationalPointSweepDistance(
 677        SweepRationalPoint point,
 678        Vector2d start,
 679        Vector2d direction,
 680        Fixed64 maxDistance,
 681        Fixed64 radius,
 682        out Fixed64 distance)
 683    {
 1497684        Signed576 deltaX = WideArithmetic.SubtractSigned576(
 1497685            WideArithmetic.MultiplySigned576(
 1497686                point.Denominator,
 1497687                Signed192.Raw(start.X)),
 1497688            point.X);
 1497689        Signed576 deltaZ = WideArithmetic.SubtractSigned576(
 1497690            WideArithmetic.MultiplySigned576(
 1497691                point.Denominator,
 1497692                Signed192.Raw(start.Y)),
 1497693            point.Z);
 1497694        Signed576 directionX = WideArithmetic.MultiplySigned576(
 1497695            point.Denominator,
 1497696            Signed192.Raw(direction.X));
 1497697        Signed576 directionZ = WideArithmetic.MultiplySigned576(
 1497698            point.Denominator,
 1497699            Signed192.Raw(direction.Y));
 1497700        Signed576 radiusNumerator = WideArithmetic.MultiplySigned576(
 1497701            point.Denominator,
 1497702            Signed192.Raw(radius));
 1497703        Signed832 constant = WideArithmetic.SubtractSigned832(
 1497704            WideArithmetic.AddSigned832(
 1497705                WideArithmetic.MultiplySigned576ToSigned832(deltaX, deltaX),
 1497706                WideArithmetic.MultiplySigned576ToSigned832(deltaZ, deltaZ)),
 1497707            WideArithmetic.MultiplySigned576ToSigned832(
 1497708                radiusNumerator,
 1497709                radiusNumerator));
 1497710        Signed832 projection = WideArithmetic.AddSigned832(
 1497711            WideArithmetic.MultiplySigned576ToSigned832(
 1497712                deltaX,
 1497713                directionX),
 1497714            WideArithmetic.MultiplySigned576ToSigned832(
 1497715                deltaZ,
 1497716                directionZ));
 717        // Triangle-sweep callers share this vertex solver and can reach it
 718        // without a whole-shape start-overlap precheck.
 1497719        if (constant.Sign <= 0)
 720        {
 7721            distance = Fixed64.Zero;
 7722            return true;
 723        }
 1490724        if (projection.Sign >= 0)
 725        {
 15726            distance = default;
 15727            return false;
 728        }
 729
 1475730        Signed832 directionSquared = WideArithmetic.AddSigned832(
 1475731            WideArithmetic.MultiplySigned576ToSigned832(
 1475732                directionX,
 1475733                directionX),
 1475734            WideArithmetic.MultiplySigned576ToSigned832(
 1475735                directionZ,
 1475736                directionZ));
 1475737        Signed832 negativeProjection =
 1475738            WideArithmetic.SubtractSigned832(default, projection);
 1475739        bool closestBeyondMaximum =
 1475740            WideArithmetic.CompareNonNegativeProducts(
 1475741                negativeProjection,
 1475742                Signed832.ExtendValue(SweepRawScale),
 1475743                directionSquared,
 1475744                Signed832.ExtendValue(Signed192.Signed(maxDistance.m_rawValue))) > 0;
 1475745        if (closestBeyondMaximum)
 746        {
 46747            if (CompareRationalPointAt(
 46748                    deltaX,
 46749                    deltaZ,
 46750                    directionX,
 46751                    directionZ,
 46752                    radiusNumerator,
 46753                    Signed192.Signed(maxDistance.m_rawValue),
 46754                    SweepRawScale) > 0)
 755            {
 44756                distance = default;
 44757                return false;
 758            }
 759        }
 1429760        else if (WideArithmetic.CompareNonNegativeProducts(
 1429761                negativeProjection,
 1429762                negativeProjection,
 1429763                directionSquared,
 1429764                constant) < 0)
 765        {
 1322766            distance = default;
 1322767            return false;
 768        }
 769
 109770        Fixed64 closest = maxDistance;
 109771        if (!closestBeyondMaximum)
 772        {
 773            // The exact comparison above proves this nonnegative quotient is
 774            // no greater than maxDistance, so its final Q32.32 value is
 775            // representable.
 107776            _ = Fixed64.TryGetSignedRawRatio(
 107777                negativeProjection,
 107778                directionSquared,
 107779                FixedMath.SHIFT_AMOUNT_I,
 107780                out closest);
 781        }
 782
 109783        long maximumSearchRaw = closest.m_rawValue;
 109784        long high = Math.Max(0L, maximumSearchRaw - 1L);
 109785        if (CompareRationalPointAtHalf(
 109786                deltaX,
 109787                deltaZ,
 109788                directionX,
 109789                directionZ,
 109790                radiusNumerator,
 109791                high) > 0)
 792        {
 5793            distance = closestBeyondMaximum ? maxDistance : closest;
 5794            return true;
 795        }
 796
 104797        long low = 0L;
 3568798        while (low < high)
 799        {
 3464800            long middle = low + ((high - low) >> 1);
 3464801            if (CompareRationalPointAtHalf(
 3464802                    deltaX,
 3464803                    deltaZ,
 3464804                    directionX,
 3464805                    directionZ,
 3464806                    radiusNumerator,
 3464807                    middle) <= 0)
 808            {
 2721809                high = middle;
 810            }
 811            else
 812            {
 743813                low = middle + 1L;
 814            }
 815        }
 816
 104817        int midpointComparison = CompareRationalPointAtHalf(
 104818            deltaX,
 104819            deltaZ,
 104820            directionX,
 104821            directionZ,
 104822            radiusNumerator,
 104823            low);
 104824        distance = Fixed64.FromRaw(
 104825            low + GetHalfToEvenIncrement(midpointComparison, low));
 104826        return true;
 827    }
 828
 829    private static long GetHalfToEvenIncrement(
 830        int midpointComparison,
 831        long lowerRaw)
 832    {
 755833        int nonzero =
 755834            (int)((uint)(midpointComparison | -midpointComparison) >> 31);
 755835        int zero = nonzero ^ 1;
 755836        return zero & (lowerRaw & 1L);
 837    }
 838
 839    private static int CompareRationalPointAtHalf(
 840        Signed576 deltaX,
 841        Signed576 deltaZ,
 842        Signed576 directionX,
 843        Signed576 directionZ,
 844        Signed576 radiusNumerator,
 845        long lowerRaw)
 846    {
 3677847        Signed192 lower = Signed192.Signed(lowerRaw);
 3677848        Signed192 midpoint = WideArithmetic.AddSigned192(
 3677849            WideArithmetic.AddSigned192(lower, lower),
 3677850            SweepOneCoefficient);
 3677851        return CompareRationalPointAt(
 3677852            deltaX,
 3677853            deltaZ,
 3677854            directionX,
 3677855            directionZ,
 3677856            radiusNumerator,
 3677857            midpoint,
 3677858            SweepDoubleRawScale);
 859    }
 860
 861    private static int CompareRationalPointAt(
 862        Signed576 deltaX,
 863        Signed576 deltaZ,
 864        Signed576 directionX,
 865        Signed576 directionZ,
 866        Signed576 radiusNumerator,
 867        Signed192 timeNumerator,
 868        Signed192 timeDenominator)
 869    {
 3723870        Signed576 x = WideArithmetic.AddSigned576(
 3723871            WideArithmetic.MultiplySigned576(deltaX, timeDenominator),
 3723872            WideArithmetic.MultiplySigned576(directionX, timeNumerator));
 3723873        Signed576 z = WideArithmetic.AddSigned576(
 3723874            WideArithmetic.MultiplySigned576(deltaZ, timeDenominator),
 3723875            WideArithmetic.MultiplySigned576(directionZ, timeNumerator));
 3723876        Signed576 scaledRadius =
 3723877            WideArithmetic.MultiplySigned576(
 3723878                radiusNumerator,
 3723879                timeDenominator);
 3723880        return WideArithmetic.SubtractSigned832(
 3723881            WideArithmetic.AddSigned832(
 3723882                WideArithmetic.MultiplySigned576ToSigned832(x, x),
 3723883                WideArithmetic.MultiplySigned576ToSigned832(z, z)),
 3723884            WideArithmetic.MultiplySigned576ToSigned832(
 3723885                scaledRadius,
 3723886                scaledRadius)).Sign;
 887    }
 888
 889    private static Signed576 GetSweepProjection(
 890        SweepPlanarConstraint constraint,
 891        Vector2d point) =>
 15506892        WideArithmetic.AddSigned576(
 15506893            WideArithmetic.MultiplySigned320(
 15506894                constraint.A,
 15506895                Signed320.ExtendValue(Signed192.Raw(point.X))),
 15506896            WideArithmetic.MultiplySigned320(
 15506897                constraint.C,
 15506898                Signed320.ExtendValue(Signed192.Raw(point.Y))));
 899}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHull.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.ConvexHull.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/// Convex hull contact generation logic for <see cref="WideOrientedBox"/>,
 14/// using separating axis tests against box axes, hull face normals, and edge cross products.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    internal static bool TryGetConvexHullContact(
 19        Vector3d boxCenter,
 20        FixedQuaternion boxOrientation,
 21        Vector3d boxHalfExtents,
 22        Vector3d hullOrigin,
 23        FixedQuaternion hullOrientation,
 24        ReadOnlySpan<Vector3d> hullLocalOffsets,
 25        ReadOnlySpan<int> triangleVertexIndices,
 26        ReadOnlySpan<int> edgeVertexPairs,
 27        out FixedContactAnchors contact)
 28    {
 7629        WideRationalBasis3d boxBasis = new(boxOrientation);
 7630        WideRationalBasis3d hullBasis = new(hullOrientation);
 7631        WideRationalBasis3d relativeBasis =
 7632            WideRationalBasis3d.CreateRelative(boxBasis, hullBasis);
 7633        Signed320 unit = Signed320.One;
 7634        Span<WideAxis3> boxAxes = stackalloc WideAxis3[3]
 7635        {
 7636            new(unit, default, default),
 7637            new(default, unit, default),
 7638            new(default, default, unit),
 7639        };
 7640        GetRelativeLocalPointNumerators(
 7641            hullOrigin,
 7642            boxCenter,
 7643            boxBasis,
 7644            out Signed192 translationX,
 7645            out Signed192 translationY,
 7646            out Signed192 translationZ);
 7647        var hullTranslation = new WideAxis3(
 7648            WideArithmetic.MultiplySigned192(
 7649                translationX,
 7650                hullBasis.Denominator),
 7651            WideArithmetic.MultiplySigned192(
 7652                translationY,
 7653                hullBasis.Denominator),
 7654            WideArithmetic.MultiplySigned192(
 7655                translationZ,
 7656                hullBasis.Denominator));
 7657        var best = default(WidePointSpanPenetration);
 60258        for (int index = 0; index < boxAxes.Length; index++)
 59        {
 22660            if (!TryKeepPointSpanAxis(
 22661                    boxAxes[index],
 22662                    boxHalfExtents,
 22663                    relativeBasis,
 22664                    hullTranslation,
 22665                    hullLocalOffsets,
 22666                    ref best))
 67            {
 168                contact = default;
 169                return false;
 70            }
 71        }
 72
 7573        for (int index = 0;
 96774            index < triangleVertexIndices.Length;
 89275            index += 3)
 76        {
 89377            Vector3d first = hullLocalOffsets[
 89378                triangleVertexIndices[index]];
 89379            Vector3d second = hullLocalOffsets[
 89380                triangleVertexIndices[index + 1]];
 89381            Vector3d third = hullLocalOffsets[
 89382                triangleVertexIndices[index + 2]];
 89383            WideGeometry.GetDifferenceCrossProduct3D(
 89384                second.X,
 89385                first.X,
 89386                second.Y,
 89387                first.Y,
 89388                second.Z,
 89389                first.Z,
 89390                third.X,
 89391                first.X,
 89392                third.Y,
 89393                first.Y,
 89394                third.Z,
 89395                first.Z,
 89396                out Signed192 normalX,
 89397                out Signed192 normalY,
 89398                out Signed192 normalZ);
 89399            WideAxis3 axis = WideRigidProjection.TransformLocalAxis(
 893100                relativeBasis,
 893101                normalX,
 893102                normalY,
 893103                normalZ);
 893104            if (!TryKeepPointSpanAxis(
 893105                    axis,
 893106                    boxHalfExtents,
 893107                    relativeBasis,
 893108                    hullTranslation,
 893109                    hullLocalOffsets,
 893110                    ref best))
 111            {
 1112                contact = default;
 1113                return false;
 114            }
 115        }
 116
 1900117        for (int index = 0; index < edgeVertexPairs.Length; index += 2)
 118        {
 877119            Vector3d start = hullLocalOffsets[edgeVertexPairs[index]];
 877120            Vector3d end = hullLocalOffsets[edgeVertexPairs[index + 1]];
 877121            WideAxis3 edge = WideRigidProjection.TransformLocalAxis(
 877122                relativeBasis,
 877123                WideArithmetic.SubtractSigned192(
 877124                    Signed192.Raw(end.X),
 877125                    Signed192.Raw(start.X)),
 877126                WideArithmetic.SubtractSigned192(
 877127                    Signed192.Raw(end.Y),
 877128                    Signed192.Raw(start.Y)),
 877129                WideArithmetic.SubtractSigned192(
 877130                    Signed192.Raw(end.Z),
 877131                    Signed192.Raw(start.Z)));
 877132            for (int axisIndex = 0;
 3506133                axisIndex < boxAxes.Length;
 2629134                axisIndex++)
 135            {
 2630136                if (!TryKeepPointSpanAxis(
 2630137                        WideAxis3.Cross(boxAxes[axisIndex], edge),
 2630138                        boxHalfExtents,
 2630139                        relativeBasis,
 2630140                        hullTranslation,
 2630141                        hullLocalOffsets,
 2630142                        ref best))
 143                {
 1144                    contact = default;
 1145                    return false;
 146                }
 147            }
 148        }
 149
 73150        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 73151        WideRigidProjection.TransformLocalAxis(
 73152            boxBasis,
 73153            orientedAxis,
 73154            out Signed576 worldX,
 73155            out Signed576 worldY,
 73156            out Signed576 worldZ);
 73157        Vector3d normal = WideNormalization.GetNormalized(
 73158            worldX,
 73159            worldY,
 73160            worldZ);
 73161        Vector3d hullLocalPoint = GetHullSupportLocalPoint(
 73162            relativeBasis,
 73163            hullLocalOffsets,
 73164            orientedAxis,
 73165            maximize: false);
 166
 73167        Vector3d boxLocalPoint = GetLocalSupportPoint(
 73168            normal,
 73169            boxOrientation,
 73170            boxHalfExtents);
 73171        Fixed64 depth = best.GetRoundedDepth(out bool depthIsClamped);
 73172        contact = new FixedContactAnchors(
 73173            new FixedPointAnchor(
 73174                boxCenter,
 73175                boxOrientation,
 73176                boxLocalPoint),
 73177            new FixedPointAnchor(
 73178                hullOrigin,
 73179                hullOrientation,
 73180                hullLocalPoint),
 73181            normal,
 73182            depth,
 73183            depthIsClamped);
 73184        return true;
 185    }
 186
 187    private static bool TryKeepPointSpanAxis(
 188        in WideAxis3 axis,
 189        Vector3d boxHalfExtents,
 190        in WideRationalBasis3d relativeBasis,
 191        in WideAxis3 hullTranslation,
 192        ReadOnlySpan<Vector3d> hullLocalOffsets,
 193        ref WidePointSpanPenetration best)
 194    {
 3749195        if (axis.IsZero)
 40196            return true;
 197
 3709198        WideRigidProjection.GetLocalAxisProjections(
 3709199            axis,
 3709200            relativeBasis,
 3709201            out Signed576 localAxisX,
 3709202            out Signed576 localAxisY,
 3709203            out Signed576 localAxisZ);
 3709204        Signed576 minimum = WideRigidProjection.GetLocalOffsetProjection(
 3709205            hullLocalOffsets[0],
 3709206            localAxisX,
 3709207            localAxisY,
 3709208            localAxisZ);
 3709209        Signed576 maximum = minimum;
 59344210        for (int index = 1; index < hullLocalOffsets.Length; index++)
 211        {
 25963212            WideRigidProjection.IncludeProjection(
 25963213                WideRigidProjection.GetLocalOffsetProjection(
 25963214                    hullLocalOffsets[index],
 25963215                    localAxisX,
 25963216                    localAxisY,
 25963217                    localAxisZ),
 25963218                ref minimum,
 25963219                ref maximum);
 220        }
 221
 3709222        Signed576 originProjection = WideAxis3.Dot(
 3709223            axis,
 3709224            hullTranslation);
 3709225        minimum = WideArithmetic.AddSigned576(originProjection, minimum);
 3709226        maximum = WideArithmetic.AddSigned576(originProjection, maximum);
 3709227        Signed576 boxRadius = WideArithmetic.MultiplySigned576(
 3709228            GetLocalBoxProjectionRadiusNumerator(axis, boxHalfExtents),
 3709229            relativeBasis.Denominator);
 3709230        Signed576 pushBoxNegative = WideArithmetic.SubtractSigned576(
 3709231            boxRadius,
 3709232            minimum);
 3709233        Signed576 pushBoxPositive = WideArithmetic.AddSigned576(
 3709234            maximum,
 3709235            boxRadius);
 3709236        if (pushBoxNegative.Sign < 0 || pushBoxPositive.Sign < 0)
 3237            return false;
 238
 3706239        bool negate =
 3706240            CompareSigned(pushBoxPositive, pushBoxNegative) < 0;
 3706241        Signed576 overlap = negate
 3706242            ? pushBoxPositive
 3706243            : pushBoxNegative;
 3706244        Signed320 commonDenominator =
 3706245            Signed320.ExtendValue(relativeBasis.Denominator);
 3706246        Signed576 squaredAxisLength = axis.SquaredLength;
 3706247        if (best.ShouldReplace(
 3706248            overlap,
 3706249            squaredAxisLength,
 3706250            commonDenominator))
 251        {
 145252            best = new WidePointSpanPenetration(
 145253                axis,
 145254                negate,
 145255                overlap,
 145256                squaredAxisLength,
 145257                commonDenominator);
 258        }
 3706259        return true;
 260    }
 261
 262}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHullCapsule.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.ConvexHullCapsule.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 wide-precision convex hull versus capsule contact generation,
 14/// testing face, edge, and vertex candidates to resolve the deepest
 15/// separating axis between an oriented convex hull and a capsule.
 16/// </content>
 17internal static partial class WideOrientedBox
 18{
 19    private const int HullCapsuleMagnitudeWords = 64;
 20
 21    internal static bool TryGetConvexHullCenteredCapsuleContact(
 22        Vector3d hullOrigin,
 23        FixedQuaternion hullRotation,
 24        ReadOnlySpan<Vector3d> hullLocalPoints,
 25        ReadOnlySpan<int> triangleVertexIndices,
 26        ReadOnlySpan<int> edgeVertexPairs,
 27        Vector3d capsuleCenter,
 28        FixedQuaternion capsuleRotation,
 29        Vector3d capsuleLocalAxisDirection,
 30        Fixed64 capsuleAxisLength,
 31        Fixed64 capsuleRadius,
 32        out FixedContactAnchors contact)
 33    {
 3434        WideRationalBasis3d hullBasis = new(hullRotation);
 3435        GetRotatedLocalAxisNumerators(
 3436            capsuleRotation,
 3437            capsuleLocalAxisDirection,
 3438            out Signed192 capsuleAxisX,
 3439            out Signed192 capsuleAxisY,
 3440            out Signed192 capsuleAxisZ,
 3441            out Signed192 capsuleAxisDenominator);
 3442        var capsuleAxis = new WideAxis3(
 3443            Signed320.ExtendValue(capsuleAxisX),
 3444            Signed320.ExtendValue(capsuleAxisY),
 3445            Signed320.ExtendValue(capsuleAxisZ));
 46
 3447        HullCapsuleCandidate best = default;
 3448        bool hasBest = false;
 3449        for (int index = 0;
 38950            index < triangleVertexIndices.Length;
 35551            index += 3)
 52        {
 35853            if (!TryKeepHullCapsuleCandidate(
 35854                    new HullCapsuleCandidate(
 35855                        HullCapsuleCandidateKind.Face,
 35856                        index,
 35857                        0),
 35858                    hullOrigin,
 35859                    hullBasis,
 35860                    hullLocalPoints,
 35861                    triangleVertexIndices,
 35862                    edgeVertexPairs,
 35863                    capsuleCenter,
 35864                    capsuleAxis,
 35865                    capsuleAxisDenominator,
 35866                    capsuleAxisLength,
 35867                    capsuleRadius,
 35868                    ref best,
 35869                    ref hasBest))
 70            {
 371                contact = default;
 372                return false;
 73            }
 74        }
 75
 74876        for (int index = 0; index < edgeVertexPairs.Length; index += 2)
 77        {
 34478            if (!TryKeepHullCapsuleCandidate(
 34479                    new HullCapsuleCandidate(
 34480                        HullCapsuleCandidateKind.EdgeCross,
 34481                        index,
 34482                        0),
 34483                    hullOrigin,
 34484                    hullBasis,
 34485                    hullLocalPoints,
 34486                    triangleVertexIndices,
 34487                    edgeVertexPairs,
 34488                    capsuleCenter,
 34489                    capsuleAxis,
 34490                    capsuleAxisDenominator,
 34491                    capsuleAxisLength,
 34492                    capsuleRadius,
 34493                    ref best,
 34494                    ref hasBest))
 95            {
 196                contact = default;
 197                return false;
 98            }
 99        }
 100
 506101        for (int index = 0; index < hullLocalPoints.Length; index++)
 102        {
 224103            if (!TryKeepHullCapsuleCandidate(
 224104                    new HullCapsuleCandidate(
 224105                        HullCapsuleCandidateKind.VertexCore,
 224106                        index,
 224107                        0),
 224108                    hullOrigin,
 224109                    hullBasis,
 224110                    hullLocalPoints,
 224111                    triangleVertexIndices,
 224112                    edgeVertexPairs,
 224113                    capsuleCenter,
 224114                    capsuleAxis,
 224115                    capsuleAxisDenominator,
 224116                    capsuleAxisLength,
 224117                    capsuleRadius,
 224118                    ref best,
 224119                    ref hasBest))
 120            {
 1121                contact = default;
 1122                return false;
 123            }
 124        }
 125
 696126        for (int index = 0; index < edgeVertexPairs.Length; index += 2)
 127        {
 320128            for (int endpointSign = -1;
 958129                endpointSign <= 1;
 638130                endpointSign += 2)
 131            {
 639132                if (!TryKeepHullCapsuleCandidate(
 639133                        new HullCapsuleCandidate(
 639134                            HullCapsuleCandidateKind.EndpointEdge,
 639135                            index,
 639136                            endpointSign),
 639137                        hullOrigin,
 639138                        hullBasis,
 639139                        hullLocalPoints,
 639140                        triangleVertexIndices,
 639141                        edgeVertexPairs,
 639142                        capsuleCenter,
 639143                        capsuleAxis,
 639144                        capsuleAxisDenominator,
 639145                        capsuleAxisLength,
 639146                        capsuleRadius,
 639147                        ref best,
 639148                        ref hasBest))
 149                {
 1150                    contact = default;
 1151                    return false;
 152                }
 153            }
 154        }
 155
 28156        if (!hasBest)
 157        {
 1158            contact = default;
 1159            return false;
 160        }
 161
 27162        Span<ulong> rational =
 27163            stackalloc ulong[HullCapsuleMagnitudeWords];
 27164        Span<ulong> squaredAxisLength =
 27165            stackalloc ulong[HullCapsuleMagnitudeWords];
 27166        _ = EvaluateHullCapsuleCandidate(
 27167            best,
 27168            hullOrigin,
 27169            hullBasis,
 27170            hullLocalPoints,
 27171            triangleVertexIndices,
 27172            edgeVertexPairs,
 27173            capsuleCenter,
 27174            capsuleAxis,
 27175            capsuleAxisDenominator,
 27176            capsuleAxisLength,
 27177            capsuleRadius,
 27178            rational,
 27179            out int rationalSign,
 27180            squaredAxisLength,
 27181            out CapsuleAxis3 axis,
 27182            out bool negate,
 27183            out Signed192 commonDenominator);
 27184        CapsuleAxis3 orientedAxis = negate ? -axis : axis;
 27185        Vector3d normal = WideNormalization.GetNormalized(
 27186            orientedAxis.X,
 27187            orientedAxis.Y,
 27188            orientedAxis.Z);
 27189        int capsuleAxialSign = -GetCapsuleAxisProjection(
 27190            orientedAxis,
 27191            capsuleAxis).Sign;
 27192        FixedPointAnchor capsuleAnchor =
 27193            WideGeometry.GetCenteredCapsuleSupportAnchor(
 27194                capsuleCenter,
 27195                capsuleRotation,
 27196                capsuleLocalAxisDirection,
 27197                capsuleAxisLength,
 27198                capsuleRadius,
 27199                -normal,
 27200                capsuleAxialSign);
 27201        FixedPointAnchor hullAnchor =
 27202            GetMatchedHullCapsuleSupportAnchor(
 27203                hullOrigin,
 27204                hullRotation,
 27205                hullBasis,
 27206                hullLocalPoints,
 27207                triangleVertexIndices,
 27208                edgeVertexPairs,
 27209                orientedAxis,
 27210                capsuleAnchor);
 27211        GetHullCapsuleDepth(
 27212            rational,
 27213            rationalSign,
 27214            squaredAxisLength,
 27215            commonDenominator,
 27216            capsuleRadius,
 27217            out Fixed64 depth,
 27218            out bool depthIsClamped);
 27219        contact = new FixedContactAnchors(
 27220            hullAnchor,
 27221            capsuleAnchor,
 27222            normal,
 27223            depth,
 27224            depthIsClamped);
 27225        return true;
 226    }
 227
 228    private static bool TryKeepHullCapsuleCandidate(
 229        HullCapsuleCandidate candidate,
 230        Vector3d hullOrigin,
 231        WideRationalBasis3d hullBasis,
 232        ReadOnlySpan<Vector3d> hullLocalPoints,
 233        ReadOnlySpan<int> triangleVertexIndices,
 234        ReadOnlySpan<int> edgeVertexPairs,
 235        Vector3d capsuleCenter,
 236        WideAxis3 capsuleAxis,
 237        Signed192 capsuleAxisDenominator,
 238        Fixed64 capsuleAxisLength,
 239        Fixed64 capsuleRadius,
 240        ref HullCapsuleCandidate best,
 241        ref bool hasBest)
 242    {
 1565243        Span<ulong> rational =
 1565244            stackalloc ulong[HullCapsuleMagnitudeWords];
 1565245        Span<ulong> squaredAxisLength =
 1565246            stackalloc ulong[HullCapsuleMagnitudeWords];
 1565247        int status = EvaluateHullCapsuleCandidate(
 1565248            candidate,
 1565249            hullOrigin,
 1565250            hullBasis,
 1565251            hullLocalPoints,
 1565252            triangleVertexIndices,
 1565253            edgeVertexPairs,
 1565254            capsuleCenter,
 1565255            capsuleAxis,
 1565256            capsuleAxisDenominator,
 1565257            capsuleAxisLength,
 1565258            capsuleRadius,
 1565259            rational,
 1565260            out int rationalSign,
 1565261            squaredAxisLength,
 1565262            out _,
 1565263            out _,
 1565264            out _);
 1565265        if (status < 0)
 6266            return false;
 1559267        if (status == 0)
 117268            return true;
 1442269        if (!hasBest)
 270        {
 31271            best = candidate;
 31272            hasBest = true;
 31273            return true;
 274        }
 275
 1411276        Span<ulong> bestRational =
 1411277            stackalloc ulong[HullCapsuleMagnitudeWords];
 1411278        Span<ulong> bestSquaredAxisLength =
 1411279            stackalloc ulong[HullCapsuleMagnitudeWords];
 1411280        _ = EvaluateHullCapsuleCandidate(
 1411281            best,
 1411282            hullOrigin,
 1411283            hullBasis,
 1411284            hullLocalPoints,
 1411285            triangleVertexIndices,
 1411286            edgeVertexPairs,
 1411287            capsuleCenter,
 1411288            capsuleAxis,
 1411289            capsuleAxisDenominator,
 1411290            capsuleAxisLength,
 1411291            capsuleRadius,
 1411292            bestRational,
 1411293            out int bestRationalSign,
 1411294            bestSquaredAxisLength,
 1411295            out _,
 1411296            out _,
 1411297            out _);
 1411298        if (WideArithmetic.CompareSignedNormalizedMagnitudes(
 1411299                rational,
 1411300                rationalSign,
 1411301                squaredAxisLength,
 1411302                bestRational,
 1411303                bestRationalSign,
 1411304                bestSquaredAxisLength) < 0)
 305        {
 29306            best = candidate;
 307        }
 1411308        return true;
 309    }
 310
 311    // Returns -1 for separation, 0 for a degenerate axis, and 1 for overlap.
 312    private static int EvaluateHullCapsuleCandidate(
 313        HullCapsuleCandidate candidate,
 314        Vector3d hullOrigin,
 315        WideRationalBasis3d hullBasis,
 316        ReadOnlySpan<Vector3d> hullLocalPoints,
 317        ReadOnlySpan<int> triangleVertexIndices,
 318        ReadOnlySpan<int> edgeVertexPairs,
 319        Vector3d capsuleCenter,
 320        WideAxis3 capsuleAxis,
 321        Signed192 capsuleAxisDenominator,
 322        Fixed64 capsuleAxisLength,
 323        Fixed64 capsuleRadius,
 324        Span<ulong> rational,
 325        out int rationalSign,
 326        Span<ulong> squaredAxisLength,
 327        out CapsuleAxis3 axis,
 328        out bool negate,
 329        out Signed192 commonDenominator)
 330    {
 3003331        axis = BuildHullCapsuleCandidateAxis(
 3003332            candidate,
 3003333            hullOrigin,
 3003334            hullBasis,
 3003335            hullLocalPoints,
 3003336            triangleVertexIndices,
 3003337            edgeVertexPairs,
 3003338            capsuleCenter,
 3003339            capsuleAxis,
 3003340            capsuleAxisDenominator,
 3003341            capsuleAxisLength);
 3003342        rational.Clear();
 3003343        squaredAxisLength.Clear();
 3003344        rationalSign = 0;
 3003345        negate = false;
 3003346        commonDenominator = default;
 3003347        if (axis.IsZero)
 117348            return 0;
 349
 2886350        BuildHullCapsuleAxisSquared(axis, squaredAxisLength);
 2886351        Span<ulong> minimum =
 2886352            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886353        Span<ulong> maximum =
 2886354            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886355        GetHullCapsuleProjectionInterval(
 2886356            hullLocalPoints,
 2886357            hullBasis,
 2886358            axis,
 2886359            minimum,
 2886360            out int minimumSign,
 2886361            maximum,
 2886362            out int maximumSign);
 363
 2886364        Signed704 centerProjection = GetHullCapsuleCenterProjection(
 2886365            capsuleCenter,
 2886366            hullOrigin,
 2886367            axis);
 2886368        Span<ulong> centerMagnitude =
 2886369            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886370        centerMagnitude.Clear();
 2886371        GetHullCapsuleMagnitude(
 2886372            centerProjection,
 2886373            centerMagnitude);
 2886374        Span<ulong> hullDenominatorMagnitude =
 2886375            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886376        GetHullCapsuleMagnitude(
 2886377            hullBasis.Denominator,
 2886378            hullDenominatorMagnitude);
 2886379        Span<ulong> scaledCenter =
 2886380            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886381        WideArithmetic.MultiplyMagnitudes(
 2886382            centerMagnitude,
 2886383            hullDenominatorMagnitude,
 2886384            scaledCenter);
 385
 2886386        Span<ulong> positive =
 2886387            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886388        CombineHullCapsuleSignedMagnitudes(
 2886389            maximum,
 2886390            maximumSign,
 2886391            scaledCenter,
 2886392            -centerProjection.Sign,
 2886393            positive,
 2886394            out int positiveSign);
 2886395        Span<ulong> negative =
 2886396            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886397        CombineHullCapsuleSignedMagnitudes(
 2886398            scaledCenter,
 2886399            centerProjection.Sign,
 2886400            minimum,
 2886401            -minimumSign,
 2886402            negative,
 2886403            out int negativeSign);
 404
 2886405        Signed320 baseScale = WideArithmetic.MultiplySigned192(
 2886406            capsuleAxisDenominator,
 2886407            Signed192.Raw(Fixed64.Two));
 2886408        MultiplyHullCapsuleMagnitude(
 2886409            positive,
 2886410            baseScale,
 2886411            positive);
 2886412        MultiplyHullCapsuleMagnitude(
 2886413            negative,
 2886414            baseScale,
 2886415            negative);
 416
 2886417        Signed704 alignment =
 2886418            GetCapsuleAxisProjection(axis, capsuleAxis);
 2886419        Span<ulong> axial =
 2886420            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886421        axial.Clear();
 2886422        GetHullCapsuleMagnitude(alignment, axial);
 2886423        MultiplyHullCapsuleMagnitude(
 2886424            axial,
 2886425            Signed192.Raw(capsuleAxisLength),
 2886426            axial);
 2886427        MultiplyHullCapsuleMagnitude(
 2886428            axial,
 2886429            hullBasis.Denominator,
 2886430            axial);
 2886431        CombineHullCapsuleSignedMagnitudes(
 2886432            positive,
 2886433            positiveSign,
 2886434            axial,
 2886435            1,
 2886436            positive,
 2886437            out positiveSign);
 2886438        CombineHullCapsuleSignedMagnitudes(
 2886439            negative,
 2886440            negativeSign,
 2886441            axial,
 2886442            1,
 2886443            negative,
 2886444            out negativeSign);
 445
 2886446        int directionComparison =
 2886447            CompareHullCapsuleSignedMagnitudes(
 2886448                negative,
 2886449                negativeSign,
 2886450                positive,
 2886451                positiveSign);
 2886452        negate = directionComparison < 0;
 2886453        ReadOnlySpan<ulong> selected =
 2886454            negate ? negative : positive;
 2886455        rationalSign = negate ? negativeSign : positiveSign;
 2886456        selected.CopyTo(rational);
 457
 2886458        Signed576 commonWide = WideArithmetic.MultiplySigned576(
 2886459            Signed576.ExtendValue(
 2886460                WideArithmetic.MultiplySigned192(
 2886461                    hullBasis.Denominator,
 2886462                    capsuleAxisDenominator)),
 2886463            Signed192.Raw(Fixed64.Two));
 2886464        _ = Signed192.TryNarrowSigned(
 2886465            commonWide,
 2886466            out commonDenominator);
 2886467        Signed320 radialCoefficient =
 2886468            WideArithmetic.MultiplySigned192(
 2886469                commonDenominator,
 2886470                Signed192.Raw(capsuleRadius));
 2886471        Span<ulong> coefficient =
 2886472            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886473        GetHullCapsuleMagnitude(
 2886474            radialCoefficient,
 2886475            coefficient);
 2886476        return WideArithmetic.GetSignedMagnitudeAndSquareRootSign(
 2886477                rational,
 2886478                rationalSign,
 2886479                coefficient,
 2886480                radialCoefficient.Sign,
 2886481                squaredAxisLength) < 0
 2886482            ? -1
 2886483            : 1;
 484    }
 485
 486    private static CapsuleAxis3 BuildHullCapsuleCandidateAxis(
 487        HullCapsuleCandidate candidate,
 488        Vector3d hullOrigin,
 489        WideRationalBasis3d hullBasis,
 490        ReadOnlySpan<Vector3d> hullLocalPoints,
 491        ReadOnlySpan<int> triangleVertexIndices,
 492        ReadOnlySpan<int> edgeVertexPairs,
 493        Vector3d capsuleCenter,
 494        WideAxis3 capsuleAxis,
 495        Signed192 capsuleAxisDenominator,
 496        Fixed64 capsuleAxisLength)
 497    {
 3003498        if (candidate.Kind == HullCapsuleCandidateKind.Face)
 499        {
 1720500            Vector3d first = hullLocalPoints[
 1720501                triangleVertexIndices[candidate.Index]];
 1720502            Vector3d second = hullLocalPoints[
 1720503                triangleVertexIndices[candidate.Index + 1]];
 1720504            Vector3d third = hullLocalPoints[
 1720505                triangleVertexIndices[candidate.Index + 2]];
 1720506            WideGeometry.GetDifferenceCrossProduct3D(
 1720507                second.X,
 1720508                first.X,
 1720509                second.Y,
 1720510                first.Y,
 1720511                second.Z,
 1720512                first.Z,
 1720513                third.X,
 1720514                first.X,
 1720515                third.Y,
 1720516                first.Y,
 1720517                third.Z,
 1720518                first.Z,
 1720519                out Signed192 normalX,
 1720520                out Signed192 normalY,
 1720521                out Signed192 normalZ);
 1720522            return ToCapsuleAxis(WideRigidProjection.TransformLocalAxis(
 1720523                hullBasis,
 1720524                normalX,
 1720525                normalY,
 1720526                normalZ));
 527        }
 1283528        if (candidate.Kind == HullCapsuleCandidateKind.EdgeCross)
 529        {
 380530            WideAxis3 edge = GetHullEdge(
 380531                hullBasis,
 380532                hullLocalPoints[edgeVertexPairs[candidate.Index]],
 380533                hullLocalPoints[edgeVertexPairs[candidate.Index + 1]]);
 380534            return ToCapsuleAxis(WideAxis3.Cross(edge, capsuleAxis));
 535        }
 903536        if (candidate.Kind == HullCapsuleCandidateKind.VertexCore)
 537        {
 256538            return GetVertexToCapsuleAxis(
 256539                hullOrigin,
 256540                capsuleCenter,
 256541                hullBasis,
 256542                hullLocalPoints[candidate.Index],
 256543                capsuleAxis,
 256544                capsuleAxisDenominator,
 256545                capsuleAxisLength);
 546        }
 547
 647548        return GetCapsuleEndpointToHullEdgeAxis(
 647549            hullOrigin,
 647550            capsuleCenter,
 647551            hullBasis,
 647552            hullLocalPoints[edgeVertexPairs[candidate.Index]],
 647553            hullLocalPoints[edgeVertexPairs[candidate.Index + 1]],
 647554            capsuleAxis,
 647555            capsuleAxisDenominator,
 647556            capsuleAxisLength,
 647557            candidate.EndpointSign);
 558    }
 559
 560    private static CapsuleAxis3 GetCapsuleEndpointToHullEdgeAxis(
 561        Vector3d hullOrigin,
 562        Vector3d capsuleCenter,
 563        WideRationalBasis3d hullBasis,
 564        Vector3d localStart,
 565        Vector3d localEnd,
 566        WideAxis3 capsuleAxis,
 567        Signed192 capsuleAxisDenominator,
 568        Fixed64 capsuleAxisLength,
 569        int endpointSign)
 570    {
 647571        WideAxis3 startToEndpoint = GetCornerToAxisEndpointAxis3D(
 647572            hullOrigin,
 647573            capsuleCenter,
 647574            hullBasis,
 647575            localStart,
 647576            capsuleAxis,
 647577            capsuleAxisDenominator,
 647578            capsuleAxisLength,
 647579            endpointSign);
 647580        WideAxis3 edge = GetHullEdge(
 647581            hullBasis,
 647582            localStart,
 647583            localEnd);
 647584        Signed576 edgeSquared = edge.SquaredLength;
 647585        if (edgeSquared.IsZero)
 6586            return ToCapsuleAxis(startToEndpoint);
 587
 641588        Signed576 projection =
 641589            WideAxis3.Dot(startToEndpoint, edge);
 641590        if (projection.Sign <= 0)
 180591            return ToCapsuleAxis(startToEndpoint);
 461592        Signed576 upperBound = WideArithmetic.MultiplySigned576(
 461593            WideArithmetic.MultiplySigned576(
 461594                edgeSquared,
 461595                capsuleAxisDenominator),
 461596            Signed192.Raw(Fixed64.Two));
 461597        if (WideArithmetic.CompareNonNegative(
 461598                projection,
 461599                upperBound) >= 0)
 600        {
 188601            return ToCapsuleAxis(GetCornerToAxisEndpointAxis3D(
 188602                hullOrigin,
 188603                capsuleCenter,
 188604                hullBasis,
 188605                localEnd,
 188606                capsuleAxis,
 188607                capsuleAxisDenominator,
 188608                capsuleAxisLength,
 188609                endpointSign));
 610        }
 611
 273612        return GetPerpendicularAxis(
 273613            startToEndpoint,
 273614            edge,
 273615            edgeSquared,
 273616            projection);
 617    }
 618
 619}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHullCapsule.Support.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.ConvexHullCapsule.Support.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/// Support utilities for convex-hull vs capsule tests: candidate feature
 14/// classification and wide, fixed-point projection interval computation
 15/// along a capsule axis within a rational basis.
 16/// </content>
 17internal static partial class WideOrientedBox
 18{
 19    #region Nested Types
 20
 21    private enum HullCapsuleCandidateKind
 22    {
 23        Face,
 24        EdgeCross,
 25        VertexCore,
 26        EndpointEdge,
 27    }
 28
 29    private readonly struct HullCapsuleCandidate
 30    {
 31        internal readonly HullCapsuleCandidateKind Kind;
 32        internal readonly int Index;
 33        internal readonly int EndpointSign;
 34
 35        internal HullCapsuleCandidate(
 36            HullCapsuleCandidateKind kind,
 37            int index,
 38            int endpointSign)
 39        {
 156540            Kind = kind;
 156541            Index = index;
 156542            EndpointSign = endpointSign;
 156543        }
 44    }
 45
 46    #endregion
 47
 48    private static void GetHullCapsuleProjectionInterval(
 49        ReadOnlySpan<Vector3d> points,
 50        WideRationalBasis3d basis,
 51        CapsuleAxis3 axis,
 52        Span<ulong> minimum,
 53        out int minimumSign,
 54        Span<ulong> maximum,
 55        out int maximumSign)
 56    {
 288657        BuildHullCapsuleLocalProjection(
 288658            points[0],
 288659            basis,
 288660            axis,
 288661            minimum,
 288662            out minimumSign);
 288663        minimum.CopyTo(maximum);
 288664        maximumSign = minimumSign;
 288665        Span<ulong> candidate =
 288666            stackalloc ulong[HullCapsuleMagnitudeWords];
 4588067        for (int index = 1; index < points.Length; index++)
 68        {
 2005469            BuildHullCapsuleLocalProjection(
 2005470                points[index],
 2005471                basis,
 2005472                axis,
 2005473                candidate,
 2005474                out int candidateSign);
 2005475            if (CompareHullCapsuleSignedMagnitudes(
 2005476                    candidate,
 2005477                    candidateSign,
 2005478                    minimum,
 2005479                    minimumSign) < 0)
 80            {
 229581                candidate.CopyTo(minimum);
 229582                minimumSign = candidateSign;
 83            }
 2005484            if (CompareHullCapsuleSignedMagnitudes(
 2005485                    candidate,
 2005486                    candidateSign,
 2005487                    maximum,
 2005488                    maximumSign) > 0)
 89            {
 172990                candidate.CopyTo(maximum);
 172991                maximumSign = candidateSign;
 92            }
 93        }
 288694    }
 95
 96    private static void BuildHullCapsuleLocalProjection(
 97        Vector3d point,
 98        WideRationalBasis3d basis,
 99        CapsuleAxis3 axis,
 100        Span<ulong> result,
 101        out int resultSign)
 102    {
 24064103        Span<ulong> x =
 24064104            stackalloc ulong[HullCapsuleMagnitudeWords];
 24064105        Span<ulong> y =
 24064106            stackalloc ulong[HullCapsuleMagnitudeWords];
 24064107        Span<ulong> z =
 24064108            stackalloc ulong[HullCapsuleMagnitudeWords];
 24064109        BuildHullCapsuleProjectionTerm(
 24064110            GetCapsuleBasisProjection(
 24064111                axis,
 24064112                basis.Xx,
 24064113                basis.Xy,
 24064114                basis.Xz),
 24064115            Signed192.Raw(point.X),
 24064116            x,
 24064117            out int xSign);
 24064118        BuildHullCapsuleProjectionTerm(
 24064119            GetCapsuleBasisProjection(
 24064120                axis,
 24064121                basis.Yx,
 24064122                basis.Yy,
 24064123                basis.Yz),
 24064124            Signed192.Raw(point.Y),
 24064125            y,
 24064126            out int ySign);
 24064127        BuildHullCapsuleProjectionTerm(
 24064128            GetCapsuleBasisProjection(
 24064129                axis,
 24064130                basis.Zx,
 24064131                basis.Zy,
 24064132                basis.Zz),
 24064133            Signed192.Raw(point.Z),
 24064134            z,
 24064135            out int zSign);
 24064136        Span<ulong> xy =
 24064137            stackalloc ulong[HullCapsuleMagnitudeWords];
 24064138        CombineHullCapsuleSignedMagnitudes(
 24064139            x,
 24064140            xSign,
 24064141            y,
 24064142            ySign,
 24064143            xy,
 24064144            out int xySign);
 24064145        CombineHullCapsuleSignedMagnitudes(
 24064146            xy,
 24064147            xySign,
 24064148            z,
 24064149            zSign,
 24064150            result,
 24064151            out resultSign);
 24064152    }
 153
 154    private static void BuildHullCapsuleProjectionTerm(
 155        Signed704 projection,
 156        Signed192 coordinate,
 157        Span<ulong> result,
 158        out int resultSign)
 159    {
 72192160        Span<ulong> projectionMagnitude =
 72192161            stackalloc ulong[HullCapsuleMagnitudeWords];
 72192162        projectionMagnitude.Clear();
 72192163        GetHullCapsuleMagnitude(
 72192164            projection,
 72192165            projectionMagnitude);
 72192166        Span<ulong> coordinateMagnitude =
 72192167            stackalloc ulong[HullCapsuleMagnitudeWords];
 72192168        GetHullCapsuleMagnitude(
 72192169            coordinate,
 72192170            coordinateMagnitude);
 72192171        WideArithmetic.MultiplyMagnitudes(
 72192172            projectionMagnitude,
 72192173            coordinateMagnitude,
 72192174            result);
 72192175        resultSign = projection.Sign * coordinate.Sign;
 72192176    }
 177
 178    private static Signed704 GetHullCapsuleCenterProjection(
 179        Vector3d end,
 180        Vector3d start,
 181        CapsuleAxis3 axis) =>
 2886182        WideArithmetic.AddSigned704(
 2886183            WideArithmetic.AddSigned704(
 2886184                WideArithmetic.MultiplySigned576ToSigned704(
 2886185                    axis.X,
 2886186                    Signed320.ExtendValue(
 2886187                        WideArithmetic.SubtractSigned192(
 2886188                            Signed192.Raw(end.X),
 2886189                            Signed192.Raw(start.X)))),
 2886190                WideArithmetic.MultiplySigned576ToSigned704(
 2886191                    axis.Y,
 2886192                    Signed320.ExtendValue(
 2886193                        WideArithmetic.SubtractSigned192(
 2886194                            Signed192.Raw(end.Y),
 2886195                            Signed192.Raw(start.Y))))),
 2886196            WideArithmetic.MultiplySigned576ToSigned704(
 2886197                axis.Z,
 2886198                Signed320.ExtendValue(
 2886199                    WideArithmetic.SubtractSigned192(
 2886200                        Signed192.Raw(end.Z),
 2886201                        Signed192.Raw(start.Z)))));
 202
 203    private static void BuildHullCapsuleAxisSquared(
 204        CapsuleAxis3 axis,
 205        Span<ulong> result)
 206    {
 2886207        Span<ulong> component =
 2886208            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886209        Span<ulong> square =
 2886210            stackalloc ulong[HullCapsuleMagnitudeWords];
 2886211        result.Clear();
 2886212        GetHullCapsuleMagnitude(axis.X, component);
 2886213        WideArithmetic.MultiplyMagnitudes(
 2886214            component,
 2886215            component,
 2886216            square);
 2886217        WideArithmetic.AddMagnitudeInto(square, result);
 2886218        GetHullCapsuleMagnitude(axis.Y, component);
 2886219        WideArithmetic.MultiplyMagnitudes(
 2886220            component,
 2886221            component,
 2886222            square);
 2886223        WideArithmetic.AddMagnitudeInto(square, result);
 2886224        GetHullCapsuleMagnitude(axis.Z, component);
 2886225        WideArithmetic.MultiplyMagnitudes(
 2886226            component,
 2886227            component,
 2886228            square);
 2886229        WideArithmetic.AddMagnitudeInto(square, result);
 2886230    }
 231
 232    private static FixedPointAnchor GetMatchedHullCapsuleSupportAnchor(
 233        Vector3d hullOrigin,
 234        FixedQuaternion hullRotation,
 235        WideRationalBasis3d basis,
 236        ReadOnlySpan<Vector3d> points,
 237        ReadOnlySpan<int> triangleVertexIndices,
 238        ReadOnlySpan<int> edgeVertexPairs,
 239        CapsuleAxis3 orientedAxis,
 240        in FixedPointAnchor target)
 241    {
 27242        int supportIndex = 0;
 27243        Span<ulong> best =
 27244            stackalloc ulong[HullCapsuleMagnitudeWords];
 27245        BuildHullCapsuleLocalProjection(
 27246            points[0],
 27247            basis,
 27248            orientedAxis,
 27249            best,
 27250            out int bestSign);
 27251        Span<ulong> candidate =
 27252            stackalloc ulong[HullCapsuleMagnitudeWords];
 424253        for (int index = 1; index < points.Length; index++)
 254        {
 185255            BuildHullCapsuleLocalProjection(
 185256                points[index],
 185257                basis,
 185258                orientedAxis,
 185259                candidate,
 185260                out int candidateSign);
 185261            if (CompareHullCapsuleSignedMagnitudes(
 185262                    candidate,
 185263                    candidateSign,
 185264                    best,
 185265                    bestSign) <= 0)
 266            {
 267                continue;
 268            }
 25269            supportIndex = index;
 25270            candidate.CopyTo(best);
 25271            bestSign = candidateSign;
 272        }
 273
 27274        FixedPointAnchor closest = new(
 27275            hullOrigin,
 27276            hullRotation,
 27277            points[supportIndex]);
 27278        for (int index = 0;
 341279            index < triangleVertexIndices.Length;
 314280            index += 3)
 281        {
 314282            Vector3d first = points[
 314283                triangleVertexIndices[index]];
 314284            Vector3d second = points[
 314285                triangleVertexIndices[index + 1]];
 314286            Vector3d third = points[
 314287                triangleVertexIndices[index + 2]];
 314288            if (!IsHullCapsuleSupportPoint(
 314289                    first,
 314290                    basis,
 314291                    orientedAxis,
 314292                    best,
 314293                    bestSign)
 314294                || !IsHullCapsuleSupportPoint(
 314295                    second,
 314296                    basis,
 314297                    orientedAxis,
 314298                    best,
 314299                    bestSign)
 314300                || !IsHullCapsuleSupportPoint(
 314301                    third,
 314302                    basis,
 314303                    orientedAxis,
 314304                    best,
 314305                    bestSign))
 306            {
 307                continue;
 308            }
 309
 48310            FixedPointAnchor candidateAnchor =
 48311                new FixedTriangle(first, second, third)
 48312                    .GetClosestPointAnchor(
 48313                        hullOrigin,
 48314                        hullRotation,
 48315                        target);
 48316            if (target.CompareSquaredDistance(
 48317                    candidateAnchor,
 48318                    closest) < 0)
 319            {
 24320                closest = candidateAnchor;
 321            }
 322        }
 323
 27324        for (int index = 0;
 343325            index < edgeVertexPairs.Length;
 316326            index += 2)
 327        {
 316328            Vector3d start =
 316329                points[edgeVertexPairs[index]];
 316330            Vector3d end =
 316331                points[edgeVertexPairs[index + 1]];
 316332            if (!IsHullCapsuleSupportPoint(
 316333                    start,
 316334                    basis,
 316335                    orientedAxis,
 316336                    best,
 316337                    bestSign)
 316338                || !IsHullCapsuleSupportPoint(
 316339                    end,
 316340                    basis,
 316341                    orientedAxis,
 316342                    best,
 316343                    bestSign))
 344            {
 345                continue;
 346            }
 347
 99348            FixedPointAnchor candidateAnchor =
 99349                new FixedTriangle(start, end, end)
 99350                    .GetClosestPointAnchor(
 99351                        hullOrigin,
 99352                        hullRotation,
 99353                        target);
 99354            if (target.CompareSquaredDistance(
 99355                    candidateAnchor,
 99356                    closest) < 0)
 357            {
 3358                closest = candidateAnchor;
 359            }
 360        }
 27361        return closest;
 362    }
 363
 364    private static bool IsHullCapsuleSupportPoint(
 365        Vector3d point,
 366        WideRationalBasis3d basis,
 367        CapsuleAxis3 orientedAxis,
 368        ReadOnlySpan<ulong> supportProjection,
 369        int supportProjectionSign)
 370    {
 912371        Span<ulong> projection =
 912372            stackalloc ulong[HullCapsuleMagnitudeWords];
 912373        BuildHullCapsuleLocalProjection(
 912374            point,
 912375            basis,
 912376            orientedAxis,
 912377            projection,
 912378            out int projectionSign);
 912379        return CompareHullCapsuleSignedMagnitudes(
 912380            projection,
 912381            projectionSign,
 912382            supportProjection,
 912383            supportProjectionSign) == 0;
 384    }
 385
 386    private static void GetHullCapsuleDepth(
 387        ReadOnlySpan<ulong> rational,
 388        int rationalSign,
 389        ReadOnlySpan<ulong> squaredAxisLength,
 390        Signed192 commonDenominator,
 391        Fixed64 radius,
 392        out Fixed64 depth,
 393        out bool depthIsClamped)
 394    {
 27395        ulong floor = 0UL;
 27396        ulong high = unchecked((ulong)long.MaxValue);
 1728397        while (floor < high)
 398        {
 1701399            ulong midpoint = floor + ((high - floor + 1UL) >> 1);
 1701400            int comparison = CompareHullCapsuleDepthToTwiceRaw(
 1701401                rational,
 1701402                rationalSign,
 1701403                squaredAxisLength,
 1701404                commonDenominator,
 1701405                radius,
 1701406                new Signed192(0UL, 0UL, midpoint << 1));
 1701407            if (comparison >= 0)
 408            {
 155409                floor = midpoint;
 410            }
 411            else
 412            {
 1546413                high = midpoint - 1UL;
 414            }
 415        }
 416
 27417        if (floor == unchecked((ulong)long.MaxValue))
 418        {
 2419            depth = Fixed64.MaxValue;
 2420            depthIsClamped =
 2421                CompareHullCapsuleDepthToTwiceRaw(
 2422                    rational,
 2423                    rationalSign,
 2424                    squaredAxisLength,
 2425                    commonDenominator,
 2426                    radius,
 2427                    new Signed192(
 2428                        0UL,
 2429                        0UL,
 2430                        unchecked((ulong)long.MaxValue << 1))) > 0;
 2431            return;
 432        }
 433
 25434        int midpointComparison =
 25435            CompareHullCapsuleDepthToTwiceRaw(
 25436                rational,
 25437                rationalSign,
 25438                squaredAxisLength,
 25439                commonDenominator,
 25440                radius,
 25441                new Signed192(
 25442                    0UL,
 25443                    0UL,
 25444                    (floor << 1) | 1UL));
 445        // The comparator is -1, 0, or 1. Adding one plus the floor parity
 446        // encodes greater-than-half and midpoint-to-even as a 0/1 increment.
 25447        ulong roundingIncrement =
 25448            (ulong)((midpointComparison + 1 + (int)(floor & 1UL)) >> 1);
 25449        depth = Fixed64.FromRaw(
 25450            (long)(floor + roundingIncrement));
 25451        depthIsClamped = false;
 25452    }
 453
 454    private static int CompareHullCapsuleDepthToTwiceRaw(
 455        ReadOnlySpan<ulong> rational,
 456        int rationalSign,
 457        ReadOnlySpan<ulong> squaredAxisLength,
 458        Signed192 commonDenominator,
 459        Fixed64 radius,
 460        Signed192 twiceRaw)
 461    {
 1728462        Span<ulong> twiceRational =
 1728463            stackalloc ulong[HullCapsuleMagnitudeWords];
 1728464        rational.CopyTo(twiceRational);
 1728465        WideArithmetic.AddMagnitudeInto(
 1728466            rational,
 1728467            twiceRational);
 1728468        Signed192 radialDelta = WideArithmetic.SubtractSigned192(
 1728469            WideArithmetic.AddSigned192(
 1728470                Signed192.Raw(radius),
 1728471                Signed192.Raw(radius)),
 1728472            twiceRaw);
 1728473        Signed320 coefficient = WideArithmetic.MultiplySigned192(
 1728474            commonDenominator,
 1728475            radialDelta);
 1728476        Span<ulong> coefficientMagnitude =
 1728477            stackalloc ulong[HullCapsuleMagnitudeWords];
 1728478        GetHullCapsuleMagnitude(
 1728479            coefficient,
 1728480            coefficientMagnitude);
 1728481        return WideArithmetic.GetSignedMagnitudeAndSquareRootSign(
 1728482            twiceRational,
 1728483            rationalSign,
 1728484            coefficientMagnitude,
 1728485            coefficient.Sign,
 1728486            squaredAxisLength);
 487    }
 488
 489    private static void MultiplyHullCapsuleMagnitude(
 490        Span<ulong> value,
 491        Signed192 factor,
 492        Span<ulong> result)
 493    {
 5772494        Span<ulong> factorMagnitude =
 5772495            stackalloc ulong[HullCapsuleMagnitudeWords];
 5772496        Span<ulong> product =
 5772497            stackalloc ulong[HullCapsuleMagnitudeWords];
 5772498        GetHullCapsuleMagnitude(factor, factorMagnitude);
 5772499        WideArithmetic.MultiplyMagnitudes(
 5772500            value,
 5772501            factorMagnitude,
 5772502            product);
 5772503        product.CopyTo(result);
 5772504    }
 505
 506    private static void MultiplyHullCapsuleMagnitude(
 507        Span<ulong> value,
 508        Signed320 factor,
 509        Span<ulong> result)
 510    {
 5772511        Span<ulong> factorMagnitude =
 5772512            stackalloc ulong[HullCapsuleMagnitudeWords];
 5772513        Span<ulong> product =
 5772514            stackalloc ulong[HullCapsuleMagnitudeWords];
 5772515        GetHullCapsuleMagnitude(factor, factorMagnitude);
 5772516        WideArithmetic.MultiplyMagnitudes(
 5772517            value,
 5772518            factorMagnitude,
 5772519            product);
 5772520        product.CopyTo(result);
 5772521    }
 522
 523    private static void GetHullCapsuleMagnitude(
 524        Signed192 value,
 525        Span<ulong> result)
 526    {
 80850527        result.Clear();
 80850528        WideArithmetic.GetMagnitude(
 80850529            value,
 80850530            out result[2],
 80850531            out result[1],
 80850532            out result[0]);
 80850533    }
 534
 535    private static void GetHullCapsuleMagnitude(
 536        Signed320 value,
 537        Span<ulong> result)
 538    {
 10386539        result.Clear();
 10386540        WideArithmetic.GetMagnitude(
 10386541            value,
 10386542            out result[4],
 10386543            out result[3],
 10386544            out result[2],
 10386545            out result[1],
 10386546            out result[0]);
 10386547    }
 548
 549    private static void GetHullCapsuleMagnitude(
 550        Signed576 value,
 551        Span<ulong> result)
 552    {
 8658553        result.Clear();
 8658554        Span<ulong> magnitude = stackalloc ulong[9];
 8658555        WideArithmetic.GetMagnitude(value, magnitude);
 8658556        magnitude.CopyTo(result);
 8658557    }
 558
 559    private static void GetHullCapsuleMagnitude(
 560        Signed704 value,
 561        Span<ulong> result)
 562    {
 77964563        result.Clear();
 77964564        Span<ulong> magnitude = stackalloc ulong[11];
 77964565        WideArithmetic.GetMagnitude(value, magnitude);
 77964566        magnitude.CopyTo(result);
 77964567    }
 568
 569    private static int CompareHullCapsuleSignedMagnitudes(
 570        ReadOnlySpan<ulong> left,
 571        int leftSign,
 572        ReadOnlySpan<ulong> right,
 573        int rightSign)
 574    {
 44091575        if (leftSign != rightSign)
 24262576            return leftSign < rightSign ? -1 : 1;
 19829577        if (leftSign == 0)
 728578            return 0;
 19101579        int comparison =
 19101580            WideArithmetic.CompareMagnitudeEqualLength(left, right);
 19101581        return leftSign > 0 ? comparison : -comparison;
 582    }
 583
 584    private static void CombineHullCapsuleSignedMagnitudes(
 585        ReadOnlySpan<ulong> left,
 586        int leftSign,
 587        ReadOnlySpan<ulong> right,
 588        int rightSign,
 589        Span<ulong> result,
 590        out int resultSign)
 591    {
 59672592        if (leftSign == 0
 59672593            || WideArithmetic.IsZeroMagnitude(left))
 594        {
 11674595            right.CopyTo(result);
 11674596            resultSign = WideArithmetic.IsZeroMagnitude(right)
 11674597                ? 0
 11674598                : rightSign;
 11674599            return;
 600        }
 47998601        if (rightSign == 0
 47998602            || WideArithmetic.IsZeroMagnitude(right))
 603        {
 34888604            left.CopyTo(result);
 34888605            resultSign = leftSign;
 34888606            return;
 607        }
 13110608        if (leftSign == rightSign)
 609        {
 6831610            left.CopyTo(result);
 6831611            WideArithmetic.AddMagnitudeInto(right, result);
 6831612            resultSign = leftSign;
 6831613            return;
 614        }
 615
 6279616        int comparison =
 6279617            WideArithmetic.CompareMagnitudeEqualLength(left, right);
 6279618        if (comparison == 0)
 619        {
 1983620            result.Clear();
 1983621            resultSign = 0;
 622        }
 4296623        else if (comparison > 0)
 624        {
 2730625            WideArithmetic.SubtractEqualMagnitudes(
 2730626                left,
 2730627                right,
 2730628                result);
 2730629            resultSign = leftSign;
 630        }
 631        else
 632        {
 1566633            WideArithmetic.SubtractEqualMagnitudes(
 1566634                right,
 1566635                left,
 1566636                result);
 1566637            resultSign = rightSign;
 638        }
 1566639    }
 640}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHullPair.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.ConvexHullPair.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 convex hull containment and separating-axis
 14/// tests for oriented boxes against arbitrary convex hulls.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    internal static bool ContainsConvexHullPoint(
 19        Vector3d hullOrigin,
 20        FixedQuaternion hullRotation,
 21        ReadOnlySpan<Vector3d> hullLocalPoints,
 22        ReadOnlySpan<int> triangleVertexIndices,
 23        Vector3d hullInteriorLocalPoint,
 24        FixedPointAnchor point)
 25    {
 526        if (!point.Rotation.IsNormalized())
 127            return false;
 28
 429        WideRationalBasis3d hullBasis = new(hullRotation);
 430        WideRationalBasis3d pointBasis = new(point.Rotation);
 8831        for (int index = 0; index < triangleVertexIndices.Length; index += 3)
 32        {
 4233            Vector3d first = hullLocalPoints[triangleVertexIndices[index]];
 4234            Vector3d second = hullLocalPoints[triangleVertexIndices[index + 1]];
 4235            Vector3d third = hullLocalPoints[triangleVertexIndices[index + 2]];
 4236            WideGeometry.GetDifferenceCrossProduct3D(
 4237                second.X,
 4238                first.X,
 4239                second.Y,
 4240                first.Y,
 4241                second.Z,
 4242                first.Z,
 4243                third.X,
 4244                first.X,
 4245                third.Y,
 4246                first.Y,
 4247                third.Z,
 4248                first.Z,
 4249                out Signed192 normalX,
 4250                out Signed192 normalY,
 4251                out Signed192 normalZ);
 4252            WideAxis3 axis = WideRigidProjection.TransformLocalAxis(
 4253                hullBasis,
 4254                normalX,
 4255                normalY,
 4256                normalZ);
 4257            if (axis.IsZero)
 58                continue;
 59
 4060            WideRigidProjection.GetLocalAxisProjections(
 4061                axis,
 4062                hullBasis,
 4063                out Signed576 hullAxisX,
 4064                out Signed576 hullAxisY,
 4065                out Signed576 hullAxisZ);
 4066            Signed576 faceProjection = WideRigidProjection.GetLocalOffsetProjection(
 4067                first,
 4068                hullAxisX,
 4069                hullAxisY,
 4070                hullAxisZ);
 4071            Signed576 interiorDelta = WideArithmetic.SubtractSigned576(
 4072                WideRigidProjection.GetLocalOffsetProjection(
 4073                    hullInteriorLocalPoint,
 4074                    hullAxisX,
 4075                    hullAxisY,
 4076                    hullAxisZ),
 4077                faceProjection);
 4078            if (interiorDelta.Sign == 0)
 79                continue;
 80
 3881            Signed576 originProjection = WideRigidProjection.GetWorldOriginDifferenceProjection(
 3882                point.Origin,
 3883                hullOrigin,
 3884                axis);
 3885            WideRigidProjection.GetLocalAxisProjections(
 3886                axis,
 3887                pointBasis,
 3888                out Signed576 pointAxisX,
 3889                out Signed576 pointAxisY,
 3890                out Signed576 pointAxisZ);
 3891            Signed576 pointProjection = WideArithmetic.MultiplySigned576(
 3892                WideArithmetic.AddSigned576(
 3893                    WideArithmetic.MultiplySigned576(
 3894                        originProjection,
 3895                        pointBasis.Denominator),
 3896                    WideRigidProjection.GetLocalOffsetProjection(
 3897                        point.LocalPoint,
 3898                        pointAxisX,
 3899                        pointAxisY,
 38100                        pointAxisZ)),
 38101                hullBasis.Denominator);
 38102            Signed576 faceProjectionCommon = WideArithmetic.MultiplySigned576(
 38103                faceProjection,
 38104                pointBasis.Denominator);
 38105            Signed576 pointDelta = WideArithmetic.SubtractSigned576(
 38106                pointProjection,
 38107                faceProjectionCommon);
 38108            if ((pointDelta.Sign != 0)
 38109                & (pointDelta.Sign != interiorDelta.Sign))
 110            {
 2111                return false;
 112            }
 113        }
 114
 2115        return true;
 116    }
 117
 118    internal static bool TryGetConvexHullContact(
 119        Vector3d firstOrigin,
 120        FixedQuaternion firstRotation,
 121        ReadOnlySpan<Vector3d> firstLocalPoints,
 122        ReadOnlySpan<int> firstTriangleVertexIndices,
 123        ReadOnlySpan<int> firstEdgeVertexPairs,
 124        Vector3d secondOrigin,
 125        FixedQuaternion secondRotation,
 126        ReadOnlySpan<Vector3d> secondLocalPoints,
 127        ReadOnlySpan<int> secondTriangleVertexIndices,
 128        ReadOnlySpan<int> secondEdgeVertexPairs,
 129        out FixedContactAnchors contact)
 130    {
 7131        WideRationalBasis3d firstBasis = new(firstRotation);
 7132        WideRationalBasis3d secondBasis = new(secondRotation);
 7133        var best = default(WidePointSpanPenetration);
 134
 7135        if (!TryKeepHullFaceAxes(
 7136                firstLocalPoints,
 7137                firstTriangleVertexIndices,
 7138                firstBasis,
 7139                firstOrigin,
 7140                firstBasis,
 7141                firstLocalPoints,
 7142                secondOrigin,
 7143                secondBasis,
 7144                secondLocalPoints,
 7145                ref best)
 7146            || !TryKeepHullFaceAxes(
 7147                secondLocalPoints,
 7148                secondTriangleVertexIndices,
 7149                secondBasis,
 7150                firstOrigin,
 7151                firstBasis,
 7152                firstLocalPoints,
 7153                secondOrigin,
 7154                secondBasis,
 7155                secondLocalPoints,
 7156                ref best))
 157        {
 2158            contact = default;
 2159            return false;
 160        }
 161
 5162        for (int firstIndex = 0;
 45163            firstIndex < firstEdgeVertexPairs.Length;
 40164            firstIndex += 2)
 165        {
 41166            WideAxis3 firstEdge = GetHullEdge(
 41167                firstBasis,
 41168                firstLocalPoints[firstEdgeVertexPairs[firstIndex]],
 41169                firstLocalPoints[firstEdgeVertexPairs[firstIndex + 1]]);
 41170            for (int secondIndex = 0;
 494171                secondIndex < secondEdgeVertexPairs.Length;
 453172                secondIndex += 2)
 173            {
 454174                WideAxis3 secondEdge = GetHullEdge(
 454175                    secondBasis,
 454176                    secondLocalPoints[secondEdgeVertexPairs[secondIndex]],
 454177                    secondLocalPoints[secondEdgeVertexPairs[secondIndex + 1]]);
 454178                if (!TryKeepHullPairAxis(
 454179                        WideAxis3.Cross(firstEdge, secondEdge),
 454180                        firstOrigin,
 454181                        firstBasis,
 454182                        firstLocalPoints,
 454183                        secondOrigin,
 454184                        secondBasis,
 454185                        secondLocalPoints,
 454186                        ref best))
 187                {
 1188                    contact = default;
 1189                    return false;
 190                }
 191            }
 192        }
 193
 4194        if (!best.HasValue)
 195        {
 1196            contact = default;
 1197            return false;
 198        }
 199
 3200        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 3201        Vector3d normal = WideNormalization.GetNormalized(
 3202            Signed576.ExtendValue(orientedAxis.X),
 3203            Signed576.ExtendValue(orientedAxis.Y),
 3204            Signed576.ExtendValue(orientedAxis.Z));
 3205        Vector3d firstLocalPoint = GetHullSupportLocalPoint(
 3206            firstBasis,
 3207            firstLocalPoints,
 3208            orientedAxis,
 3209            maximize: true);
 3210        Vector3d secondLocalPoint = GetHullSupportLocalPoint(
 3211            secondBasis,
 3212            secondLocalPoints,
 3213            orientedAxis,
 3214            maximize: false);
 3215        Fixed64 depth = best.GetRoundedDepth(out bool depthIsClamped);
 3216        contact = new FixedContactAnchors(
 3217            new FixedPointAnchor(
 3218                firstOrigin,
 3219                firstRotation,
 3220                firstLocalPoint),
 3221            new FixedPointAnchor(
 3222                secondOrigin,
 3223                secondRotation,
 3224                secondLocalPoint),
 3225            normal,
 3226            depth,
 3227            depthIsClamped);
 3228        return true;
 229    }
 230
 231    private static bool TryKeepHullFaceAxes(
 232        ReadOnlySpan<Vector3d> axisSourcePoints,
 233        ReadOnlySpan<int> axisSourceTriangles,
 234        in WideRationalBasis3d axisBasis,
 235        Vector3d firstOrigin,
 236        in WideRationalBasis3d firstBasis,
 237        ReadOnlySpan<Vector3d> firstPoints,
 238        Vector3d secondOrigin,
 239        in WideRationalBasis3d secondBasis,
 240        ReadOnlySpan<Vector3d> secondPoints,
 241        ref WidePointSpanPenetration best)
 242    {
 244243        for (int index = 0; index < axisSourceTriangles.Length; index += 3)
 244        {
 112245            Vector3d first = axisSourcePoints[axisSourceTriangles[index]];
 112246            Vector3d second = axisSourcePoints[axisSourceTriangles[index + 1]];
 112247            Vector3d third = axisSourcePoints[axisSourceTriangles[index + 2]];
 112248            WideGeometry.GetDifferenceCrossProduct3D(
 112249                second.X,
 112250                first.X,
 112251                second.Y,
 112252                first.Y,
 112253                second.Z,
 112254                first.Z,
 112255                third.X,
 112256                first.X,
 112257                third.Y,
 112258                first.Y,
 112259                third.Z,
 112260                first.Z,
 112261                out Signed192 normalX,
 112262                out Signed192 normalY,
 112263                out Signed192 normalZ);
 112264            if (!TryKeepHullPairAxis(
 112265                    WideRigidProjection.TransformLocalAxis(
 112266                        axisBasis,
 112267                        normalX,
 112268                        normalY,
 112269                        normalZ),
 112270                    firstOrigin,
 112271                    firstBasis,
 112272                    firstPoints,
 112273                    secondOrigin,
 112274                    secondBasis,
 112275                    secondPoints,
 112276                    ref best))
 277            {
 2278                return false;
 279            }
 280        }
 281
 10282        return true;
 283    }
 284
 285    private static bool TryKeepHullPairAxis(
 286        in WideAxis3 axis,
 287        Vector3d firstOrigin,
 288        in WideRationalBasis3d firstBasis,
 289        ReadOnlySpan<Vector3d> firstPoints,
 290        Vector3d secondOrigin,
 291        in WideRationalBasis3d secondBasis,
 292        ReadOnlySpan<Vector3d> secondPoints,
 293        ref WidePointSpanPenetration best)
 294    {
 566295        if (axis.IsZero)
 155296            return true;
 297
 411298        GetHullProjectionInterval(
 411299            firstPoints,
 411300            firstBasis,
 411301            axis,
 411302            secondBasis.Denominator,
 411303            out Signed576 firstMinimum,
 411304            out Signed576 firstMaximum);
 411305        GetHullProjectionInterval(
 411306            secondPoints,
 411307            secondBasis,
 411308            axis,
 411309            firstBasis.Denominator,
 411310            out Signed576 secondMinimum,
 411311            out Signed576 secondMaximum);
 411312        Signed576 originProjection = WideRigidProjection.GetWorldOriginDifferenceProjection(
 411313            secondOrigin,
 411314            firstOrigin,
 411315            axis);
 411316        Signed576 originCommon = WideArithmetic.MultiplySigned576(
 411317            WideArithmetic.MultiplySigned576(
 411318                originProjection,
 411319                secondBasis.Denominator),
 411320            firstBasis.Denominator);
 411321        secondMinimum = WideArithmetic.AddSigned576(
 411322            secondMinimum,
 411323            originCommon);
 411324        secondMaximum = WideArithmetic.AddSigned576(
 411325            secondMaximum,
 411326            originCommon);
 327
 411328        Signed576 pushFirstNegative = WideArithmetic.SubtractSigned576(
 411329            firstMaximum,
 411330            secondMinimum);
 411331        Signed576 pushFirstPositive = WideArithmetic.SubtractSigned576(
 411332            secondMaximum,
 411333            firstMinimum);
 411334        if (pushFirstNegative.Sign < 0 || pushFirstPositive.Sign < 0)
 3335            return false;
 336
 408337        bool negate = CompareSigned(
 408338            pushFirstPositive,
 408339            pushFirstNegative) < 0;
 408340        Signed576 overlap = negate
 408341            ? pushFirstPositive
 408342            : pushFirstNegative;
 408343        Signed320 commonDenominator = WideArithmetic.MultiplySigned192(
 408344            firstBasis.Denominator,
 408345            secondBasis.Denominator);
 408346        Signed576 squaredAxisLength = axis.SquaredLength;
 408347        if (best.ShouldReplace(
 408348            overlap,
 408349            squaredAxisLength,
 408350            commonDenominator))
 351        {
 10352            best = new WidePointSpanPenetration(
 10353                axis,
 10354                negate,
 10355                overlap,
 10356                squaredAxisLength,
 10357                commonDenominator);
 358        }
 359
 408360        return true;
 361    }
 362
 363    private static void GetHullProjectionInterval(
 364        ReadOnlySpan<Vector3d> points,
 365        in WideRationalBasis3d basis,
 366        in WideAxis3 axis,
 367        Signed192 otherDenominator,
 368        out Signed576 minimum,
 369        out Signed576 maximum)
 370    {
 3655371        WideRigidProjection.GetLocalAxisProjections(
 3655372            axis,
 3655373            basis,
 3655374            out Signed576 localAxisX,
 3655375            out Signed576 localAxisY,
 3655376            out Signed576 localAxisZ);
 3655377        minimum = WideArithmetic.MultiplySigned576(
 3655378            WideRigidProjection.GetLocalOffsetProjection(
 3655379                points[0],
 3655380                localAxisX,
 3655381                localAxisY,
 3655382                localAxisZ),
 3655383            otherDenominator);
 3655384        maximum = minimum;
 30150385        for (int index = 1; index < points.Length; index++)
 386        {
 11420387            WideRigidProjection.IncludeProjection(
 11420388                WideArithmetic.MultiplySigned576(
 11420389                    WideRigidProjection.GetLocalOffsetProjection(
 11420390                        points[index],
 11420391                        localAxisX,
 11420392                        localAxisY,
 11420393                        localAxisZ),
 11420394                    otherDenominator),
 11420395                ref minimum,
 11420396                ref maximum);
 397        }
 3655398    }
 399
 400    private static WideAxis3 GetHullEdge(
 401        in WideRationalBasis3d basis,
 402        Vector3d start,
 403        Vector3d end) =>
 2053404        WideRigidProjection.TransformLocalAxis(
 2053405            basis,
 2053406            WideArithmetic.SubtractSigned192(Signed192.Raw(end.X), Signed192.Raw(start.X)),
 2053407            WideArithmetic.SubtractSigned192(Signed192.Raw(end.Y), Signed192.Raw(start.Y)),
 2053408            WideArithmetic.SubtractSigned192(Signed192.Raw(end.Z), Signed192.Raw(start.Z)));
 409
 410    private static Vector3d GetHullSupportLocalPoint(
 411        in WideRationalBasis3d basis,
 412        ReadOnlySpan<Vector3d> points,
 413        in WideAxis3 axis,
 414        bool maximize)
 415    {
 148416        WideRigidProjection.GetLocalAxisProjections(
 148417            axis,
 148418            basis,
 148419            out Signed576 localAxisX,
 148420            out Signed576 localAxisY,
 148421            out Signed576 localAxisZ);
 148422        Vector3d best = points[0];
 148423        Signed576 bestProjection = WideRigidProjection.GetLocalOffsetProjection(
 148424            best,
 148425            localAxisX,
 148426            localAxisY,
 148427            localAxisZ);
 1678428        for (int index = 1; index < points.Length; index++)
 429        {
 691430            Vector3d candidate = points[index];
 691431            Signed576 projection = WideRigidProjection.GetLocalOffsetProjection(
 691432                candidate,
 691433                localAxisX,
 691434                localAxisY,
 691435                localAxisZ);
 691436            int comparison = CompareSigned(projection, bestProjection);
 691437            if (maximize ? comparison > 0 : comparison < 0)
 438            {
 4439                best = candidate;
 4440                bestProjection = projection;
 441            }
 442        }
 443
 148444        return best;
 445    }
 446}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexPrism.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.ConvexPrism.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/// Contains exact oriented-box and convex-prism relation calculations.
 14/// </content>
 15internal static partial class WideOrientedBox
 16{
 17    #region Nested Types
 18
 19    private readonly struct RationalAxis3
 20    {
 21        internal readonly Signed192 X;
 22        internal readonly Signed192 Y;
 23        internal readonly Signed192 Z;
 24
 25        internal RationalAxis3(Signed192 x, Signed192 y, Signed192 z)
 26        {
 10227            X = x;
 10228            Y = y;
 10229            Z = z;
 10230        }
 31
 32        internal WideAxis3 ToWide() =>
 8333            new(
 8334                Signed320.ExtendValue(X),
 8335                Signed320.ExtendValue(Y),
 8336                Signed320.ExtendValue(Z));
 37    }
 38
 39    #endregion
 40
 41    internal static bool TryGetConvexPrismContact(
 42        Vector3d center,
 43        FixedQuaternion orientation,
 44        Vector3d halfExtents,
 45        Vector3d prismOrigin,
 46        Fixed64 prismRotation,
 47        ReadOnlySpan<Vector2d> prismLocalOffsets,
 48        Fixed64 prismHalfThickness,
 49        out FixedContactAnchors contact)
 50    {
 2451        WideRationalBasis3d basis = new(orientation);
 2452        var best = default(WidePointSpanPenetration);
 2453        WideAxis3 up = new(default, Signed320.One, default);
 2454        if (!TryKeepConvexPrismAxis(
 2455                up,
 2456                center,
 2457                halfExtents,
 2458                basis,
 2459                prismOrigin,
 2460                prismRotation,
 2461                prismLocalOffsets,
 2462                prismHalfThickness,
 2463                ref best))
 64        {
 165            contact = default;
 166            return false;
 67        }
 68
 2369        Span<RationalAxis3> boxAxes = stackalloc RationalAxis3[3]
 2370        {
 2371            new(basis.Xx, basis.Xy, basis.Xz),
 2372            new(basis.Yx, basis.Yy, basis.Yz),
 2373            new(basis.Zx, basis.Zy, basis.Zz),
 2374        };
 16075        for (int axisIndex = 0; axisIndex < boxAxes.Length; axisIndex++)
 76        {
 6177            WideAxis3 boxAxis = boxAxes[axisIndex].ToWide();
 6178            if (!TryKeepConvexPrismAxis(
 6179                    boxAxis,
 6180                    center,
 6181                    halfExtents,
 6182                    basis,
 6183                    prismOrigin,
 6184                    prismRotation,
 6185                    prismLocalOffsets,
 6186                    prismHalfThickness,
 6187                    ref best)
 6188                || !TryKeepConvexPrismAxis(
 6189                    CrossWithUp(boxAxis),
 6190                    center,
 6191                    halfExtents,
 6192                    basis,
 6193                    prismOrigin,
 6194                    prismRotation,
 6195                    prismLocalOffsets,
 6196                    prismHalfThickness,
 6197                    ref best))
 98            {
 499                contact = default;
 4100                return false;
 101            }
 102        }
 103
 170104        for (int edgeIndex = 0; edgeIndex < prismLocalOffsets.Length; edgeIndex++)
 105        {
 68106            Vector2d start = prismLocalOffsets[edgeIndex];
 68107            Vector2d end = prismLocalOffsets[
 68108                edgeIndex + 1 == prismLocalOffsets.Length ? 0 : edgeIndex + 1];
 68109            GetRotatedPlanarEdge(
 68110                prismRotation,
 68111                start,
 68112                end,
 68113                out Signed192 edgeX,
 68114                out Signed192 edgeZ);
 68115            WideAxis3 faceAxis = new(
 68116                Signed320.ExtendValue(edgeZ),
 68117                default,
 68118                Signed320.ExtendValue(
 68119                    WideArithmetic.SubtractSigned192(default, edgeX)));
 68120            if (!TryKeepConvexPrismAxis(
 68121                    faceAxis,
 68122                    center,
 68123                    halfExtents,
 68124                    basis,
 68125                    prismOrigin,
 68126                    prismRotation,
 68127                    prismLocalOffsets,
 68128                    prismHalfThickness,
 68129                    ref best))
 130            {
 1131                contact = default;
 1132                return false;
 133            }
 134
 530135            for (int boxAxisIndex = 0; boxAxisIndex < boxAxes.Length; boxAxisIndex++)
 136            {
 199137                if (!TryKeepConvexPrismAxis(
 199138                        CrossWithPlanarEdge(
 199139                            boxAxes[boxAxisIndex],
 199140                            edgeX,
 199141                            edgeZ),
 199142                        center,
 199143                        halfExtents,
 199144                        basis,
 199145                        prismOrigin,
 199146                        prismRotation,
 199147                        prismLocalOffsets,
 199148                        prismHalfThickness,
 199149                        ref best))
 150                {
 1151                    contact = default;
 1152                    return false;
 153                }
 154            }
 155        }
 156
 17157        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 17158        Vector3d normal = WideNormalization.GetNormalized(
 17159            Signed576.ExtendValue(orientedAxis.X),
 17160            Signed576.ExtendValue(orientedAxis.Y),
 17161            Signed576.ExtendValue(orientedAxis.Z));
 17162        Vector3d localBoxPoint = GetLocalAxisSupportPoint(
 17163            basis,
 17164            halfExtents,
 17165            orientedAxis);
 17166        Vector3d prismOffset = GetPrismSupportOffset(
 17167            prismLocalOffsets,
 17168            prismHalfThickness,
 17169            prismRotation,
 17170            orientedAxis);
 17171        Fixed64 depth = best.GetRoundedDepth(out bool depthIsClamped);
 172
 17173        contact = new FixedContactAnchors(
 17174            new FixedPointAnchor(
 17175                center,
 17176                orientation,
 17177                localBoxPoint),
 17178            new FixedPointAnchor(
 17179                prismOrigin,
 17180                FixedQuaternion.FromAxisAngle(
 17181                    Vector3d.Up,
 17182                    -prismRotation),
 17183                prismOffset),
 17184            normal,
 17185            depth,
 17186            depthIsClamped);
 17187        return true;
 188    }
 189
 190    private static bool TryKeepConvexPrismAxis(
 191        WideAxis3 axis,
 192        Vector3d boxCenter,
 193        Vector3d halfExtents,
 194        WideRationalBasis3d basis,
 195        Vector3d prismOrigin,
 196        Fixed64 prismRotation,
 197        ReadOnlySpan<Vector2d> prismLocalOffsets,
 198        Fixed64 prismHalfThickness,
 199        ref WidePointSpanPenetration best)
 200    {
 410201        if (axis.IsZero)
 49202            return true;
 203
 361204        Signed576 boxRadius = WideArithmetic.MultiplySigned576(
 361205            GetBoxProjectionRadiusNumerator(
 361206                axis,
 361207                halfExtents,
 361208                basis),
 361209            Signed192.One);
 361210        Signed576 originProjection = WideArithmetic.MultiplySigned576(
 361211            WideRigidProjection.GetWorldOriginDifferenceProjection(
 361212                prismOrigin,
 361213                boxCenter,
 361214                axis),
 361215            Signed192.One);
 361216        Signed576 minimumPlanar = default;
 361217        Signed576 maximumPlanar = default;
 361218        bool hasPlanarProjection = false;
 3508219        for (int index = 0; index < prismLocalOffsets.Length; index++)
 220        {
 1393221            Signed576 projection = GetRotatedPlanarOffsetProjection(
 1393222                prismLocalOffsets[index],
 1393223                prismRotation,
 1393224                axis);
 1393225            if (!hasPlanarProjection)
 226            {
 361227                minimumPlanar = projection;
 361228                maximumPlanar = projection;
 361229                hasPlanarProjection = true;
 230            }
 231            else
 232            {
 1032233                if (CompareSigned(projection, minimumPlanar) < 0)
 118234                    minimumPlanar = projection;
 1032235                if (CompareSigned(projection, maximumPlanar) > 0)
 153236                    maximumPlanar = projection;
 237            }
 238        }
 239
 361240        Signed576 verticalRadius = WideArithmetic.MultiplySigned576(
 361241            WideArithmetic.MultiplySigned576(
 361242                Signed576.ExtendValue(GetMagnitude(axis.Y)),
 361243                Signed192.Raw(prismHalfThickness)),
 361244            Signed192.One);
 361245        Signed576 minimum = WideArithmetic.SubtractSigned576(
 361246            WideArithmetic.AddSigned576(originProjection, minimumPlanar),
 361247            verticalRadius);
 361248        Signed576 maximum = WideArithmetic.AddSigned576(
 361249            WideArithmetic.AddSigned576(originProjection, maximumPlanar),
 361250            verticalRadius);
 361251        minimum = WideArithmetic.MultiplySigned576(minimum, basis.Denominator);
 361252        maximum = WideArithmetic.MultiplySigned576(maximum, basis.Denominator);
 361253        Signed576 pushBoxNegative = WideArithmetic.SubtractSigned576(
 361254            boxRadius,
 361255            minimum);
 361256        Signed576 pushBoxPositive = WideArithmetic.AddSigned576(
 361257            maximum,
 361258            boxRadius);
 361259        if (pushBoxNegative.Sign < 0 || pushBoxPositive.Sign < 0)
 7260            return false;
 261
 354262        int pushComparison = CompareSigned(
 354263            pushBoxNegative,
 354264            pushBoxPositive);
 354265        bool negate = pushComparison > 0
 354266            || (pushComparison == 0
 354267                && ShouldNegateCanonicalAxis(axis));
 354268        Signed576 overlap = pushComparison <= 0
 354269            ? pushBoxNegative
 354270            : pushBoxPositive;
 354271        Signed320 commonDenominator =
 354272            WideArithmetic.MultiplySigned192(
 354273                basis.Denominator,
 354274                Signed192.One);
 354275        Signed576 squaredAxisLength = axis.SquaredLength;
 354276        if (best.ShouldReplace(
 354277            overlap,
 354278            squaredAxisLength,
 354279            commonDenominator))
 280        {
 47281            best = new WidePointSpanPenetration(
 47282                axis,
 47283                negate,
 47284                overlap,
 47285                squaredAxisLength,
 47286                commonDenominator);
 287        }
 288
 354289        return true;
 290    }
 291
 292    private static Signed576 GetRotatedPlanarOffsetProjection(
 293        Vector2d offset,
 294        Fixed64 rotation,
 295        WideAxis3 axis)
 296    {
 8958297        WideConvex2dRelations.GetRelativePointNumerators(
 8958298            Vector2d.Zero,
 8958299            rotation,
 8958300            offset,
 8958301            Vector2d.Zero,
 8958302            out Signed192 x,
 8958303            out Signed192 z);
 8958304        return WideArithmetic.AddSigned576(
 8958305            WideArithmetic.MultiplySigned320(
 8958306                Signed320.ExtendValue(x),
 8958307                axis.X),
 8958308            WideArithmetic.MultiplySigned320(
 8958309                Signed320.ExtendValue(z),
 8958310                axis.Z));
 311    }
 312
 313    private static void GetRotatedPlanarEdge(
 314        Fixed64 rotation,
 315        Vector2d start,
 316        Vector2d end,
 317        out Signed192 x,
 318        out Signed192 z)
 319    {
 346320        WideConvex2dRelations.GetRelativePointNumerators(
 346321            Vector2d.Zero,
 346322            rotation,
 346323            end,
 346324            Vector2d.Zero,
 346325            out Signed192 endX,
 346326            out Signed192 endZ);
 346327        WideConvex2dRelations.GetRelativePointNumerators(
 346328            Vector2d.Zero,
 346329            rotation,
 346330            start,
 346331            Vector2d.Zero,
 346332            out Signed192 startX,
 346333            out Signed192 startZ);
 346334        x = WideArithmetic.SubtractSigned192(endX, startX);
 346335        z = WideArithmetic.SubtractSigned192(endZ, startZ);
 346336    }
 337
 338    private static Vector3d GetLocalAxisSupportPoint(
 339        WideRationalBasis3d basis,
 340        Vector3d halfExtents,
 341        WideAxis3 axis)
 342    {
 1042343        return new Vector3d(
 1042344            WideRigidProjection.GetBasisAxisProjection(axis, basis.Xx, basis.Xy, basis.Xz).Sign > 0
 1042345                ? halfExtents.X
 1042346                : -halfExtents.X,
 1042347            WideRigidProjection.GetBasisAxisProjection(axis, basis.Yx, basis.Yy, basis.Yz).Sign > 0
 1042348                ? halfExtents.Y
 1042349                : -halfExtents.Y,
 1042350            WideRigidProjection.GetBasisAxisProjection(axis, basis.Zx, basis.Zy, basis.Zz).Sign > 0
 1042351                ? halfExtents.Z
 1042352                : -halfExtents.Z);
 353    }
 354
 355    private static Vector3d GetPrismSupportOffset(
 356        ReadOnlySpan<Vector2d> offsets,
 357        Fixed64 halfThickness,
 358        Fixed64 rotation,
 359        WideAxis3 boxToPrismAxis)
 360    {
 86361        int bestIndex = 0;
 86362        Signed576 bestProjection = GetRotatedPlanarOffsetProjection(
 86363            offsets[0],
 86364            rotation,
 86365            boxToPrismAxis);
 682366        for (int index = 1; index < offsets.Length; index++)
 367        {
 255368            Signed576 projection = GetRotatedPlanarOffsetProjection(
 255369                offsets[index],
 255370                rotation,
 255371                boxToPrismAxis);
 255372            int projectionComparison = CompareSigned(
 255373                projection,
 255374                bestProjection);
 255375            if (projectionComparison < 0)
 376            {
 5377                bestProjection = projection;
 5378                bestIndex = index;
 379            }
 250380            else if (projectionComparison == 0
 250381                && IsLexicographicallyEarlier(offsets[index], offsets[bestIndex]))
 382            {
 3383                bestIndex = index;
 384            }
 385        }
 386
 86387        Vector2d planar = offsets[bestIndex];
 86388        return new Vector3d(
 86389            planar.X,
 86390            boxToPrismAxis.Y.Sign >= 0
 86391                ? -halfThickness
 86392                : halfThickness,
 86393            planar.Y);
 394    }
 395
 396    private static bool ShouldNegateCanonicalAxis(WideAxis3 axis)
 397    {
 276398        if (!axis.X.IsZero)
 77399            return axis.X.Sign < 0;
 199400        if (!axis.Y.IsZero)
 129401            return axis.Y.Sign < 0;
 70402        return axis.Z.Sign < 0;
 403    }
 404
 405    private static bool IsLexicographicallyEarlier(Vector2d candidate, Vector2d current) =>
 95406        candidate.X < current.X
 95407        || (candidate.X == current.X && candidate.Y < current.Y);
 408
 409    private static WideAxis3 CrossWithUp(WideAxis3 axis) =>
 1195410        new(
 1195411            WideArithmetic.SubtractSigned320(default, axis.Z),
 1195412            default,
 1195413            axis.X);
 414
 415    private static WideAxis3 CrossWithPlanarEdge(
 416        RationalAxis3 axis,
 417        Signed192 edgeX,
 418        Signed192 edgeZ) =>
 219419        new(
 219420            WideArithmetic.MultiplySigned192(axis.Y, edgeZ),
 219421            WideArithmetic.SubtractSigned320(
 219422                WideArithmetic.MultiplySigned192(axis.Z, edgeX),
 219423                WideArithmetic.MultiplySigned192(axis.X, edgeZ)),
 219424            WideArithmetic.SubtractSigned320(
 219425                default,
 219426                WideArithmetic.MultiplySigned192(axis.Y, edgeX)));
 427}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.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.Runtime.CompilerServices;
 9
 10namespace FixedMathSharp.Geometry;
 11
 12/// <summary>
 13/// Owns exact full-domain reducers for <see cref="FixedOrientedBox"/>.
 14/// </summary>
 15internal static partial class WideOrientedBox
 16{
 17    #region Nested Types
 18
 19    private readonly struct RadialPenetration
 20    {
 21        internal readonly WideAxis3 Axis;
 22        internal readonly bool Negate;
 23        internal readonly Fixed64 Depth;
 24        internal readonly bool DepthIsClamped;
 25        internal readonly Signed576 Rational;
 26        internal readonly Signed832 RadialNumerator;
 27        internal readonly Signed576 RadialDenominator;
 28        internal readonly Signed576 AxisSquared;
 29
 30        internal RadialPenetration(
 31            WideAxis3 axis,
 32            bool negate,
 33            Fixed64 depth,
 34            bool depthIsClamped,
 35            Signed576 rational,
 36            Signed832 radialNumerator,
 37            Signed576 radialDenominator,
 38            Signed576 axisSquared)
 39        {
 35840            Axis = axis;
 35841            Negate = negate;
 35842            Depth = depth;
 35843            DepthIsClamped = depthIsClamped;
 35844            Rational = rational;
 35845            RadialNumerator = radialNumerator;
 35846            RadialDenominator = radialDenominator;
 35847            AxisSquared = axisSquared;
 35848            HasValue = true;
 35849        }
 50
 51        internal bool HasValue { get; }
 52    }
 53
 54    #endregion
 55
 56    internal static void GetAxes(
 57        FixedQuaternion orientation,
 58        out Vector3d axisX,
 59        out Vector3d axisY,
 60        out Vector3d axisZ)
 61    {
 52862        WideRationalBasis3d basis = new(orientation);
 52863        axisX = GetAxis(basis.Xx, basis.Xy, basis.Xz, basis.Denominator, false);
 52864        axisY = GetAxis(basis.Yx, basis.Yy, basis.Yz, basis.Denominator, false);
 52865        axisZ = GetAxis(basis.Zx, basis.Zy, basis.Zz, basis.Denominator, false);
 52866    }
 67
 68    internal static Vector3d GetLocalSupportPoint(
 69        Vector3d worldDirection,
 70        FixedQuaternion orientation,
 71        Vector3d halfExtents)
 72    {
 74273        WideRationalBasis3d basis = new(orientation);
 74274        GetDirectionProjections(
 74275            worldDirection,
 74276            basis,
 74277            out Signed320 x,
 74278            out Signed320 y,
 74279            out Signed320 z);
 74280        return new Vector3d(
 74281            x.Sign > 0 ? halfExtents.X : -halfExtents.X,
 74282            y.Sign > 0 ? halfExtents.Y : -halfExtents.Y,
 74283            z.Sign > 0 ? halfExtents.Z : -halfExtents.Z);
 84    }
 85
 86    internal static FixedBoundBox GetBoundsClippedToDomain(
 87        Vector3d center,
 88        FixedQuaternion orientation,
 89        Vector3d halfExtents)
 90    {
 51691        WideRationalBasis3d basis = new(orientation);
 51692        Signed576 denominator = ToSigned576(basis.Denominator);
 51693        Signed320 minimumNumerator = WideArithmetic.MultiplySigned192(
 51694            Signed192.Signed(long.MinValue),
 51695            basis.Denominator);
 51696        Signed320 maximumNumerator = WideArithmetic.MultiplySigned192(
 51697            Signed192.Signed(long.MaxValue),
 51698            basis.Denominator);
 51699        Signed320 xExtent = GetExtentNumerator(
 516100            basis.Xx,
 516101            basis.Yx,
 516102            basis.Zx,
 516103            halfExtents);
 516104        Signed320 yExtent = GetExtentNumerator(
 516105            basis.Xy,
 516106            basis.Yy,
 516107            basis.Zy,
 516108            halfExtents);
 516109        Signed320 zExtent = GetExtentNumerator(
 516110            basis.Xz,
 516111            basis.Yz,
 516112            basis.Zz,
 516113            halfExtents);
 516114        return FixedBoundBox.FromMinMax(
 516115            new Vector3d(
 516116                GetClippedEndpoint(
 516117                    center.X, xExtent, basis.Denominator, denominator,
 516118                    minimumNumerator, maximumNumerator, true),
 516119                GetClippedEndpoint(
 516120                    center.Y, yExtent, basis.Denominator, denominator,
 516121                    minimumNumerator, maximumNumerator, true),
 516122                GetClippedEndpoint(
 516123                    center.Z, zExtent, basis.Denominator, denominator,
 516124                    minimumNumerator, maximumNumerator, true)),
 516125            new Vector3d(
 516126                GetClippedEndpoint(
 516127                    center.X, xExtent, basis.Denominator, denominator,
 516128                    minimumNumerator, maximumNumerator, false),
 516129                GetClippedEndpoint(
 516130                    center.Y, yExtent, basis.Denominator, denominator,
 516131                    minimumNumerator, maximumNumerator, false),
 516132                GetClippedEndpoint(
 516133                    center.Z, zExtent, basis.Denominator, denominator,
 516134                    minimumNumerator, maximumNumerator, false)));
 135    }
 136
 137    internal static bool Contains(
 138        Vector3d point,
 139        Vector3d center,
 140        FixedQuaternion orientation,
 141        Vector3d halfExtents)
 142    {
 2702143        WideRationalBasis3d basis = new(orientation);
 2702144        GetPointProjections(
 2702145            point,
 2702146            center,
 2702147            basis,
 2702148            out Signed320 x,
 2702149            out Signed320 y,
 2702150            out Signed320 z);
 2702151        return IsWithinExtent(x, halfExtents.X, basis.Denominator)
 2702152            && IsWithinExtent(y, halfExtents.Y, basis.Denominator)
 2702153            && IsWithinExtent(z, halfExtents.Z, basis.Denominator);
 154    }
 155
 156    internal static FixedPointAnchor GetClosestPointAnchor(
 157        Vector3d point,
 158        Vector3d center,
 159        FixedQuaternion orientation,
 160        Vector3d halfExtents)
 161    {
 523162        WideRationalBasis3d basis = new(orientation);
 523163        GetPointProjections(
 523164            point,
 523165            center,
 523166            basis,
 523167            out Signed320 x,
 523168            out Signed320 y,
 523169            out Signed320 z);
 523170        Signed320 xExtent = GetExtentNumerator(halfExtents.X, basis.Denominator);
 523171        Signed320 yExtent = GetExtentNumerator(halfExtents.Y, basis.Denominator);
 523172        Signed320 zExtent = GetExtentNumerator(halfExtents.Z, basis.Denominator);
 523173        bool outsideX = WideArithmetic.CompareMagnitude(x, xExtent) > 0;
 523174        bool outsideY = WideArithmetic.CompareMagnitude(y, yExtent) > 0;
 523175        bool outsideZ = WideArithmetic.CompareMagnitude(z, zExtent) > 0;
 176
 523177        Signed320 localX = GetClampedNumerator(x, xExtent, outsideX);
 523178        Signed320 localY = GetClampedNumerator(y, yExtent, outsideY);
 523179        Signed320 localZ = GetClampedNumerator(z, zExtent, outsideZ);
 523180        if (!(outsideX || outsideY || outsideZ))
 181        {
 9182            Signed320 xClearance = WideArithmetic.SubtractSigned320(xExtent, GetMagnitude(x));
 9183            Signed320 yClearance = WideArithmetic.SubtractSigned320(yExtent, GetMagnitude(y));
 9184            Signed320 zClearance = WideArithmetic.SubtractSigned320(zExtent, GetMagnitude(z));
 9185            if (WideArithmetic.CompareMagnitude(xClearance, yClearance) <= 0
 9186                && WideArithmetic.CompareMagnitude(xClearance, zClearance) <= 0)
 187            {
 4188                localX = GetSignedExtent(x, xExtent);
 189            }
 5190            else if (WideArithmetic.CompareMagnitude(yClearance, zClearance) <= 0)
 191            {
 3192                localY = GetSignedExtent(y, yExtent);
 193            }
 194            else
 195            {
 2196                localZ = GetSignedExtent(z, zExtent);
 197            }
 198        }
 199
 523200        return new FixedPointAnchor(
 523201            center,
 523202            orientation,
 523203            GetRationalLocalPoint(
 523204                basis,
 523205                localX,
 523206                localY,
 523207                localZ));
 208    }
 209
 210    internal static Vector3d GetNearestFaceNormal(
 211        Vector3d point,
 212        Vector3d center,
 213        FixedQuaternion orientation,
 214        Vector3d halfExtents)
 215    {
 526216        WideRationalBasis3d basis = new(orientation);
 526217        GetPointProjections(
 526218            point,
 526219            center,
 526220            basis,
 526221            out Signed320 x,
 526222            out Signed320 y,
 526223            out Signed320 z);
 526224        Signed320 xDistance = WideArithmetic.SubtractSigned320(
 526225            GetExtentNumerator(halfExtents.X, basis.Denominator),
 526226            GetMagnitude(x));
 526227        Signed320 yDistance = WideArithmetic.SubtractSigned320(
 526228            GetExtentNumerator(halfExtents.Y, basis.Denominator),
 526229            GetMagnitude(y));
 526230        Signed320 zDistance = WideArithmetic.SubtractSigned320(
 526231            GetExtentNumerator(halfExtents.Z, basis.Denominator),
 526232            GetMagnitude(z));
 233
 526234        if (xDistance.Sign < 0)
 515235            return GetAxis(basis.Xx, basis.Xy, basis.Xz, basis.Denominator, x.Sign < 0);
 11236        if (yDistance.Sign < 0)
 2237            return GetAxis(basis.Yx, basis.Yy, basis.Yz, basis.Denominator, y.Sign < 0);
 9238        if (zDistance.Sign < 0)
 2239            return GetAxis(basis.Zx, basis.Zy, basis.Zz, basis.Denominator, z.Sign < 0);
 7240        if (WideArithmetic.CompareMagnitude(xDistance, yDistance) <= 0
 7241            && WideArithmetic.CompareMagnitude(xDistance, zDistance) <= 0)
 242        {
 2243            return GetAxis(basis.Xx, basis.Xy, basis.Xz, basis.Denominator, x.Sign < 0);
 244        }
 5245        if (WideArithmetic.CompareMagnitude(yDistance, zDistance) <= 0)
 2246            return GetAxis(basis.Yx, basis.Yy, basis.Yz, basis.Denominator, y.Sign < 0);
 3247        return GetAxis(basis.Zx, basis.Zy, basis.Zz, basis.Denominator, z.Sign < 0);
 248    }
 249
 250    internal static bool TryMaterializeLocalPoint(
 251        Vector3d center,
 252        FixedQuaternion orientation,
 253        Vector3d localPoint,
 254        out Vector3d worldPoint)
 255    {
 679256        WideRationalBasis3d basis = new(orientation);
 679257        Signed576 denominator = ToSigned576(basis.Denominator);
 679258        bool representable = TryMaterializeCoordinate(
 679259            center.X,
 679260            basis.Xx,
 679261            basis.Yx,
 679262            basis.Zx,
 679263            basis.Denominator,
 679264            denominator,
 679265            localPoint,
 679266            out Fixed64 x)
 679267            & TryMaterializeCoordinate(
 679268                center.Y,
 679269                basis.Xy,
 679270                basis.Yy,
 679271                basis.Zy,
 679272                basis.Denominator,
 679273                denominator,
 679274                localPoint,
 679275                out Fixed64 y)
 679276            & TryMaterializeCoordinate(
 679277                center.Z,
 679278                basis.Xz,
 679279                basis.Yz,
 679280                basis.Zz,
 679281                basis.Denominator,
 679282                denominator,
 679283                localPoint,
 679284                out Fixed64 z);
 679285        if (!representable)
 286        {
 8287            worldPoint = default;
 8288            return false;
 289        }
 290
 671291        worldPoint = new Vector3d(x, y, z);
 671292        return true;
 293    }
 294
 295    internal static bool TryMaterializeLocalPoint(
 296        Vector3d firstOrigin,
 297        Vector3d secondOrigin,
 298        FixedQuaternion orientation,
 299        Vector3d localPoint,
 300        out Vector3d worldPoint)
 301    {
 69302        WideRationalBasis3d basis = new(orientation);
 69303        Signed576 denominator = ToSigned576(basis.Denominator);
 69304        bool representable = TryMaterializeCoordinate(
 69305                firstOrigin.X,
 69306                secondOrigin.X,
 69307                basis.Xx,
 69308                basis.Yx,
 69309                basis.Zx,
 69310                basis.Denominator,
 69311                denominator,
 69312                localPoint,
 69313                out Fixed64 x)
 69314            & TryMaterializeCoordinate(
 69315                firstOrigin.Y,
 69316                secondOrigin.Y,
 69317                basis.Xy,
 69318                basis.Yy,
 69319                basis.Zy,
 69320                basis.Denominator,
 69321                denominator,
 69322                localPoint,
 69323                out Fixed64 y)
 69324            & TryMaterializeCoordinate(
 69325                firstOrigin.Z,
 69326                secondOrigin.Z,
 69327                basis.Xz,
 69328                basis.Yz,
 69329                basis.Zz,
 69330                basis.Denominator,
 69331                denominator,
 69332                localPoint,
 69333                out Fixed64 z);
 69334        if (!representable)
 335        {
 1336            worldPoint = default;
 1337            return false;
 338        }
 339
 68340        worldPoint = new Vector3d(x, y, z);
 68341        return true;
 342    }
 343
 344    internal static bool TryTransformLocalOffset(
 345        FixedQuaternion orientation,
 346        Vector3d localOffset,
 347        out Vector3d worldOffset) =>
 112348        TryMaterializeLocalPoint(
 112349            Vector3d.Zero,
 112350            orientation,
 112351            localOffset,
 112352            out worldOffset);
 353
 354    internal static bool TryGetRelativeOffset(
 355        FixedQuaternion orientation,
 356        Vector3d firstOrigin,
 357        Vector3d firstOffset,
 358        Vector3d secondOrigin,
 359        Vector3d secondLocalPoint,
 360        out Vector3d result)
 361    {
 35362        WideRationalBasis3d basis = new(orientation);
 35363        Signed576 denominator = ToSigned576(basis.Denominator);
 35364        bool representable = TryGetRelativeOffsetCoordinate(
 35365                firstOrigin.X,
 35366                firstOffset.X,
 35367                secondOrigin.X,
 35368                basis.Xx,
 35369                basis.Yx,
 35370                basis.Zx,
 35371                basis.Denominator,
 35372                denominator,
 35373                secondLocalPoint,
 35374                out Fixed64 x)
 35375            & TryGetRelativeOffsetCoordinate(
 35376                firstOrigin.Y,
 35377                firstOffset.Y,
 35378                secondOrigin.Y,
 35379                basis.Xy,
 35380                basis.Yy,
 35381                basis.Zy,
 35382                basis.Denominator,
 35383                denominator,
 35384                secondLocalPoint,
 35385                out Fixed64 y)
 35386            & TryGetRelativeOffsetCoordinate(
 35387                firstOrigin.Z,
 35388                firstOffset.Z,
 35389                secondOrigin.Z,
 35390                basis.Xz,
 35391                basis.Yz,
 35392                basis.Zz,
 35393                basis.Denominator,
 35394                denominator,
 35395                secondLocalPoint,
 35396                out Fixed64 z);
 35397        if (!representable)
 398        {
 1399            result = default;
 1400            return false;
 401        }
 402
 34403        result = new Vector3d(x, y, z);
 34404        return true;
 405    }
 406
 407    internal static bool TryGetSupportOffset(
 408        Vector3d worldDirection,
 409        FixedQuaternion orientation,
 410        Vector3d halfExtents,
 411        out Vector3d centerOffset)
 412    {
 4413        WideRationalBasis3d basis = new(orientation);
 4414        Vector3d localSupport = GetLocalSupportPoint(
 4415            worldDirection,
 4416            orientation,
 4417            halfExtents);
 4418        return TryMaterializeRationalOffset(
 4419            basis,
 4420            localSupport,
 4421            out centerOffset);
 422    }
 423
 424    internal static bool TryGetSupportDifference(
 425        Vector3d center,
 426        FixedQuaternion orientation,
 427        Vector3d halfExtents,
 428        Vector3d otherOrigin,
 429        Vector3d otherOriginSupportOffset,
 430        Vector3d worldDirection,
 431        out Vector3d difference)
 432    {
 3433        WideRationalBasis3d basis = new(orientation);
 3434        Vector3d localSupport = GetLocalSupportPoint(
 3435            worldDirection,
 3436            orientation,
 3437            halfExtents);
 3438        Signed576 denominator = ToSigned576(basis.Denominator);
 3439        bool representable = TryMaterializeSupportDifferenceCoordinate(
 3440            center.X,
 3441            otherOrigin.X,
 3442            otherOriginSupportOffset.X,
 3443            basis.Xx,
 3444            basis.Yx,
 3445            basis.Zx,
 3446            basis.Denominator,
 3447            denominator,
 3448            localSupport,
 3449            out Fixed64 x)
 3450            & TryMaterializeSupportDifferenceCoordinate(
 3451                center.Y,
 3452                otherOrigin.Y,
 3453                otherOriginSupportOffset.Y,
 3454                basis.Xy,
 3455                basis.Yy,
 3456                basis.Zy,
 3457                basis.Denominator,
 3458                denominator,
 3459                localSupport,
 3460                out Fixed64 y)
 3461            & TryMaterializeSupportDifferenceCoordinate(
 3462                center.Z,
 3463                otherOrigin.Z,
 3464                otherOriginSupportOffset.Z,
 3465                basis.Xz,
 3466                basis.Yz,
 3467                basis.Zz,
 3468                basis.Denominator,
 3469                denominator,
 3470                localSupport,
 3471                out Fixed64 z);
 3472        if (!representable)
 473        {
 1474            difference = default;
 1475            return false;
 476        }
 477
 2478        difference = new Vector3d(x, y, z);
 2479        return true;
 480    }
 481
 482    internal static bool TryGetSupportDifference(
 483        Vector3d center,
 484        FixedQuaternion orientation,
 485        Vector3d halfExtents,
 486        Vector3d otherCenter,
 487        FixedQuaternion otherOrientation,
 488        Vector3d otherHalfExtents,
 489        Vector3d worldDirection,
 490        out Vector3d difference)
 491    {
 2492        WideRationalBasis3d basis = new(orientation);
 2493        WideRationalBasis3d otherBasis = new(otherOrientation);
 2494        Vector3d localSupport = GetLocalSupportPoint(
 2495            worldDirection,
 2496            orientation,
 2497            halfExtents);
 2498        Vector3d otherLocalSupport = GetLocalSupportPoint(
 2499            -worldDirection,
 2500            otherOrientation,
 2501            otherHalfExtents);
 2502        Signed320 denominator = WideArithmetic.MultiplySigned192(
 2503            basis.Denominator,
 2504            otherBasis.Denominator);
 2505        Signed576 denominatorWide = Signed576.ExtendValue(
 2506            denominator);
 2507        bool representable = TryMaterializeBoxSupportDifferenceCoordinate(
 2508                center.X,
 2509                otherCenter.X,
 2510                basis.Xx,
 2511                basis.Yx,
 2512                basis.Zx,
 2513                basis.Denominator,
 2514                localSupport,
 2515                otherBasis.Xx,
 2516                otherBasis.Yx,
 2517                otherBasis.Zx,
 2518                otherBasis.Denominator,
 2519                otherLocalSupport,
 2520                denominator,
 2521                denominatorWide,
 2522                out Fixed64 x)
 2523            & TryMaterializeBoxSupportDifferenceCoordinate(
 2524                center.Y,
 2525                otherCenter.Y,
 2526                basis.Xy,
 2527                basis.Yy,
 2528                basis.Zy,
 2529                basis.Denominator,
 2530                localSupport,
 2531                otherBasis.Xy,
 2532                otherBasis.Yy,
 2533                otherBasis.Zy,
 2534                otherBasis.Denominator,
 2535                otherLocalSupport,
 2536                denominator,
 2537                denominatorWide,
 2538                out Fixed64 y)
 2539            & TryMaterializeBoxSupportDifferenceCoordinate(
 2540                center.Z,
 2541                otherCenter.Z,
 2542                basis.Xz,
 2543                basis.Yz,
 2544                basis.Zz,
 2545                basis.Denominator,
 2546                localSupport,
 2547                otherBasis.Xz,
 2548                otherBasis.Yz,
 2549                otherBasis.Zz,
 2550                otherBasis.Denominator,
 2551                otherLocalSupport,
 2552                denominator,
 2553                denominatorWide,
 2554                out Fixed64 z);
 2555        if (!representable)
 556        {
 1557            difference = default;
 1558            return false;
 559        }
 560
 1561        difference = new Vector3d(x, y, z);
 1562        return true;
 563    }
 564
 565    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 566    private static void GetDirectionProjections(
 567        Vector3d direction,
 568        WideRationalBasis3d basis,
 569        out Signed320 x,
 570        out Signed320 y,
 571        out Signed320 z)
 572    {
 1769573        Signed192 directionX = Signed192.Raw(direction.X);
 1769574        Signed192 directionY = Signed192.Raw(direction.Y);
 1769575        Signed192 directionZ = Signed192.Raw(direction.Z);
 1769576        x = WideArithmetic.GetDotProduct3D(directionX, directionY, directionZ, basis.Xx, basis.Xy, basis.Xz);
 1769577        y = WideArithmetic.GetDotProduct3D(directionX, directionY, directionZ, basis.Yx, basis.Yy, basis.Yz);
 1769578        z = WideArithmetic.GetDotProduct3D(directionX, directionY, directionZ, basis.Zx, basis.Zy, basis.Zz);
 1769579    }
 580
 581    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 582    private static void GetPointProjections(
 583        Vector3d point,
 584        Vector3d center,
 585        WideRationalBasis3d basis,
 586        out Signed320 x,
 587        out Signed320 y,
 588        out Signed320 z)
 589    {
 8289590        Signed192 differenceX = WideArithmetic.SubtractSigned192(Signed192.Raw(point.X), Signed192.Raw(center.X));
 8289591        Signed192 differenceY = WideArithmetic.SubtractSigned192(Signed192.Raw(point.Y), Signed192.Raw(center.Y));
 8289592        Signed192 differenceZ = WideArithmetic.SubtractSigned192(Signed192.Raw(point.Z), Signed192.Raw(center.Z));
 8289593        x = WideArithmetic.GetDotProduct3D(differenceX, differenceY, differenceZ, basis.Xx, basis.Xy, basis.Xz);
 8289594        y = WideArithmetic.GetDotProduct3D(differenceX, differenceY, differenceZ, basis.Yx, basis.Yy, basis.Yz);
 8289595        z = WideArithmetic.GetDotProduct3D(differenceX, differenceY, differenceZ, basis.Zx, basis.Zy, basis.Zz);
 8289596    }
 597
 598    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 599    private static bool IsWithinExtent(
 600        Signed320 projection,
 601        Fixed64 extent,
 602        Signed192 denominator) =>
 4077603        WideArithmetic.CompareMagnitude(
 4077604            projection,
 4077605            GetExtentNumerator(extent, denominator)) <= 0;
 606
 607    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 608    private static Signed320 GetClampedNumerator(
 609        Signed320 projection,
 610        Signed320 extent,
 611        bool outside) =>
 1626612        outside ? GetSignedExtent(projection, extent) : projection;
 613
 614    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 615    private static Signed320 GetSignedExtent(Signed320 projection, Signed320 extent) =>
 1557616        projection.Sign < 0
 1557617            ? WideArithmetic.SubtractSigned320(default, extent)
 1557618            : extent;
 619
 620    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 621    private static Signed320 GetExtentNumerator(Fixed64 extent, Signed192 denominator) =>
 10494622        WideArithmetic.MultiplySigned192(Signed192.Raw(extent), denominator);
 623
 624    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 625    private static Signed576 GetMagnitude(Signed576 value) =>
 314013626        value.Sign < 0
 314013627            ? WideArithmetic.SubtractSigned576(default, value)
 314013628            : value;
 629
 630    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 631    private static Signed320 GetMagnitude(Signed320 value) =>
 31263632        value.Sign < 0
 31263633            ? WideArithmetic.SubtractSigned320(default, value)
 31263634            : value;
 635
 636    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 637    private static Signed192 GetMagnitude(Signed192 value) =>
 5196638        value.Sign < 0
 5196639            ? WideArithmetic.SubtractSigned192(default, value)
 5196640            : value;
 641
 642    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 643    private static Signed320 GetExtentNumerator(
 644        Signed192 axisX,
 645        Signed192 axisY,
 646        Signed192 axisZ,
 647        Vector3d halfExtents) =>
 1624648        WideArithmetic.AddSigned320(
 1624649            WideArithmetic.AddSigned320(
 1624650                WideArithmetic.MultiplySigned192(GetMagnitude(axisX), Signed192.Raw(halfExtents.X)),
 1624651                WideArithmetic.MultiplySigned192(GetMagnitude(axisY), Signed192.Raw(halfExtents.Y))),
 1624652            WideArithmetic.MultiplySigned192(GetMagnitude(axisZ), Signed192.Raw(halfExtents.Z)));
 653
 654    private static Fixed64 GetClippedEndpoint(
 655        Fixed64 center,
 656        Signed320 extentNumerator,
 657        Signed192 denominator,
 658        Signed576 denominatorWide,
 659        Signed320 minimumNumerator,
 660        Signed320 maximumNumerator,
 661        bool minimum)
 662    {
 3096663        Signed320 centerNumerator = WideArithmetic.MultiplySigned192(Signed192.Raw(center), denominator);
 3096664        Signed320 endpointNumerator = minimum
 3096665            ? WideArithmetic.SubtractSigned320(centerNumerator, extentNumerator)
 3096666            : WideArithmetic.AddSigned320(centerNumerator, extentNumerator);
 3096667        if (CompareSigned(endpointNumerator, minimumNumerator) <= 0)
 3668            return Fixed64.MinValue;
 3093669        if (CompareSigned(endpointNumerator, maximumNumerator) >= 0)
 3670            return Fixed64.MaxValue;
 671
 3090672        _ = Fixed64.TryGetSignedRawRatio(
 3090673            Signed576.ExtendValue(endpointNumerator),
 3090674            denominatorWide,
 3090675            out Fixed64 endpoint);
 3090676        Signed320 roundedNumerator = WideArithmetic.MultiplySigned192(Signed192.Raw(endpoint), denominator);
 3090677        int comparison = CompareSigned(roundedNumerator, endpointNumerator);
 3090678        if (minimum && comparison > 0)
 1540679            return Fixed64.FromRaw(endpoint.m_rawValue - 1L);
 1550680        if (!minimum && comparison < 0)
 1540681            return Fixed64.FromRaw(endpoint.m_rawValue + 1L);
 10682        return endpoint;
 683    }
 684
 685    private static Vector3d GetAxis(
 686        Signed192 x,
 687        Signed192 y,
 688        Signed192 z,
 689        Signed192 denominator,
 690        bool negate)
 691    {
 2382692        if (negate)
 693        {
 9694            x = WideArithmetic.SubtractSigned192(default, x);
 9695            y = WideArithmetic.SubtractSigned192(default, y);
 9696            z = WideArithmetic.SubtractSigned192(default, z);
 697        }
 698
 2382699        Signed576 denominatorWide = ToSigned576(denominator);
 2382700        Signed192 scale = Signed192.Signed(1L << FixedMath.SHIFT_AMOUNT_I);
 2382701        _ = Fixed64.TryGetSignedRawRatio(
 2382702            Signed576.ExtendValue(WideArithmetic.MultiplySigned192(x, scale)),
 2382703            denominatorWide,
 2382704            out Fixed64 roundedX);
 2382705        _ = Fixed64.TryGetSignedRawRatio(
 2382706            Signed576.ExtendValue(WideArithmetic.MultiplySigned192(y, scale)),
 2382707            denominatorWide,
 2382708            out Fixed64 roundedY);
 2382709        _ = Fixed64.TryGetSignedRawRatio(
 2382710            Signed576.ExtendValue(WideArithmetic.MultiplySigned192(z, scale)),
 2382711            denominatorWide,
 2382712            out Fixed64 roundedZ);
 2382713        return new Vector3d(roundedX, roundedY, roundedZ);
 714    }
 715
 716    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 717    private static int CompareSigned(Signed320 left, Signed320 right)
 718    {
 34012719        int leftSign = left.Sign;
 34012720        int rightSign = right.Sign;
 34012721        if (leftSign != rightSign)
 17252722            return leftSign < rightSign ? -1 : 1;
 16760723        return WideArithmetic.SubtractSigned320(left, right).Sign;
 724    }
 725
 726    private static int CompareSigned(Signed576 left, Signed576 right) =>
 36071727        WideArithmetic.SubtractSigned576(left, right).Sign;
 728
 729    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 730    private static Signed576 ToSigned576(Signed192 value) =>
 5177731        Signed576.ExtendValue(Signed320.ExtendValue(value));
 732
 733}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Cylinder.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.Cylinder.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/// Cylinder-vs-oriented-box intersection and penetration logic, including
 14/// support types for tracking axis-aligned penetration depth and contact
 15/// features between a box face and a cylinder cap.
 16/// </content>
 17internal static partial class WideOrientedBox
 18{
 19    #region Nested Types
 20
 21    private readonly struct CylinderPenetration
 22    {
 23        internal readonly WideAxis3 Axis;
 24        internal readonly bool Negate;
 25        internal readonly Fixed64 Depth;
 26        internal readonly bool DepthIsClamped;
 27        internal readonly Signed576 Rational;
 28        internal readonly Signed832 RadialNumerator;
 29        internal readonly Signed576 RadialDenominator;
 30        internal readonly Signed576 SquaredAxisLength;
 31
 32        internal CylinderPenetration(
 33            WideAxis3 axis,
 34            bool negate,
 35            Fixed64 depth,
 36            bool depthIsClamped,
 37            Signed576 rational,
 38            Signed832 radialNumerator,
 39            Signed576 radialDenominator,
 40            Signed576 squaredAxisLength)
 41        {
 102542            Axis = axis;
 102543            Negate = negate;
 102544            Depth = depth;
 102545            DepthIsClamped = depthIsClamped;
 102546            Rational = rational;
 102547            RadialNumerator = radialNumerator;
 102548            RadialDenominator = radialDenominator;
 102549            SquaredAxisLength = squaredAxisLength;
 102550            HasValue = true;
 102551        }
 52
 53        internal bool HasValue { get; }
 54    }
 55
 56    internal readonly struct CenteredCylinderContactFeature
 57    {
 58        internal CenteredCylinderContactFeature(
 59            int boxFaceAxis,
 60            int boxFaceSign,
 61            int cylinderCapSign)
 62        {
 101563            BoxFaceAxis = boxFaceAxis;
 101564            BoxFaceSign = boxFaceSign;
 101565            CylinderCapSign = cylinderCapSign;
 101566            IsCapFace = true;
 101567        }
 68
 69        internal int BoxFaceAxis { get; }
 70        internal int BoxFaceSign { get; }
 71        internal int CylinderCapSign { get; }
 72        internal bool IsCapFace { get; }
 73    }
 74
 75    #endregion
 76
 77    internal static bool TryGetCenteredCylinderContact(
 78        Vector3d center,
 79        FixedQuaternion orientation,
 80        Vector3d halfExtents,
 81        Vector3d cylinderCenter,
 82        FixedQuaternion cylinderRotation,
 83        Vector3d localCylinderAxisDirection,
 84        Fixed64 cylinderAxisLength,
 85        Fixed64 cylinderRadius,
 86        out FixedContactAnchors contact)
 1087        => TryGetCenteredCylinderContact(
 1088            center,
 1089            orientation,
 1090            halfExtents,
 1091            cylinderCenter,
 1092            cylinderRotation,
 1093            localCylinderAxisDirection,
 1094            cylinderAxisLength,
 1095            cylinderRadius,
 1096            out contact,
 1097            out _);
 98
 99    internal static bool TryGetCenteredCylinderContact(
 100        Vector3d center,
 101        FixedQuaternion orientation,
 102        Vector3d halfExtents,
 103        Vector3d cylinderCenter,
 104        FixedQuaternion cylinderRotation,
 105        Vector3d localCylinderAxisDirection,
 106        Fixed64 cylinderAxisLength,
 107        Fixed64 cylinderRadius,
 108        out FixedContactAnchors contact,
 109        out CenteredCylinderContactFeature feature)
 110    {
 1026111        GetRotatedLocalAxisNumerators(
 1026112            cylinderRotation,
 1026113            localCylinderAxisDirection,
 1026114            out Signed192 cylinderAxisX,
 1026115            out Signed192 cylinderAxisY,
 1026116            out Signed192 cylinderAxisZ,
 1026117            out Signed192 cylinderAxisDenominator);
 1026118        WideAxis3 cylinderAxis = new(
 1026119            Signed320.ExtendValue(cylinderAxisX),
 1026120            Signed320.ExtendValue(cylinderAxisY),
 1026121            Signed320.ExtendValue(cylinderAxisZ));
 1026122        if (!CanOverlapCenteredCapsule(
 1026123                center,
 1026124                orientation,
 1026125                halfExtents,
 1026126                cylinderCenter,
 1026127                cylinderRotation,
 1026128                localCylinderAxisDirection,
 1026129                cylinderAxisLength,
 1026130                cylinderRadius))
 131        {
 4132            contact = default;
 4133            feature = default;
 4134            return false;
 135        }
 136
 1022137        WideRationalBasis3d basis = new(orientation);
 1022138        Signed576 commonDenominatorWide = WideArithmetic.MultiplySigned576(
 1022139            Signed576.ExtendValue(
 1022140                WideArithmetic.MultiplySigned192(
 1022141                    basis.Denominator,
 1022142                    cylinderAxisDenominator)),
 1022143            Signed192.Raw(Fixed64.Two));
 144        // Each normalized rigid-frame denominator needs at most 68 signed
 145        // bits. Their product plus the Q32.32 factor for two needs at most
 146        // 170 signed bits, so this narrowing is exact.
 1022147        _ = Signed192.TryNarrowSigned(
 1022148            commonDenominatorWide,
 1022149            out Signed192 commonDenominator);
 1022150        Span<WideAxis3> boxAxes = stackalloc WideAxis3[3]
 1022151        {
 1022152            basis.GetAxis(0),
 1022153            basis.GetAxis(1),
 1022154            basis.GetAxis(2),
 1022155        };
 1022156        var best = default(CylinderPenetration);
 1022157        if (!TryKeepCylinderAxis(
 1022158                cylinderAxis,
 1022159                center,
 1022160                halfExtents,
 1022161                basis,
 1022162                commonDenominator,
 1022163                cylinderCenter,
 1022164                cylinderAxis,
 1022165                cylinderAxisDenominator,
 1022166                cylinderAxisLength,
 1022167                cylinderRadius,
 1022168                ref best))
 169        {
 1170            contact = default;
 1171            feature = default;
 1172            return false;
 173        }
 174
 8162175        for (int index = 0; index < boxAxes.Length; index++)
 176        {
 3061177            if (!TryKeepCylinderAxis(
 3061178                    boxAxes[index],
 3061179                    center,
 3061180                    halfExtents,
 3061181                    basis,
 3061182                    commonDenominator,
 3061183                    cylinderCenter,
 3061184                    cylinderAxis,
 3061185                    cylinderAxisDenominator,
 3061186                    cylinderAxisLength,
 3061187                    cylinderRadius,
 3061188                    ref best)
 3061189                || !TryKeepCylinderAxis(
 3061190                    WideAxis3.Cross(boxAxes[index], cylinderAxis),
 3061191                    center,
 3061192                    halfExtents,
 3061193                    basis,
 3061194                    commonDenominator,
 3061195                    cylinderCenter,
 3061196                    cylinderAxis,
 3061197                    cylinderAxisDenominator,
 3061198                    cylinderAxisLength,
 3061199                    cylinderRadius,
 3061200                    ref best))
 201            {
 1202                contact = default;
 1203                feature = default;
 1204                return false;
 205            }
 206        }
 207
 1020208        for (int cornerIndex = 0;
 9172209            cornerIndex < FixedOrientedBox.CornerCount;
 8152210            cornerIndex++)
 211        {
 8153212            Vector3d localCorner = new(
 8153213                (cornerIndex & 1) == 0 ? -halfExtents.X : halfExtents.X,
 8153214                (cornerIndex & 2) == 0 ? -halfExtents.Y : halfExtents.Y,
 8153215                (cornerIndex & 4) == 0 ? -halfExtents.Z : halfExtents.Z);
 48916216            for (int endpointSign = -1; endpointSign <= 1; endpointSign += 2)
 217            {
 16306218                WideAxis3 endpointAxis = GetCornerToAxisEndpointAxis3D(
 16306219                    center,
 16306220                    cylinderCenter,
 16306221                    basis,
 16306222                    localCorner,
 16306223                    cylinderAxis,
 16306224                    cylinderAxisDenominator,
 16306225                    cylinderAxisLength,
 16306226                    endpointSign);
 16306227                if (!TryKeepCylinderAxis(
 16306228                        endpointAxis,
 16306229                        center,
 16306230                        halfExtents,
 16306231                        basis,
 16306232                        commonDenominator,
 16306233                        cylinderCenter,
 16306234                        cylinderAxis,
 16306235                        cylinderAxisDenominator,
 16306236                        cylinderAxisLength,
 16306237                        cylinderRadius,
 16306238                        ref best))
 239                {
 1240                    contact = default;
 1241                    feature = default;
 1242                    return false;
 243                }
 244            }
 245        }
 246
 1019247        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 1019248        Vector3d normal = WideNormalization.GetNormalized(
 1019249            Signed576.ExtendValue(orientedAxis.X),
 1019250            Signed576.ExtendValue(orientedAxis.Y),
 1019251            Signed576.ExtendValue(orientedAxis.Z));
 1019252        Vector3d boxLocalPoint = GetLocalAxisSupportPoint(
 1019253            basis,
 1019254            halfExtents,
 1019255            orientedAxis);
 1019256        FixedPointAnchor cylinderAnchor =
 1019257            WideGeometry.GetCenteredCylinderSupportAnchor(
 1019258                cylinderCenter,
 1019259                cylinderRotation,
 1019260                localCylinderAxisDirection,
 1019261                cylinderAxisLength,
 1019262                cylinderRadius,
 1019263                -normal);
 1019264        contact = new FixedContactAnchors(
 1019265            new FixedPointAnchor(
 1019266                center,
 1019267                orientation,
 1019268                boxLocalPoint),
 1019269            cylinderAnchor,
 1019270            normal,
 1019271            best.Depth,
 1019272            best.DepthIsClamped);
 1019273        feature = GetCenteredCylinderContactFeature(
 1019274            orientedAxis,
 1019275            cylinderAxis,
 1019276            basis);
 1019277        return true;
 278    }
 279
 280    private static CenteredCylinderContactFeature
 281        GetCenteredCylinderContactFeature(
 282            WideAxis3 orientedAxis,
 283            WideAxis3 cylinderAxis,
 284            WideRationalBasis3d basis)
 285    {
 1019286        if (!AreParallel(orientedAxis, cylinderAxis))
 3287            return default;
 288
 4066289        for (int index = 0; index < 3; index++)
 290        {
 2032291            WideAxis3 boxAxis = basis.GetAxis(index);
 2032292            if (!AreParallel(orientedAxis, boxAxis))
 293                continue;
 294
 1015295            return new CenteredCylinderContactFeature(
 1015296                index,
 1015297                WideAxis3.Dot(orientedAxis, boxAxis).Sign,
 1015298                -WideAxis3.Dot(orientedAxis, cylinderAxis).Sign);
 299        }
 300
 1301        return default;
 302    }
 303
 304    private static bool AreParallel(WideAxis3 first, WideAxis3 second)
 305    {
 3051306        Signed576 x = WideArithmetic.SubtractSigned576(
 3051307            WideArithmetic.MultiplySigned320(first.Y, second.Z),
 3051308            WideArithmetic.MultiplySigned320(first.Z, second.Y));
 3051309        Signed576 y = WideArithmetic.SubtractSigned576(
 3051310            WideArithmetic.MultiplySigned320(first.Z, second.X),
 3051311            WideArithmetic.MultiplySigned320(first.X, second.Z));
 3051312        Signed576 z = WideArithmetic.SubtractSigned576(
 3051313            WideArithmetic.MultiplySigned320(first.X, second.Y),
 3051314            WideArithmetic.MultiplySigned320(first.Y, second.X));
 3051315        return x.IsZero && y.IsZero && z.IsZero;
 316    }
 317
 318    private static WideAxis3 GetCornerToAxisEndpointAxis3D(
 319        Vector3d boxCenter,
 320        Vector3d axisCenter,
 321        WideRationalBasis3d basis,
 322        Vector3d localCorner,
 323        WideAxis3 axis,
 324        Signed192 axisDenominator,
 325        Fixed64 axisLength,
 326        int endpointSign) =>
 17393327        new(
 17393328            GetCornerToAxisEndpointComponent(
 17393329                boxCenter.X,
 17393330                axisCenter.X,
 17393331                basis.Xx,
 17393332                basis.Yx,
 17393333                basis.Zx,
 17393334                basis.Denominator,
 17393335                localCorner,
 17393336                axis.X,
 17393337                axisDenominator,
 17393338                axisLength,
 17393339                endpointSign),
 17393340            GetCornerToAxisEndpointComponent(
 17393341                boxCenter.Y,
 17393342                axisCenter.Y,
 17393343                basis.Xy,
 17393344                basis.Yy,
 17393345                basis.Zy,
 17393346                basis.Denominator,
 17393347                localCorner,
 17393348                axis.Y,
 17393349                axisDenominator,
 17393350                axisLength,
 17393351                endpointSign),
 17393352            GetCornerToAxisEndpointComponent(
 17393353                boxCenter.Z,
 17393354                axisCenter.Z,
 17393355                basis.Xz,
 17393356                basis.Yz,
 17393357                basis.Zz,
 17393358                basis.Denominator,
 17393359                localCorner,
 17393360                axis.Z,
 17393361                axisDenominator,
 17393362                axisLength,
 17393363                endpointSign));
 364
 365    private static Signed320 GetCornerToAxisEndpointComponent(
 366        Fixed64 boxCenter,
 367        Fixed64 axisCenter,
 368        Signed192 basisX,
 369        Signed192 basisY,
 370        Signed192 basisZ,
 371        Signed192 basisDenominator,
 372        Vector3d localCorner,
 373        Signed320 axisComponent,
 374        Signed192 axisDenominator,
 375        Fixed64 axisLength,
 376        int endpointSign)
 377    {
 52179378        Signed192 twiceScale = Signed192.Raw(Fixed64.Two);
 52179379        Signed320 corner = GetLocalOffsetNumerator(
 52179380            basisX,
 52179381            basisY,
 52179382            basisZ,
 52179383            localCorner);
 52179384        Signed576 center = WideArithmetic.MultiplySigned576(
 52179385            WideArithmetic.MultiplySigned320(
 52179386                WideArithmetic.MultiplySigned192(
 52179387                    WideArithmetic.SubtractSigned192(
 52179388                        Signed192.Raw(axisCenter),
 52179389                        Signed192.Raw(boxCenter)),
 52179390                    basisDenominator),
 52179391                Signed320.ExtendValue(axisDenominator)),
 52179392            twiceScale);
 52179393        Signed576 endpoint = WideArithmetic.MultiplySigned576(
 52179394            WideArithmetic.MultiplySigned576(
 52179395                Signed576.ExtendValue(axisComponent),
 52179396                Signed192.Signed(
 52179397                    endpointSign * axisLength.m_rawValue)),
 52179398            basisDenominator);
 52179399        Signed576 cornerWide = WideArithmetic.MultiplySigned576(
 52179400            WideArithmetic.MultiplySigned320(
 52179401                corner,
 52179402                Signed320.ExtendValue(axisDenominator)),
 52179403            twiceScale);
 52179404        Signed576 component = WideArithmetic.SubtractSigned576(
 52179405            WideArithmetic.AddSigned576(center, endpoint),
 52179406            cornerWide);
 407        // The center term needs at most 235 signed bits (65-bit delta, two
 408        // 68-bit rigid denominators, and the 34-bit Q32.32 factor for two).
 409        // The endpoint and corner terms are no wider, so the final difference
 410        // fits exactly in Signed320.
 52179411        return new Signed320(
 52179412            component.Word4,
 52179413            component.Word3,
 52179414            component.Word2,
 52179415            component.Word1,
 52179416            component.Word0);
 417    }
 418
 419    private static bool TryKeepCylinderAxis(
 420        WideAxis3 axis,
 421        Vector3d boxCenter,
 422        Vector3d halfExtents,
 423        WideRationalBasis3d basis,
 424        Signed192 commonDenominator,
 425        Vector3d cylinderCenter,
 426        WideAxis3 cylinderAxis,
 427        Signed192 cylinderAxisDenominator,
 428        Fixed64 cylinderAxisLength,
 429        Fixed64 cylinderRadius,
 430        ref CylinderPenetration best)
 431    {
 23449432        if (axis.IsZero)
 1018433            return true;
 434
 22431435        Signed576 boxRadius = GetBoxProjectionRadiusNumerator(
 22431436            axis,
 22431437            halfExtents,
 22431438            basis);
 22431439        Signed576 centerProjection = WideRigidProjection.GetWorldOriginDifferenceProjection(
 22431440            cylinderCenter,
 22431441            boxCenter,
 22431442            axis);
 22431443        bool negate = centerProjection.Sign < 0;
 22431444        Signed576 baseRational = WideArithmetic.SubtractSigned576(
 22431445            boxRadius,
 22431446            WideArithmetic.MultiplySigned576(
 22431447                GetMagnitude(centerProjection),
 22431448                basis.Denominator));
 22431449        Signed576 rational = WideArithmetic.MultiplySigned576(
 22431450            WideArithmetic.MultiplySigned576(
 22431451                baseRational,
 22431452                cylinderAxisDenominator),
 22431453            Signed192.Raw(Fixed64.Two));
 22431454        Signed576 alignmentWide = WideAxis3.Dot(
 22431455            axis,
 22431456            cylinderAxis);
 22431457        Signed576 alignmentMagnitude = GetMagnitude(alignmentWide);
 22431458        rational = WideArithmetic.AddSigned576(
 22431459            rational,
 22431460            WideArithmetic.MultiplySigned576(
 22431461                WideArithmetic.MultiplySigned576(
 22431462                    alignmentMagnitude,
 22431463                    Signed192.Raw(cylinderAxisLength)),
 22431464                basis.Denominator));
 465
 22431466        Signed576 cylinderAxisSquared = cylinderAxis.SquaredLength;
 22431467        Signed576 projectionSquared = axis.SquaredLength;
 22431468        Signed832 firstPlaneTerm = WideArithmetic.MultiplySigned576ToSigned832(
 22431469            projectionSquared,
 22431470            cylinderAxisSquared);
 22431471        Signed832 planeSquared = WideArithmetic.SubtractSigned832(
 22431472            firstPlaneTerm,
 22431473            WideArithmetic.MultiplySigned576ToSigned832(
 22431474                alignmentWide,
 22431475                alignmentWide));
 22431476        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 22431477            Signed192.Raw(cylinderRadius),
 22431478            Signed192.Raw(cylinderRadius));
 22431479        Signed832 radialNumerator = WideArithmetic.MultiplyNonNegativeToSigned832(
 22431480            planeSquared,
 22431481            radiusSquared);
 22431482        if (rational.Sign < 0
 22431483            && !IsCylinderRadicalAtLeastRatio(
 22431484                radialNumerator,
 22431485                cylinderAxisSquared,
 22431486                WideArithmetic.SubtractSigned576(default, rational),
 22431487                commonDenominator))
 488        {
 3489            return false;
 490        }
 491
 22428492        GetCylinderDepth(
 22428493            rational,
 22428494            radialNumerator,
 22428495            cylinderAxisSquared,
 22428496            projectionSquared,
 22428497            commonDenominator,
 22428498            out Fixed64 depth,
 22428499            out bool depthIsClamped);
 22428500        bool shouldReplace = !best.HasValue || depth < best.Depth;
 22428501        if (best.HasValue && depth == best.Depth)
 502        {
 1050503            shouldReplace = WideArithmetic.CompareRadialProjectionDepths(
 1050504                rational,
 1050505                radialNumerator,
 1050506                cylinderAxisSquared,
 1050507                projectionSquared,
 1050508                best.Rational,
 1050509                best.RadialNumerator,
 1050510                best.RadialDenominator,
 1050511                best.SquaredAxisLength,
 1050512                commonDenominator) < 0;
 513        }
 22428514        if (shouldReplace)
 515        {
 1025516            best = new CylinderPenetration(
 1025517                axis,
 1025518                negate,
 1025519                depth,
 1025520                depthIsClamped,
 1025521                rational,
 1025522                radialNumerator,
 1025523                cylinderAxisSquared,
 1025524                projectionSquared);
 525        }
 22428526        return true;
 527    }
 528
 529    private static bool IsCylinderRadicalAtLeastRatio(
 530        Signed832 radicalNumerator,
 531        Signed576 radicalDenominator,
 532        Signed576 ratioNumerator,
 533        Signed192 ratioDenominator)
 534    {
 30535        Span<ulong> radical = stackalloc ulong[13];
 30536        Span<ulong> radicalDivisor = stackalloc ulong[9];
 30537        Span<ulong> ratio = stackalloc ulong[9];
 30538        Span<ulong> ratioDivisor = stackalloc ulong[3];
 30539        Span<ulong> squared = stackalloc ulong[18];
 30540        Span<ulong> ratioDivisorSquared = stackalloc ulong[6];
 30541        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 30542        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 30543        WideArithmetic.GetMagnitude(radicalNumerator, radical);
 30544        WideArithmetic.GetMagnitude(
 30545            radicalDenominator,
 30546            radicalDivisor);
 30547        WideArithmetic.GetMagnitude(ratioNumerator, ratio);
 30548        WideArithmetic.GetMagnitude(
 30549            ratioDenominator,
 30550            out ratioDivisor[2],
 30551            out ratioDivisor[1],
 30552            out ratioDivisor[0]);
 30553        WideArithmetic.MultiplyMagnitudes(
 30554            ratioDivisor,
 30555            ratioDivisor,
 30556            ratioDivisorSquared);
 30557        WideArithmetic.MultiplyMagnitudes(radical, ratioDivisorSquared, left);
 30558        WideArithmetic.MultiplyMagnitudes(ratio, ratio, squared);
 30559        WideArithmetic.MultiplyMagnitudes(squared, radicalDivisor, right);
 30560        return WideArithmetic.CompareMagnitudeEqualLength(left, right) >= 0;
 561    }
 562
 563    private static void GetCylinderDepth(
 564        Signed576 rational,
 565        Signed832 radialNumerator,
 566        Signed576 radialDenominator,
 567        Signed576 squaredAxisLength,
 568        Signed192 commonDenominator,
 569        out Fixed64 depth,
 570        out bool depthIsClamped)
 571    {
 22428572        Signed576 radial = WideArithmetic.GetFloorSquareRootOfProduct(
 22428573            radialNumerator,
 22428574            Signed192.Signed(1L));
 22428575        Signed576 radialDivisorWide = WideArithmetic.GetFloorSquareRoot(
 22428576            Signed704.ExtendValue(radialDenominator));
 577        // A rotated unit-axis numerator needs at most 103 signed bits. Its
 578        // squared length therefore needs at most 208, and this square root
 579        // needs at most 104, so the Signed192 narrowing is exact.
 22428580        _ = Signed192.TryNarrowSigned(
 22428581            radialDivisorWide,
 22428582            out Signed192 radialDivisor);
 22428583        Signed576 numerator = WideArithmetic.AddSigned576(
 22428584            WideArithmetic.MultiplySigned576(rational, radialDivisor),
 22428585            WideArithmetic.MultiplySigned576(radial, commonDenominator));
 22428586        Signed576 axisLength = WideArithmetic.GetFloorSquareRoot(
 22428587            Signed704.ExtendValue(squaredAxisLength));
 22428588        Signed320 commonAndRadial = WideArithmetic.MultiplySigned192(
 22428589            commonDenominator,
 22428590            radialDivisor);
 22428591        Signed704 denominator = WideArithmetic.MultiplySigned576ToSigned704(
 22428592            axisLength,
 22428593            commonAndRadial);
 22428594        if (!Fixed64.TryGetSignedRawRatio(
 22428595                Signed704.ExtendValue(numerator),
 22428596                denominator,
 22428597                out depth))
 598        {
 30599            depth = Fixed64.MaxValue;
 30600            depthIsClamped = true;
 30601            return;
 602        }
 603
 22398604        depthIsClamped = false;
 22398605    }
 606}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CylinderCapFace.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.CylinderCapFace.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/// Contact generation for oriented box vs. centered cylinder cap-face collisions.
 14/// </content>
 15internal static partial class WideOrientedBox
 16{
 17    #region Nested Types
 18
 19    private readonly struct LocalCapContact : IEquatable<LocalCapContact>
 20    {
 21        internal LocalCapContact(Signed320 u, Signed320 v)
 22        {
 405223            U = u;
 405224            V = v;
 405225        }
 26
 27        internal Signed320 U { get; }
 28        internal Signed320 V { get; }
 29
 30        public bool Equals(LocalCapContact other) =>
 607531            U.Equals(other.U) && V.Equals(other.V);
 32    }
 33
 34    #endregion
 35
 36    // Rounded canonical axes can differ by a few raw units from the exact
 37    // quaternion basis even when authored from the same rotation.
 138    private static readonly Fixed64 ParallelFaceAlignmentThreshold =
 139        Fixed64.One - Fixed64.FromRaw(64L);
 40
 41    internal static void GetCenteredCylinderCapFaceContacts(
 42        Vector3d boxCenter,
 43        FixedQuaternion boxOrientation,
 44        Vector3d boxHalfExtents,
 45        Vector3d cylinderCenter,
 46        FixedQuaternion cylinderRotation,
 47        Vector3d localCylinderAxis,
 48        Fixed64 cylinderLength,
 49        Fixed64 cylinderRadius,
 50        FixedContactAnchors primary,
 51        CenteredCylinderContactFeature feature,
 52        Span<FixedContactLocalPoints> contacts,
 53        out int count)
 54    {
 101555        count = 0;
 101556        if (!feature.IsCapFace)
 257            return;
 58
 101359        int faceAxis = feature.BoxFaceAxis;
 60
 61        // A normalized axis scaled by half of a representable positive length
 62        // is always representable when the radial extent is zero.
 101363        FixedPointAnchor capCenterAnchor =
 101364            WideGeometry.GetCenteredCylinderSupportAnchor(
 101365            cylinderCenter,
 101366            cylinderRotation,
 101367            localCylinderAxis,
 101368            cylinderLength,
 101369            Fixed64.Zero,
 101370            -primary.Normal,
 101371            feature.CylinderCapSign);
 101372        _ = capCenterAnchor.TryGetOffsetFrom(
 101373            new FixedPointAnchor(
 101374                cylinderCenter,
 101375                FixedQuaternion.Identity,
 101376                Vector3d.Zero),
 101377            out Vector3d capCenterOffset);
 78
 101379        WideRationalBasis3d basis = new(boxOrientation);
 101380        GetPointProjections(
 101381            cylinderCenter,
 101382            boxCenter,
 101383            basis,
 101384            out Signed320 centerX,
 101385            out Signed320 centerY,
 101386            out Signed320 centerZ);
 101387        GetDirectionProjections(
 101388            capCenterOffset,
 101389            basis,
 101390            out Signed320 capX,
 101391            out Signed320 capY,
 101392            out Signed320 capZ);
 101393        centerX = WideArithmetic.AddSigned320(centerX, capX);
 101394        centerY = WideArithmetic.AddSigned320(centerY, capY);
 101395        centerZ = WideArithmetic.AddSigned320(centerZ, capZ);
 96
 101397        Signed320 extentX = GetExtentNumerator(
 101398            boxHalfExtents.X,
 101399            basis.Denominator);
 1013100        Signed320 extentY = GetExtentNumerator(
 1013101            boxHalfExtents.Y,
 1013102            basis.Denominator);
 1013103        Signed320 extentZ = GetExtentNumerator(
 1013104            boxHalfExtents.Z,
 1013105            basis.Denominator);
 1013106        Signed320 radius = WideArithmetic.MultiplySigned192(
 1013107            Signed192.Raw(cylinderRadius),
 1013108            basis.Denominator);
 1013109        GetFaceCoordinates(
 1013110            faceAxis,
 1013111            centerX,
 1013112            centerY,
 1013113            centerZ,
 1013114            extentX,
 1013115            extentY,
 1013116            extentZ,
 1013117            out Signed320 centerU,
 1013118            out Signed320 centerV,
 1013119            out Signed320 extentU,
 1013120            out Signed320 extentV);
 1013121        Span<LocalCapContact> localContacts =
 1013122            stackalloc LocalCapContact[4];
 1013123        KeepCapExtreme(
 1013124            centerU,
 1013125            centerV,
 1013126            extentU,
 1013127            extentV,
 1013128            radius,
 1013129            positive: false,
 1013130            primaryAxisIsU: true,
 1013131            localContacts,
 1013132            ref count);
 1013133        KeepCapExtreme(
 1013134            centerU,
 1013135            centerV,
 1013136            extentU,
 1013137            extentV,
 1013138            radius,
 1013139            positive: true,
 1013140            primaryAxisIsU: true,
 1013141            localContacts,
 1013142            ref count);
 1013143        KeepCapExtreme(
 1013144            centerV,
 1013145            centerU,
 1013146            extentV,
 1013147            extentU,
 1013148            radius,
 1013149            positive: false,
 1013150            primaryAxisIsU: false,
 1013151            localContacts,
 1013152            ref count);
 1013153        KeepCapExtreme(
 1013154            centerV,
 1013155            centerU,
 1013156            extentV,
 1013157            extentU,
 1013158            radius,
 1013159            positive: true,
 1013160            primaryAxisIsU: false,
 1013161            localContacts,
 1013162            ref count);
 163
 1013164        FixedPointAnchor cylinderSupport =
 1013165            WideGeometry.GetCenteredCylinderSupportAnchor(
 1013166                cylinderCenter,
 1013167                cylinderRotation,
 1013168                localCylinderAxis,
 1013169                cylinderLength,
 1013170                Fixed64.Zero,
 1013171                -primary.Normal,
 1013172                feature.CylinderCapSign);
 1013173        Fixed64 supportAxial =
 1013174            Vector3d.Dot(cylinderSupport.LocalPoint, localCylinderAxis);
 1013175        int outputCount = 0;
 10124176        for (int index = 0; index < count; index++)
 177        {
 4049178            LocalCapContact local = localContacts[index];
 4049179            GetLocalCoordinates(
 4049180                faceAxis,
 4049181                local.U,
 4049182                local.V,
 4049183                GetSignedFaceExtent(
 4049184                    faceAxis,
 4049185                    feature.BoxFaceSign,
 4049186                    extentX,
 4049187                    extentY,
 4049188                    extentZ),
 4049189                out Signed320 localX,
 4049190                out Signed320 localY,
 4049191                out Signed320 localZ);
 192            // Clipping constrains this point to the box face and the
 193            // overlapping cylinder cap, so both local frames are bounded by
 194            // their representable authored extents.
 4049195            Vector3d boxLocalPoint = GetRationalLocalPoint(
 4049196                localX,
 4049197                localY,
 4049198                localZ,
 4049199                basis.Denominator);
 200
 4049201            var boxPoint = new FixedPointAnchor(
 4049202                boxCenter,
 4049203                boxOrientation,
 4049204                boxLocalPoint);
 4049205            _ = boxPoint.TryGetLocalPointIn(
 4049206                cylinderCenter,
 4049207                cylinderRotation,
 4049208                out Vector3d cylinderLocalPoint);
 209
 4049210            Fixed64 currentAxial =
 4049211                Vector3d.Dot(cylinderLocalPoint, localCylinderAxis);
 4049212            cylinderLocalPoint +=
 4049213                localCylinderAxis * (supportAxial - currentAxial);
 4049214            contacts[outputCount++] = new FixedContactLocalPoints(
 4049215                boxLocalPoint,
 4049216                cylinderLocalPoint);
 217        }
 218
 1013219        count = outputCount;
 1013220    }
 221
 222    private static Vector3d GetRationalLocalPoint(
 223        Signed320 xNumerator,
 224        Signed320 yNumerator,
 225        Signed320 zNumerator,
 226        Signed192 denominator)
 227    {
 4049228        Signed576 denominatorWide = Signed576.ExtendValue(
 4049229            Signed320.ExtendValue(denominator));
 4049230        _ = Fixed64.TryGetSignedRawRatio(
 4049231            Signed576.ExtendValue(xNumerator),
 4049232            denominatorWide,
 4049233            out Fixed64 x);
 4049234        _ = Fixed64.TryGetSignedRawRatio(
 4049235            Signed576.ExtendValue(yNumerator),
 4049236            denominatorWide,
 4049237            out Fixed64 y);
 4049238        _ = Fixed64.TryGetSignedRawRatio(
 4049239            Signed576.ExtendValue(zNumerator),
 4049240            denominatorWide,
 4049241            out Fixed64 z);
 4049242        return new Vector3d(x, y, z);
 243    }
 244
 245    private static void GetFaceCoordinates(
 246        int faceAxis,
 247        Signed320 x,
 248        Signed320 y,
 249        Signed320 z,
 250        Signed320 extentX,
 251        Signed320 extentY,
 252        Signed320 extentZ,
 253        out Signed320 u,
 254        out Signed320 v,
 255        out Signed320 extentU,
 256        out Signed320 extentV)
 257    {
 1013258        if (faceAxis == 0)
 259        {
 1260            u = y;
 1261            v = z;
 1262            extentU = extentY;
 1263            extentV = extentZ;
 1264            return;
 265        }
 1012266        if (faceAxis == 1)
 267        {
 1010268            u = x;
 1010269            v = z;
 1010270            extentU = extentX;
 1010271            extentV = extentZ;
 1010272            return;
 273        }
 274
 2275        u = x;
 2276        v = y;
 2277        extentU = extentX;
 2278        extentV = extentY;
 2279    }
 280
 281    private static void KeepCapExtreme(
 282        Signed320 centerPrimary,
 283        Signed320 centerSecondary,
 284        Signed320 extentPrimary,
 285        Signed320 extentSecondary,
 286        Signed320 radius,
 287        bool positive,
 288        bool primaryAxisIsU,
 289        Span<LocalCapContact> contacts,
 290        ref int count)
 291    {
 4052292        Signed320 secondary = ClampToExtent(
 4052293            centerSecondary,
 4052294            extentSecondary);
 4052295        Signed320 secondaryDelta = WideArithmetic.SubtractSigned320(
 4052296            secondary,
 4052297            centerSecondary);
 4052298        Signed576 radialSquared = WideArithmetic.SubtractSigned576(
 4052299            WideArithmetic.MultiplySigned320(radius, radius),
 4052300            WideArithmetic.MultiplySigned320(
 4052301                secondaryDelta,
 4052302                secondaryDelta));
 4052303        Signed576 remaining = WideArithmetic.GetFloorSquareRoot(
 4052304            Signed704.ExtendValue(radialSquared));
 4052305        Signed576 center = Signed576.ExtendValue(centerPrimary);
 4052306        Signed576 extreme = positive
 4052307            ? WideArithmetic.AddSigned576(center, remaining)
 4052308            : WideArithmetic.SubtractSigned576(center, remaining);
 4052309        Signed576 minimum = Signed576.ExtendValue(
 4052310            WideArithmetic.SubtractSigned320(default, extentPrimary));
 4052311        Signed576 maximum = Signed576.ExtendValue(extentPrimary);
 4052312        if (CompareSigned(extreme, minimum) < 0)
 2313            extreme = minimum;
 4050314        else if (CompareSigned(extreme, maximum) > 0)
 5315            extreme = maximum;
 316        // The extreme was just clamped between Signed320 extents.
 4052317        Signed320 primary = new(
 4052318            extreme.Word4,
 4052319            extreme.Word3,
 4052320            extreme.Word2,
 4052321            extreme.Word1,
 4052322            extreme.Word0);
 323
 4052324        LocalCapContact candidate = primaryAxisIsU
 4052325            ? new LocalCapContact(primary, secondary)
 4052326            : new LocalCapContact(secondary, primary);
 20248327        for (int index = 0; index < count; index++)
 328        {
 6075329            if (contacts[index].Equals(candidate))
 3330                return;
 331        }
 332
 4049333        contacts[count++] = candidate;
 4049334    }
 335
 336    private static Signed320 GetSignedFaceExtent(
 337        int faceAxis,
 338        int faceSign,
 339        Signed320 extentX,
 340        Signed320 extentY,
 341        Signed320 extentZ)
 342    {
 4049343        Signed320 extent = faceAxis == 0
 4049344            ? extentX
 4049345            : faceAxis == 1
 4049346                ? extentY
 4049347                : extentZ;
 4049348        return faceSign < 0
 4049349            ? WideArithmetic.SubtractSigned320(default, extent)
 4049350            : extent;
 351    }
 352
 353    private static void GetLocalCoordinates(
 354        int faceAxis,
 355        Signed320 u,
 356        Signed320 v,
 357        Signed320 face,
 358        out Signed320 x,
 359        out Signed320 y,
 360        out Signed320 z)
 361    {
 4049362        if (faceAxis == 0)
 363        {
 4364            x = face;
 4365            y = u;
 4366            z = v;
 4367            return;
 368        }
 4045369        if (faceAxis == 1)
 370        {
 4037371            x = u;
 4037372            y = face;
 4037373            z = v;
 4037374            return;
 375        }
 376
 8377        x = u;
 8378        y = v;
 8379        z = face;
 8380    }
 381
 382    private static Signed320 ClampToExtent(
 383        Signed320 value,
 384        Signed320 extent)
 385    {
 4052386        Signed320 minimum =
 4052387            WideArithmetic.SubtractSigned320(default, extent);
 4052388        if (CompareSigned(value, minimum) < 0)
 2389            return minimum;
 4050390        return CompareSigned(value, extent) > 0 ? extent : value;
 391    }
 392}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Materialization.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.Materialization.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
 8namespace FixedMathSharp.Geometry;
 9
 10/// <content>
 11/// Provides high-precision materialization helpers for converting wide (extended-precision)
 12/// oriented box coordinates back into standard <see cref="Fixed64"/>/<see cref="Vector3d"/> values.
 13/// </content>
 14internal static partial class WideOrientedBox
 15{
 16    private static Vector3d GetRationalLocalPoint(
 17        WideRationalBasis3d basis,
 18        Signed320 localX,
 19        Signed320 localY,
 20        Signed320 localZ)
 21    {
 54122        Signed576 denominator = ToSigned576(basis.Denominator);
 54123        _ = Fixed64.TryGetSignedRawRatio(
 54124            Signed576.ExtendValue(localX),
 54125            denominator,
 54126            out Fixed64 x);
 54127        _ = Fixed64.TryGetSignedRawRatio(
 54128            Signed576.ExtendValue(localY),
 54129            denominator,
 54130            out Fixed64 y);
 54131        _ = Fixed64.TryGetSignedRawRatio(
 54132            Signed576.ExtendValue(localZ),
 54133            denominator,
 54134            out Fixed64 z);
 54135        return new Vector3d(x, y, z);
 36    }
 37
 38    private static bool TryMaterializeCoordinate(
 39        Fixed64 center,
 40        Signed192 axisX,
 41        Signed192 axisY,
 42        Signed192 axisZ,
 43        Signed192 denominator,
 44        Signed576 denominatorWide,
 45        Vector3d localPoint,
 46        out Fixed64 coordinate)
 47    {
 204948        Signed320 numerator = WideArithmetic.AddSigned320(
 204949            WideArithmetic.MultiplySigned192(Signed192.Raw(center), denominator),
 204950            WideArithmetic.AddSigned320(
 204951                WideArithmetic.AddSigned320(
 204952                    WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.X), axisX),
 204953                    WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.Y), axisY)),
 204954                WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.Z), axisZ)));
 204955        return Fixed64.TryGetSignedRawRatio(
 204956            Signed576.ExtendValue(numerator),
 204957            denominatorWide,
 204958            out coordinate);
 59    }
 60
 61    private static bool TryMaterializeCoordinate(
 62        Fixed64 firstOrigin,
 63        Fixed64 secondOrigin,
 64        Signed192 axisX,
 65        Signed192 axisY,
 66        Signed192 axisZ,
 67        Signed192 denominator,
 68        Signed576 denominatorWide,
 69        Vector3d localPoint,
 70        out Fixed64 coordinate)
 71    {
 20772        Signed192 combinedOrigin = WideArithmetic.AddSigned192(
 20773            Signed192.Raw(firstOrigin),
 20774            Signed192.Raw(secondOrigin));
 20775        Signed320 numerator = WideArithmetic.AddSigned320(
 20776            WideArithmetic.MultiplySigned192(combinedOrigin, denominator),
 20777            WideArithmetic.AddSigned320(
 20778                WideArithmetic.AddSigned320(
 20779                    WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.X), axisX),
 20780                    WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.Y), axisY)),
 20781                WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.Z), axisZ)));
 20782        return Fixed64.TryGetSignedRawRatio(
 20783            Signed576.ExtendValue(numerator),
 20784            denominatorWide,
 20785            out coordinate);
 86    }
 87
 88    private static bool TryMaterializeRationalOffset(
 89        WideRationalBasis3d basis,
 90        Vector3d localOffset,
 91        out Vector3d worldOffset)
 92    {
 493        Signed576 denominator = ToSigned576(basis.Denominator);
 494        bool representable = TryMaterializeCoordinate(
 495            Fixed64.Zero,
 496            basis.Xx,
 497            basis.Yx,
 498            basis.Zx,
 499            basis.Denominator,
 4100            denominator,
 4101            localOffset,
 4102            out Fixed64 x)
 4103            & TryMaterializeCoordinate(
 4104                Fixed64.Zero,
 4105                basis.Xy,
 4106                basis.Yy,
 4107                basis.Zy,
 4108                basis.Denominator,
 4109                denominator,
 4110                localOffset,
 4111                out Fixed64 y)
 4112            & TryMaterializeCoordinate(
 4113                Fixed64.Zero,
 4114                basis.Xz,
 4115                basis.Yz,
 4116                basis.Zz,
 4117                basis.Denominator,
 4118                denominator,
 4119                localOffset,
 4120                out Fixed64 z);
 4121        if (!representable)
 122        {
 2123            worldOffset = default;
 2124            return false;
 125        }
 126
 2127        worldOffset = new Vector3d(x, y, z);
 2128        return true;
 129    }
 130
 131    private static bool TryMaterializeSupportDifferenceCoordinate(
 132        Fixed64 center,
 133        Fixed64 otherOrigin,
 134        Fixed64 otherOffset,
 135        Signed192 axisX,
 136        Signed192 axisY,
 137        Signed192 axisZ,
 138        Signed192 basisDenominator,
 139        Signed576 denominator,
 140        Vector3d localSupport,
 141        out Fixed64 coordinate)
 142    {
 9143        Signed192 relativeOrigin = WideArithmetic.SubtractSigned192(
 9144            WideArithmetic.SubtractSigned192(Signed192.Raw(center), Signed192.Raw(otherOrigin)),
 9145            Signed192.Raw(otherOffset));
 9146        Signed320 numerator = WideArithmetic.AddSigned320(
 9147            WideArithmetic.MultiplySigned192(relativeOrigin, basisDenominator),
 9148            WideArithmetic.AddSigned320(
 9149                WideArithmetic.AddSigned320(
 9150                    WideArithmetic.MultiplySigned192(Signed192.Raw(localSupport.X), axisX),
 9151                    WideArithmetic.MultiplySigned192(Signed192.Raw(localSupport.Y), axisY)),
 9152                WideArithmetic.MultiplySigned192(Signed192.Raw(localSupport.Z), axisZ)));
 9153        return Fixed64.TryGetSignedRawRatio(
 9154            Signed576.ExtendValue(numerator),
 9155            denominator,
 9156            out coordinate);
 157    }
 158
 159    private static bool TryMaterializeBoxSupportDifferenceCoordinate(
 160        Fixed64 center,
 161        Fixed64 otherCenter,
 162        Signed192 axisX,
 163        Signed192 axisY,
 164        Signed192 axisZ,
 165        Signed192 basisDenominator,
 166        Vector3d localSupport,
 167        Signed192 otherAxisX,
 168        Signed192 otherAxisY,
 169        Signed192 otherAxisZ,
 170        Signed192 otherBasisDenominator,
 171        Vector3d otherLocalSupport,
 172        Signed320 denominator,
 173        Signed576 denominatorWide,
 174        out Fixed64 coordinate)
 175    {
 6176        Signed320 supportNumerator = WideArithmetic.GetDotProduct3D(
 6177            Signed192.Raw(localSupport.X),
 6178            Signed192.Raw(localSupport.Y),
 6179            Signed192.Raw(localSupport.Z),
 6180            axisX,
 6181            axisY,
 6182            axisZ);
 6183        Signed320 otherSupportNumerator = WideArithmetic.GetDotProduct3D(
 6184            Signed192.Raw(otherLocalSupport.X),
 6185            Signed192.Raw(otherLocalSupport.Y),
 6186            Signed192.Raw(otherLocalSupport.Z),
 6187            otherAxisX,
 6188            otherAxisY,
 6189            otherAxisZ);
 6190        Signed576 numerator = WideArithmetic.SubtractSigned576(
 6191            WideArithmetic.AddSigned576(
 6192                WideArithmetic.MultiplySigned320(
 6193                    Signed320.ExtendValue(
 6194                        WideArithmetic.SubtractSigned192(
 6195                            Signed192.Raw(center),
 6196                            Signed192.Raw(otherCenter))),
 6197                    denominator),
 6198                WideArithmetic.MultiplySigned320(
 6199                    supportNumerator,
 6200                    Signed320.ExtendValue(
 6201                        otherBasisDenominator))),
 6202            WideArithmetic.MultiplySigned320(
 6203                otherSupportNumerator,
 6204                Signed320.ExtendValue(
 6205                    basisDenominator)));
 6206        return Fixed64.TryGetSignedRawRatio(
 6207            numerator,
 6208            denominatorWide,
 6209            out coordinate);
 210    }
 211
 212    private static bool TryGetRelativeOffsetCoordinate(
 213        Fixed64 firstOrigin,
 214        Fixed64 firstOffset,
 215        Fixed64 secondOrigin,
 216        Signed192 axisX,
 217        Signed192 axisY,
 218        Signed192 axisZ,
 219        Signed192 basisDenominator,
 220        Signed576 denominator,
 221        Vector3d secondLocalPoint,
 222        out Fixed64 coordinate)
 223    {
 105224        Signed192 relativeOrigin = WideArithmetic.SubtractSigned192(
 105225            WideArithmetic.AddSigned192(
 105226                Signed192.Raw(firstOrigin),
 105227                Signed192.Raw(firstOffset)),
 105228            Signed192.Raw(secondOrigin));
 105229        Signed320 rotatedLocalPoint = WideArithmetic.AddSigned320(
 105230            WideArithmetic.AddSigned320(
 105231                WideArithmetic.MultiplySigned192(
 105232                    Signed192.Raw(secondLocalPoint.X),
 105233                    axisX),
 105234                WideArithmetic.MultiplySigned192(
 105235                    Signed192.Raw(secondLocalPoint.Y),
 105236                    axisY)),
 105237            WideArithmetic.MultiplySigned192(
 105238                Signed192.Raw(secondLocalPoint.Z),
 105239                axisZ));
 105240        Signed320 numerator = WideArithmetic.SubtractSigned320(
 105241            WideArithmetic.MultiplySigned192(
 105242                relativeOrigin,
 105243                basisDenominator),
 105244            rotatedLocalPoint);
 105245        return Fixed64.TryGetSignedRawRatio(
 105246            Signed576.ExtendValue(numerator),
 105247            denominator,
 105248            out coordinate);
 249    }
 250}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RationalSegmentSweep.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.RationalSegmentSweep.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/// Wide-oriented box rational segment sweep operations.
 14/// </content>
 15internal static partial class WideOrientedBox
 16{
 17    // A rigid triangle vertex uses fewer than 192 numerator bits over a
 18    // 126-bit quaternion basis denominator. Finite-Y clipping raises a point
 19    // to fewer than 386/319 bits. Cross-multiplying two clipped endpoints
 20    // therefore needs at most 706 bits; a line violation needs 1094 bits and
 21    // its squared half-step comparison needs fewer than 2252 bits.
 22    private const int TriangleSweepMagnitudeWords = 36;
 23
 24    private static bool TryGetRationalSegmentSweepDistance(
 25        SweepRationalPoint first,
 26        SweepRationalPoint second,
 27        Vector2d start,
 28        Vector2d direction,
 29        Fixed64 maximumDistance,
 30        Fixed64 radius,
 31        out Fixed64 distance,
 32        out Fixed64 segmentParameter)
 33    {
 21734        Signed832 edgeX = WideArithmetic.SubtractSigned832(
 21735            WideArithmetic.MultiplySigned576ToSigned832(
 21736                second.X,
 21737                first.Denominator),
 21738            WideArithmetic.MultiplySigned576ToSigned832(
 21739                first.X,
 21740                second.Denominator));
 21741        Signed832 edgeZ = WideArithmetic.SubtractSigned832(
 21742            WideArithmetic.MultiplySigned576ToSigned832(
 21743                second.Z,
 21744                first.Denominator),
 21745            WideArithmetic.MultiplySigned576ToSigned832(
 21746                first.Z,
 21747                second.Denominator));
 21748        if (edgeX.IsZero && edgeZ.IsZero)
 49        {
 950            distance = default;
 951            segmentParameter = default;
 952            return false;
 53        }
 54
 20855        Signed576 startX = WideArithmetic.SubtractSigned576(
 20856            WideArithmetic.MultiplySigned576(
 20857                first.Denominator,
 20858                Signed192.Raw(start.X)),
 20859            first.X);
 20860        Signed576 startZ = WideArithmetic.SubtractSigned576(
 20861            WideArithmetic.MultiplySigned576(
 20862                first.Denominator,
 20863                Signed192.Raw(start.Y)),
 20864            first.Z);
 20865        Span<ulong> startCross =
 20866            stackalloc ulong[TriangleSweepMagnitudeWords];
 20867        GetCrossMagnitude(
 20868            edgeX,
 20869            edgeZ,
 20870            startX,
 20871            startZ,
 20872            startCross,
 20873            out int startCrossSign);
 74
 20875        Signed192 directionX = Signed192.Raw(direction.X);
 20876        Signed192 directionZ = Signed192.Raw(direction.Y);
 20877        Span<ulong> velocityCore =
 20878            stackalloc ulong[TriangleSweepMagnitudeWords];
 20879        GetCrossMagnitude(
 20880            edgeX,
 20881            edgeZ,
 20882            directionX,
 20883            directionZ,
 20884            velocityCore,
 20885            out int velocitySign);
 20886        Span<ulong> denominatorMagnitude = stackalloc ulong[9];
 20887        WideArithmetic.GetMagnitude(
 20888            first.Denominator,
 20889            denominatorMagnitude);
 20890        Span<ulong> velocity =
 20891            stackalloc ulong[TriangleSweepMagnitudeWords];
 20892        WideArithmetic.MultiplyMagnitudes(
 20893            velocityCore,
 20894            denominatorMagnitude,
 20895            velocity);
 96
 20897        Span<ulong> edgeSquared =
 20898            stackalloc ulong[TriangleSweepMagnitudeWords];
 20899        GetEdgeSquaredMagnitude(edgeX, edgeZ, edgeSquared);
 208100        if (CompareRationalSegmentLineAt(
 208101                startCross,
 208102                startCrossSign,
 208103                velocity,
 208104                velocitySign,
 208105                edgeSquared,
 208106                denominatorMagnitude,
 208107                radius,
 208108                default,
 208109                SweepRawScale) <= 0
 208110            && TryGetRationalSegmentParameter(
 208111                first,
 208112                second,
 208113                edgeX,
 208114                edgeZ,
 208115                edgeSquared,
 208116                start,
 208117                direction,
 208118                Fixed64.Zero,
 208119                out segmentParameter))
 120        {
 4121            distance = Fixed64.Zero;
 4122            return true;
 123        }
 124
 204125        if (maximumDistance == Fixed64.Zero
 204126            || startCrossSign == 0
 204127            || velocitySign == 0
 204128            || startCrossSign == velocitySign)
 129        {
 16130            distance = default;
 16131            segmentParameter = default;
 16132            return false;
 133        }
 134
 188135        Span<ulong> startAtUnit =
 188136            stackalloc ulong[TriangleSweepMagnitudeWords];
 188137        Span<ulong> velocityAtMaximum =
 188138            stackalloc ulong[TriangleSweepMagnitudeWords];
 188139        Span<ulong> oneMagnitude = stackalloc ulong[3];
 188140        WideArithmetic.GetMagnitude(SweepRawScale, out oneMagnitude[2], out oneMagnitude[1], out oneMagnitude[0]);
 188141        Span<ulong> maximumMagnitude = stackalloc ulong[3];
 188142        WideArithmetic.GetMagnitude(
 188143            Signed192.Signed(maximumDistance.m_rawValue),
 188144            out maximumMagnitude[2],
 188145            out maximumMagnitude[1],
 188146            out maximumMagnitude[0]);
 188147        WideArithmetic.MultiplyMagnitudes(startCross, oneMagnitude, startAtUnit);
 188148        WideArithmetic.MultiplyMagnitudes(velocity, maximumMagnitude, velocityAtMaximum);
 188149        bool closestBeyondMaximum =
 188150            WideArithmetic.CompareMagnitudeEqualLength(startAtUnit, velocityAtMaximum) > 0;
 188151        if (closestBeyondMaximum
 188152            && CompareRationalSegmentLineAt(
 188153                startCross,
 188154                startCrossSign,
 188155                velocity,
 188156                velocitySign,
 188157                edgeSquared,
 188158                denominatorMagnitude,
 188159                radius,
 188160                Signed192.Signed(maximumDistance.m_rawValue),
 188161                SweepRawScale) > 0)
 162        {
 7163            distance = default;
 7164            segmentParameter = default;
 7165            return false;
 166        }
 167
 181168        long candidateRaw = maximumDistance.m_rawValue;
 181169        if (!closestBeyondMaximum)
 170        {
 178171            long crossingLow = 0L;
 178172            long crossingHigh = candidateRaw;
 6233173            while (crossingLow < crossingHigh)
 174            {
 6055175                long middle =
 6055176                    crossingLow + ((crossingHigh - crossingLow) >> 1);
 6055177                if (CompareApproachingLineAt(
 6055178                        startCross,
 6055179                        velocity,
 6055180                        middle,
 6055181                        oneMagnitude) <= 0)
 182                {
 2474183                    crossingHigh = middle;
 184                }
 185                else
 186                {
 3581187                    crossingLow = middle + 1L;
 188                }
 189            }
 190
 178191            candidateRaw = crossingLow;
 192        }
 193
 194        // A nonzero approaching line crosses no earlier than raw tick one.
 181195        long high = candidateRaw - 1L;
 181196        if (CompareRationalSegmentLineAtHalf(
 181197                startCross,
 181198                startCrossSign,
 181199                velocity,
 181200                velocitySign,
 181201                edgeSquared,
 181202                denominatorMagnitude,
 181203                radius,
 181204                high) > 0)
 205        {
 7206            distance = Fixed64.FromRaw(candidateRaw);
 207        }
 208        else
 209        {
 174210            long low = 0L;
 5946211            while (low < high)
 212            {
 5772213                long middle = low + ((high - low) >> 1);
 5772214                if (CompareRationalSegmentLineAtHalf(
 5772215                        startCross,
 5772216                        startCrossSign,
 5772217                        velocity,
 5772218                        velocitySign,
 5772219                        edgeSquared,
 5772220                        denominatorMagnitude,
 5772221                        radius,
 5772222                        middle) <= 0)
 223                {
 4250224                    high = middle;
 225                }
 226                else
 227                {
 1522228                    low = middle + 1L;
 229                }
 230            }
 231
 174232            int midpointComparison =
 174233                CompareRationalSegmentLineAtHalf(
 174234                    startCross,
 174235                    startCrossSign,
 174236                    velocity,
 174237                    velocitySign,
 174238                    edgeSquared,
 174239                    denominatorMagnitude,
 174240                    radius,
 174241                    low);
 174242            distance = Fixed64.FromRaw(
 174243                midpointComparison == 0 && (low & 1L) != 0L
 174244                    ? low + 1L
 174245                    : low);
 246        }
 247
 181248        if (TryGetRationalSegmentParameter(
 181249                first,
 181250                second,
 181251                edgeX,
 181252                edgeZ,
 181253                edgeSquared,
 181254                start,
 181255                direction,
 181256                distance,
 181257                out segmentParameter))
 258        {
 156259            return true;
 260        }
 261
 25262        distance = default;
 25263        segmentParameter = default;
 25264        return false;
 265    }
 266
 267    private static int CompareApproachingLineAt(
 268        ReadOnlySpan<ulong> startCross,
 269        ReadOnlySpan<ulong> velocity,
 270        long distanceRaw,
 271        ReadOnlySpan<ulong> oneMagnitude)
 272    {
 6055273        Span<ulong> distanceMagnitude = stackalloc ulong[1]
 6055274        {
 6055275            unchecked((ulong)distanceRaw),
 6055276        };
 6055277        Span<ulong> startTerm =
 6055278            stackalloc ulong[TriangleSweepMagnitudeWords];
 6055279        Span<ulong> velocityTerm =
 6055280            stackalloc ulong[TriangleSweepMagnitudeWords];
 6055281        WideArithmetic.MultiplyMagnitudes(startCross, oneMagnitude, startTerm);
 6055282        WideArithmetic.MultiplyMagnitudes(
 6055283            velocity,
 6055284            distanceMagnitude,
 6055285            velocityTerm);
 6055286        return WideArithmetic.CompareMagnitudeEqualLength(startTerm, velocityTerm);
 287    }
 288
 289    private static int CompareRationalSegmentLineAtHalf(
 290        ReadOnlySpan<ulong> startCross,
 291        int startCrossSign,
 292        ReadOnlySpan<ulong> velocity,
 293        int velocitySign,
 294        ReadOnlySpan<ulong> edgeSquared,
 295        ReadOnlySpan<ulong> denominator,
 296        Fixed64 radius,
 297        long lowerRaw)
 298    {
 6127299        Signed192 lower = Signed192.Signed(lowerRaw);
 6127300        Signed192 midpoint = WideArithmetic.AddSigned192(
 6127301            WideArithmetic.AddSigned192(lower, lower),
 6127302            SweepOneCoefficient);
 6127303        return CompareRationalSegmentLineAt(
 6127304            startCross,
 6127305            startCrossSign,
 6127306            velocity,
 6127307            velocitySign,
 6127308            edgeSquared,
 6127309            denominator,
 6127310            radius,
 6127311            midpoint,
 6127312            SweepDoubleRawScale);
 313    }
 314
 315    private static int CompareRationalSegmentLineAt(
 316        ReadOnlySpan<ulong> startCross,
 317        int startCrossSign,
 318        ReadOnlySpan<ulong> velocity,
 319        int velocitySign,
 320        ReadOnlySpan<ulong> edgeSquared,
 321        ReadOnlySpan<ulong> denominator,
 322        Fixed64 radius,
 323        Signed192 timeNumerator,
 324        Signed192 timeDenominator)
 325    {
 6345326        Span<ulong> timeNumeratorMagnitude = stackalloc ulong[3];
 6345327        Span<ulong> timeDenominatorMagnitude = stackalloc ulong[3];
 6345328        WideArithmetic.GetMagnitude(
 6345329            timeNumerator,
 6345330            out timeNumeratorMagnitude[2],
 6345331            out timeNumeratorMagnitude[1],
 6345332            out timeNumeratorMagnitude[0]);
 6345333        WideArithmetic.GetMagnitude(
 6345334            timeDenominator,
 6345335            out timeDenominatorMagnitude[2],
 6345336            out timeDenominatorMagnitude[1],
 6345337            out timeDenominatorMagnitude[0]);
 6345338        Span<ulong> firstTerm =
 6345339            stackalloc ulong[TriangleSweepMagnitudeWords];
 6345340        Span<ulong> secondTerm =
 6345341            stackalloc ulong[TriangleSweepMagnitudeWords];
 6345342        Span<ulong> line =
 6345343            stackalloc ulong[TriangleSweepMagnitudeWords];
 6345344        WideArithmetic.MultiplyMagnitudes(
 6345345            startCross,
 6345346            timeDenominatorMagnitude,
 6345347            firstTerm);
 6345348        WideArithmetic.MultiplyMagnitudes(
 6345349            velocity,
 6345350            timeNumeratorMagnitude,
 6345351            secondTerm);
 6345352        CombineSignedMagnitudes(
 6345353            firstTerm,
 6345354            startCrossSign,
 6345355            secondTerm,
 6345356            velocitySign * timeNumerator.Sign,
 6345357            line,
 6345358            out _);
 6345359        Span<ulong> leftSquared =
 6345360            stackalloc ulong[TriangleSweepMagnitudeWords];
 6345361        WideArithmetic.MultiplyMagnitudes(line, line, leftSquared);
 362
 6345363        Span<ulong> radiusMagnitude = stackalloc ulong[1]
 6345364        {
 6345365            unchecked((ulong)radius.m_rawValue),
 6345366        };
 6345367        Span<ulong> right =
 6345368            stackalloc ulong[TriangleSweepMagnitudeWords];
 6345369        Span<ulong> scratch =
 6345370            stackalloc ulong[TriangleSweepMagnitudeWords];
 6345371        WideArithmetic.MultiplyMagnitudes(edgeSquared, denominator, right);
 6345372        WideArithmetic.MultiplyMagnitudes(right, denominator, scratch);
 6345373        WideArithmetic.MultiplyMagnitudes(scratch, radiusMagnitude, right);
 6345374        WideArithmetic.MultiplyMagnitudes(right, radiusMagnitude, scratch);
 6345375        WideArithmetic.MultiplyMagnitudes(
 6345376            scratch,
 6345377            timeDenominatorMagnitude,
 6345378            right);
 6345379        WideArithmetic.MultiplyMagnitudes(
 6345380            right,
 6345381            timeDenominatorMagnitude,
 6345382            scratch);
 6345383        return WideArithmetic.CompareMagnitudeEqualLength(leftSquared, scratch);
 384    }
 385
 386    private static bool TryGetRationalSegmentParameter(
 387        SweepRationalPoint first,
 388        SweepRationalPoint second,
 389        Signed832 edgeX,
 390        Signed832 edgeZ,
 391        ReadOnlySpan<ulong> edgeSquared,
 392        Vector2d start,
 393        Vector2d direction,
 394        Fixed64 distance,
 395        out Fixed64 parameter)
 396    {
 190397        Signed576 startX = WideArithmetic.SubtractSigned576(
 190398            WideArithmetic.MultiplySigned576(
 190399                first.Denominator,
 190400                Signed192.Raw(start.X)),
 190401            first.X);
 190402        Signed576 startZ = WideArithmetic.SubtractSigned576(
 190403            WideArithmetic.MultiplySigned576(
 190404                first.Denominator,
 190405                Signed192.Raw(start.Y)),
 190406            first.Z);
 190407        Signed576 directionX = WideArithmetic.MultiplySigned576(
 190408            first.Denominator,
 190409            Signed192.Raw(direction.X));
 190410        Signed576 directionZ = WideArithmetic.MultiplySigned576(
 190411            first.Denominator,
 190412            Signed192.Raw(direction.Y));
 190413        Signed576 scaledX = WideArithmetic.AddSigned576(
 190414            WideArithmetic.MultiplySigned576(startX, SweepRawScale),
 190415            WideArithmetic.MultiplySigned576(
 190416                directionX,
 190417                Signed192.Signed(distance.m_rawValue)));
 190418        Signed576 scaledZ = WideArithmetic.AddSigned576(
 190419            WideArithmetic.MultiplySigned576(startZ, SweepRawScale),
 190420            WideArithmetic.MultiplySigned576(
 190421                directionZ,
 190422                Signed192.Signed(distance.m_rawValue)));
 423
 190424        Span<ulong> dot = stackalloc ulong[TriangleSweepMagnitudeWords];
 190425        GetDotMagnitude(
 190426            edgeX,
 190427            edgeZ,
 190428            scaledX,
 190429            scaledZ,
 190430            dot,
 190431            out int dotSign);
 190432        if (dotSign < 0)
 433        {
 15434            parameter = default;
 15435            return false;
 436        }
 437
 175438        Span<ulong> secondDenominator = stackalloc ulong[9];
 175439        WideArithmetic.GetMagnitude(
 175440            second.Denominator,
 175441            secondDenominator);
 175442        Span<ulong> numerator =
 175443            stackalloc ulong[TriangleSweepMagnitudeWords];
 175444        WideArithmetic.MultiplyMagnitudes(dot, secondDenominator, numerator);
 175445        Span<ulong> oneMagnitude = stackalloc ulong[3];
 175446        WideArithmetic.GetMagnitude(
 175447            SweepRawScale,
 175448            out oneMagnitude[2],
 175449            out oneMagnitude[1],
 175450            out oneMagnitude[0]);
 175451        Span<ulong> denominator =
 175452            stackalloc ulong[TriangleSweepMagnitudeWords];
 175453        WideArithmetic.MultiplyMagnitudes(edgeSquared, oneMagnitude, denominator);
 175454        if (WideArithmetic.CompareMagnitudeEqualLength(numerator, denominator) > 0)
 455        {
 15456            parameter = default;
 15457            return false;
 458        }
 459
 160460        parameter = Fixed64.GetUnitIntervalRatio(
 160461            numerator,
 160462            denominator);
 160463        return true;
 464    }
 465
 466    private static void GetEdgeSquaredMagnitude(
 467        Signed832 edgeX,
 468        Signed832 edgeZ,
 469        Span<ulong> result)
 470    {
 208471        Span<ulong> x = stackalloc ulong[13];
 208472        Span<ulong> z = stackalloc ulong[13];
 208473        WideArithmetic.GetMagnitude(edgeX, x);
 208474        WideArithmetic.GetMagnitude(edgeZ, z);
 208475        Span<ulong> xSquared =
 208476            stackalloc ulong[TriangleSweepMagnitudeWords];
 208477        Span<ulong> zSquared =
 208478            stackalloc ulong[TriangleSweepMagnitudeWords];
 208479        WideArithmetic.MultiplyMagnitudes(x, x, xSquared);
 208480        WideArithmetic.MultiplyMagnitudes(z, z, zSquared);
 208481        WideArithmetic.AddEqualMagnitudes(xSquared, zSquared, result);
 208482    }
 483
 484    private static void GetCrossMagnitude(
 485        Signed832 firstX,
 486        Signed832 firstZ,
 487        Signed576 secondX,
 488        Signed576 secondZ,
 489        Span<ulong> result,
 490        out int sign)
 491    {
 208492        Span<ulong> firstXMag = stackalloc ulong[13];
 208493        Span<ulong> firstZMag = stackalloc ulong[13];
 208494        Span<ulong> secondXMag = stackalloc ulong[9];
 208495        Span<ulong> secondZMag = stackalloc ulong[9];
 208496        WideArithmetic.GetMagnitude(firstX, firstXMag);
 208497        WideArithmetic.GetMagnitude(firstZ, firstZMag);
 208498        WideArithmetic.GetMagnitude(secondX, secondXMag);
 208499        WideArithmetic.GetMagnitude(secondZ, secondZMag);
 208500        GetCrossMagnitude(
 208501            firstXMag,
 208502            firstX.Sign,
 208503            firstZMag,
 208504            firstZ.Sign,
 208505            secondXMag,
 208506            secondX.Sign,
 208507            secondZMag,
 208508            secondZ.Sign,
 208509            result,
 208510            out sign);
 208511    }
 512
 513    private static void GetCrossMagnitude(
 514        Signed832 firstX,
 515        Signed832 firstZ,
 516        Signed192 secondX,
 517        Signed192 secondZ,
 518        Span<ulong> result,
 519        out int sign)
 520    {
 208521        Span<ulong> firstXMag = stackalloc ulong[13];
 208522        Span<ulong> firstZMag = stackalloc ulong[13];
 208523        Span<ulong> secondXMag = stackalloc ulong[3];
 208524        Span<ulong> secondZMag = stackalloc ulong[3];
 208525        WideArithmetic.GetMagnitude(firstX, firstXMag);
 208526        WideArithmetic.GetMagnitude(firstZ, firstZMag);
 208527        WideArithmetic.GetMagnitude(
 208528            secondX,
 208529            out secondXMag[2],
 208530            out secondXMag[1],
 208531            out secondXMag[0]);
 208532        WideArithmetic.GetMagnitude(
 208533            secondZ,
 208534            out secondZMag[2],
 208535            out secondZMag[1],
 208536            out secondZMag[0]);
 208537        GetCrossMagnitude(
 208538            firstXMag,
 208539            firstX.Sign,
 208540            firstZMag,
 208541            firstZ.Sign,
 208542            secondXMag,
 208543            secondX.Sign,
 208544            secondZMag,
 208545            secondZ.Sign,
 208546            result,
 208547            out sign);
 208548    }
 549
 550    private static void GetCrossMagnitude(
 551        ReadOnlySpan<ulong> firstX,
 552        int firstXSign,
 553        ReadOnlySpan<ulong> firstZ,
 554        int firstZSign,
 555        ReadOnlySpan<ulong> secondX,
 556        int secondXSign,
 557        ReadOnlySpan<ulong> secondZ,
 558        int secondZSign,
 559        Span<ulong> result,
 560        out int sign)
 561    {
 416562        Span<ulong> firstTerm =
 416563            stackalloc ulong[TriangleSweepMagnitudeWords];
 416564        Span<ulong> secondTerm =
 416565            stackalloc ulong[TriangleSweepMagnitudeWords];
 416566        WideArithmetic.MultiplyMagnitudes(firstX, secondZ, firstTerm);
 416567        WideArithmetic.MultiplyMagnitudes(firstZ, secondX, secondTerm);
 416568        CombineSignedMagnitudes(
 416569            firstTerm,
 416570            firstXSign * secondZSign,
 416571            secondTerm,
 416572            -(firstZSign * secondXSign),
 416573            result,
 416574            out sign);
 416575    }
 576
 577    private static void GetDotMagnitude(
 578        Signed832 firstX,
 579        Signed832 firstZ,
 580        Signed576 secondX,
 581        Signed576 secondZ,
 582        Span<ulong> result,
 583        out int sign)
 584    {
 190585        Span<ulong> firstXMag = stackalloc ulong[13];
 190586        Span<ulong> firstZMag = stackalloc ulong[13];
 190587        Span<ulong> secondXMag = stackalloc ulong[9];
 190588        Span<ulong> secondZMag = stackalloc ulong[9];
 190589        WideArithmetic.GetMagnitude(firstX, firstXMag);
 190590        WideArithmetic.GetMagnitude(firstZ, firstZMag);
 190591        WideArithmetic.GetMagnitude(secondX, secondXMag);
 190592        WideArithmetic.GetMagnitude(secondZ, secondZMag);
 190593        Span<ulong> firstTerm =
 190594            stackalloc ulong[TriangleSweepMagnitudeWords];
 190595        Span<ulong> secondTerm =
 190596            stackalloc ulong[TriangleSweepMagnitudeWords];
 190597        WideArithmetic.MultiplyMagnitudes(firstXMag, secondXMag, firstTerm);
 190598        WideArithmetic.MultiplyMagnitudes(firstZMag, secondZMag, secondTerm);
 190599        CombineSignedMagnitudes(
 190600            firstTerm,
 190601            firstX.Sign * secondX.Sign,
 190602            secondTerm,
 190603            firstZ.Sign * secondZ.Sign,
 190604            result,
 190605            out sign);
 190606    }
 607
 608    private static void CombineSignedMagnitudes(
 609        ReadOnlySpan<ulong> first,
 610        int firstSign,
 611        ReadOnlySpan<ulong> second,
 612        int secondSign,
 613        Span<ulong> result,
 614        out int sign)
 615    {
 11403616        if (firstSign == 0)
 617        {
 1106618            CopyMagnitude(second, result);
 1106619            sign = secondSign;
 1106620            return;
 621        }
 10297622        if (secondSign == 0)
 623        {
 1618624            CopyMagnitude(first, result);
 1618625            sign = firstSign;
 1618626            return;
 627        }
 8679628        if (firstSign == secondSign)
 629        {
 312630            WideArithmetic.AddEqualMagnitudes(first, second, result);
 312631            sign = firstSign;
 312632            return;
 633        }
 634
 8367635        int comparison = WideArithmetic.CompareMagnitudeEqualLength(first, second);
 8367636        if (comparison == 0)
 637        {
 826638            result.Clear();
 826639            sign = 0;
 826640            return;
 641        }
 7541642        if (comparison > 0)
 643        {
 7087644            WideArithmetic.SubtractEqualMagnitudes(first, second, result);
 7087645            sign = firstSign;
 7087646            return;
 647        }
 648
 454649        WideArithmetic.SubtractEqualMagnitudes(second, first, result);
 454650        sign = secondSign;
 454651    }
 652
 653    private static void CopyMagnitude(
 654        ReadOnlySpan<ulong> source,
 655        Span<ulong> destination)
 656    {
 2724657        destination.Clear();
 2724658        source[..Math.Min(source.Length, destination.Length)]
 2724659            .CopyTo(destination);
 2724660    }
 661
 662}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Ray.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.Ray.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
 8namespace FixedMathSharp.Geometry;
 9
 10/// <content>
 11/// Wide-oriented box ray intersection operations.
 12/// </content>
 13internal static partial class WideOrientedBox
 14{
 15    #region Nested Types
 16
 17    private readonly struct RayBound
 18    {
 19        internal readonly Signed320 Numerator;
 20        internal readonly Signed320 Denominator;
 21
 22        internal RayBound(
 23            Signed320 numerator,
 24            Signed320 denominator)
 25        {
 4226            Numerator = numerator;
 4227            Denominator = denominator;
 4228        }
 29    }
 30
 31    #endregion
 32
 33    internal static bool TryGetRayIntersectionInterval(
 34        Vector3d center,
 35        FixedQuaternion orientation,
 36        Vector3d halfExtents,
 37        Vector3d rayOrigin,
 38        Vector3d rayDirection,
 39        Fixed64 maxParameter,
 40        out Fixed64 entry,
 41        out Fixed64 exit)
 42    {
 1143        WideRationalBasis3d basis = new(orientation);
 1144        GetPointProjections(
 1145            rayOrigin,
 1146            center,
 1147            basis,
 1148            out Signed320 originX,
 1149            out Signed320 originY,
 1150            out Signed320 originZ);
 1151        GetDirectionProjections(
 1152            rayDirection,
 1153            basis,
 1154            out Signed320 directionX,
 1155            out Signed320 directionY,
 1156            out Signed320 directionZ);
 1157        Signed192 narrowOriginX = Signed192.NarrowValue(originX);
 1158        Signed192 narrowOriginY = Signed192.NarrowValue(originY);
 1159        Signed192 narrowOriginZ = Signed192.NarrowValue(originZ);
 1160        Signed192 narrowDirectionX = Signed192.NarrowValue(directionX);
 1161        Signed192 narrowDirectionY = Signed192.NarrowValue(directionY);
 1162        Signed192 narrowDirectionZ = Signed192.NarrowValue(directionZ);
 1163        Signed192 extentX = Signed192.NarrowValue(
 1164            GetExtentNumerator(halfExtents.X, basis.Denominator));
 1165        Signed192 extentY = Signed192.NarrowValue(
 1166            GetExtentNumerator(halfExtents.Y, basis.Denominator));
 1167        Signed192 extentZ = Signed192.NarrowValue(
 1168            GetExtentNumerator(halfExtents.Z, basis.Denominator));
 69
 1170        Signed320 one = Signed320.ExtendValue(
 1171            Signed192.Raw(Fixed64.MinIncrement));
 1172        var lower = new RayBound(default, one);
 1173        var upper = new RayBound(
 1174            Signed320.ExtendValue(Signed192.Raw(maxParameter)),
 1175            one);
 1176        if (!TryClipRayAxis(
 1177                narrowOriginX,
 1178                narrowDirectionX,
 1179                extentX,
 1180                ref lower,
 1181                ref upper)
 1182            || !TryClipRayAxis(
 1183                narrowOriginY,
 1184                narrowDirectionY,
 1185                extentY,
 1186                ref lower,
 1187                ref upper)
 1188            || !TryClipRayAxis(
 1189                narrowOriginZ,
 1190                narrowDirectionZ,
 1191                extentZ,
 1192                ref lower,
 1193                ref upper))
 94        {
 695            entry = default;
 696            exit = default;
 697            return false;
 98        }
 99
 5100        entry = RoundRayBound(lower);
 5101        exit = RoundRayBound(upper);
 5102        return true;
 103    }
 104
 105    private static bool TryClipRayAxis(
 106        Signed192 origin,
 107        Signed192 direction,
 108        Signed192 extent,
 109        ref RayBound lower,
 110        ref RayBound upper)
 111    {
 25112        Signed192 minimum = WideArithmetic.SubtractSigned192(
 25113            default,
 25114            extent);
 25115        if (direction.IsZero)
 116        {
 15117            return WideArithmetic.SubtractSigned192(
 15118                    origin,
 15119                    minimum).Sign >= 0
 15120                && WideArithmetic.SubtractSigned192(
 15121                    origin,
 15122                    extent).Sign <= 0;
 123        }
 124
 10125        RayBound first = NormalizeRayBound(
 10126            WideArithmetic.SubtractSigned192(minimum, origin),
 10127            direction);
 10128        RayBound second = NormalizeRayBound(
 10129            WideArithmetic.SubtractSigned192(extent, origin),
 10130            direction);
 10131        if (CompareRayBounds(first, second) > 0)
 1132            (first, second) = (second, first);
 10133        if (CompareRayBounds(second, lower) < 0
 10134            || CompareRayBounds(first, upper) > 0)
 135        {
 2136            return false;
 137        }
 138
 8139        if (CompareRayBounds(first, lower) > 0)
 5140            lower = first;
 8141        if (CompareRayBounds(second, upper) < 0)
 6142            upper = second;
 8143        return CompareRayBounds(lower, upper) <= 0;
 144    }
 145
 146    private static RayBound NormalizeRayBound(
 147        Signed192 numerator,
 148        Signed192 denominator)
 149    {
 20150        Signed320 scaledNumerator = WideArithmetic.MultiplySigned192(
 20151            numerator,
 20152            Signed192.One);
 20153        Signed320 wideDenominator =
 20154            Signed320.ExtendValue(denominator);
 20155        if (denominator.Sign >= 0)
 18156            return new RayBound(scaledNumerator, wideDenominator);
 157
 2158        return new RayBound(
 2159            WideArithmetic.SubtractSigned320(default, scaledNumerator),
 2160            WideArithmetic.SubtractSigned320(default, wideDenominator));
 161    }
 162
 163    private static int CompareRayBounds(RayBound left, RayBound right) =>
 53164        WideArithmetic.SubtractSigned576(
 53165            WideArithmetic.MultiplySigned320(
 53166                left.Numerator,
 53167                right.Denominator),
 53168            WideArithmetic.MultiplySigned320(
 53169                right.Numerator,
 53170                left.Denominator)).Sign;
 171
 172    private static Fixed64 RoundRayBound(RayBound bound)
 173    {
 174        // Clipping keeps both bounds inside [0, maxParameter], so the quotient
 175        // is representable and each normalized denominator is positive.
 10176        _ = Fixed64.TryGetSignedRawRatio(
 10177            Signed576.ExtendValue(bound.Numerator),
 10178            Signed576.ExtendValue(bound.Denominator),
 10179            out Fixed64 value);
 10180        return value;
 181    }
 182}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RelativeBounds.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.RelativeBounds.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
 8namespace FixedMathSharp.Geometry;
 9
 10/// <content>
 11/// Computes the relative axis-aligned bounds of one oriented box's local extents
 12/// within another oriented box's coordinate space, using wide (extended-precision)
 13/// arithmetic and clipping results to the valid <see cref="Fixed64"/> domain.
 14/// </content>
 15internal static partial class WideOrientedBox
 16{
 17    internal static FixedBoundBox GetRelativeRotatedBoundsClippedToDomain(
 18        Vector3d sourceOrigin,
 19        FixedQuaternion sourceRotation,
 20        Vector3d sourceLocalMin,
 21        Vector3d sourceLocalMax,
 22        Vector3d targetOrigin,
 23        FixedQuaternion targetRotation)
 24    {
 7025        Vector3d normalizedMinimum =
 7026            Vector3d.Min(sourceLocalMin, sourceLocalMax);
 7027        sourceLocalMax = Vector3d.Max(sourceLocalMin, sourceLocalMax);
 7028        sourceLocalMin = normalizedMinimum;
 7029        WideRationalBasis3d sourceBasis = new(sourceRotation);
 7030        WideRationalBasis3d targetBasis = new(targetRotation);
 7031        Signed320 denominator = WideArithmetic.MultiplySigned192(
 7032            sourceBasis.Denominator,
 7033            targetBasis.Denominator);
 7034        Signed192 deltaX = WideArithmetic.SubtractSigned192(
 7035            Signed192.Raw(sourceOrigin.X),
 7036            Signed192.Raw(targetOrigin.X));
 7037        Signed192 deltaY = WideArithmetic.SubtractSigned192(
 7038            Signed192.Raw(sourceOrigin.Y),
 7039            Signed192.Raw(targetOrigin.Y));
 7040        Signed192 deltaZ = WideArithmetic.SubtractSigned192(
 7041            Signed192.Raw(sourceOrigin.Z),
 7042            Signed192.Raw(targetOrigin.Z));
 43
 7044        GetRelativeBoundsCoordinate(
 7045            sourceBasis,
 7046            targetBasis.Xx,
 7047            targetBasis.Xy,
 7048            targetBasis.Xz,
 7049            sourceLocalMin,
 7050            sourceLocalMax,
 7051            deltaX,
 7052            deltaY,
 7053            deltaZ,
 7054            denominator,
 7055            out Fixed64 minX,
 7056            out Fixed64 maxX);
 7057        GetRelativeBoundsCoordinate(
 7058            sourceBasis,
 7059            targetBasis.Yx,
 7060            targetBasis.Yy,
 7061            targetBasis.Yz,
 7062            sourceLocalMin,
 7063            sourceLocalMax,
 7064            deltaX,
 7065            deltaY,
 7066            deltaZ,
 7067            denominator,
 7068            out Fixed64 minY,
 7069            out Fixed64 maxY);
 7070        GetRelativeBoundsCoordinate(
 7071            sourceBasis,
 7072            targetBasis.Zx,
 7073            targetBasis.Zy,
 7074            targetBasis.Zz,
 7075            sourceLocalMin,
 7076            sourceLocalMax,
 7077            deltaX,
 7078            deltaY,
 7079            deltaZ,
 7080            denominator,
 7081            out Fixed64 minZ,
 7082            out Fixed64 maxZ);
 7083        return FixedBoundBox.FromMinMax(
 7084            new Vector3d(minX, minY, minZ),
 7085            new Vector3d(maxX, maxY, maxZ));
 86    }
 87
 88    private static void GetRelativeBoundsCoordinate(
 89        WideRationalBasis3d sourceBasis,
 90        Signed192 targetAxisX,
 91        Signed192 targetAxisY,
 92        Signed192 targetAxisZ,
 93        Vector3d sourceLocalMin,
 94        Vector3d sourceLocalMax,
 95        Signed192 deltaX,
 96        Signed192 deltaY,
 97        Signed192 deltaZ,
 98        Signed320 denominator,
 99        out Fixed64 minimum,
 100        out Fixed64 maximum)
 101    {
 210102        Signed320 sourceXCoefficient = WideArithmetic.GetDotProduct3D(
 210103            targetAxisX,
 210104            targetAxisY,
 210105            targetAxisZ,
 210106            sourceBasis.Xx,
 210107            sourceBasis.Xy,
 210108            sourceBasis.Xz);
 210109        Signed320 sourceYCoefficient = WideArithmetic.GetDotProduct3D(
 210110            targetAxisX,
 210111            targetAxisY,
 210112            targetAxisZ,
 210113            sourceBasis.Yx,
 210114            sourceBasis.Yy,
 210115            sourceBasis.Yz);
 210116        Signed320 sourceZCoefficient = WideArithmetic.GetDotProduct3D(
 210117            targetAxisX,
 210118            targetAxisY,
 210119            targetAxisZ,
 210120            sourceBasis.Zx,
 210121            sourceBasis.Zy,
 210122            sourceBasis.Zz);
 210123        Signed320 translatedProjection = WideArithmetic.AddSigned320(
 210124            WideArithmetic.AddSigned320(
 210125                WideArithmetic.MultiplySigned192(deltaX, targetAxisX),
 210126                WideArithmetic.MultiplySigned192(deltaY, targetAxisY)),
 210127            WideArithmetic.MultiplySigned192(deltaZ, targetAxisZ));
 210128        Signed576 translatedNumerator = WideArithmetic.MultiplySigned320(
 210129            translatedProjection,
 210130            Signed320.ExtendValue(sourceBasis.Denominator));
 131
 210132        Signed576 minimumNumerator = GetRelativeEndpointNumerator(
 210133            translatedNumerator,
 210134            sourceXCoefficient,
 210135            sourceYCoefficient,
 210136            sourceZCoefficient,
 210137            sourceLocalMin,
 210138            sourceLocalMax,
 210139            true);
 210140        Signed576 maximumNumerator = GetRelativeEndpointNumerator(
 210141            translatedNumerator,
 210142            sourceXCoefficient,
 210143            sourceYCoefficient,
 210144            sourceZCoefficient,
 210145            sourceLocalMin,
 210146            sourceLocalMax,
 210147            false);
 210148        minimum = GetRelativeEndpointClippedToDomain(
 210149            minimumNumerator,
 210150            denominator,
 210151            true);
 210152        maximum = GetRelativeEndpointClippedToDomain(
 210153            maximumNumerator,
 210154            denominator,
 210155            false);
 210156    }
 157
 158    private static Signed576 GetRelativeEndpointNumerator(
 159        Signed576 translatedNumerator,
 160        Signed320 sourceXCoefficient,
 161        Signed320 sourceYCoefficient,
 162        Signed320 sourceZCoefficient,
 163        Vector3d sourceLocalMin,
 164        Vector3d sourceLocalMax,
 165        bool minimum)
 166    {
 420167        Fixed64 x = SelectEndpoint(
 420168            sourceXCoefficient,
 420169            sourceLocalMin.X,
 420170            sourceLocalMax.X,
 420171            minimum);
 420172        Fixed64 y = SelectEndpoint(
 420173            sourceYCoefficient,
 420174            sourceLocalMin.Y,
 420175            sourceLocalMax.Y,
 420176            minimum);
 420177        Fixed64 z = SelectEndpoint(
 420178            sourceZCoefficient,
 420179            sourceLocalMin.Z,
 420180            sourceLocalMax.Z,
 420181            minimum);
 420182        return WideArithmetic.AddSigned576(
 420183            WideArithmetic.AddSigned576(
 420184                WideArithmetic.AddSigned576(
 420185                    translatedNumerator,
 420186                    WideArithmetic.MultiplySigned320(
 420187                        sourceXCoefficient,
 420188                        Signed320.ExtendValue(Signed192.Raw(x)))),
 420189                WideArithmetic.MultiplySigned320(
 420190                    sourceYCoefficient,
 420191                    Signed320.ExtendValue(Signed192.Raw(y)))),
 420192            WideArithmetic.MultiplySigned320(
 420193                sourceZCoefficient,
 420194                Signed320.ExtendValue(Signed192.Raw(z))));
 195    }
 196
 197    private static Fixed64 SelectEndpoint(
 198        Signed320 coefficient,
 199        Fixed64 minimum,
 200        Fixed64 maximum,
 201        bool lower) =>
 1260202        (coefficient.Sign < 0) == lower ? maximum : minimum;
 203
 204    private static Fixed64 GetRelativeEndpointClippedToDomain(
 205        Signed576 numerator,
 206        Signed320 denominator,
 207        bool minimum)
 208    {
 420209        Signed576 minimumNumerator = WideArithmetic.MultiplySigned320(
 420210            Signed320.ExtendValue(Signed192.Raw(Fixed64.MinValue)),
 420211            denominator);
 420212        Signed576 maximumNumerator = WideArithmetic.MultiplySigned320(
 420213            Signed320.ExtendValue(Signed192.Raw(Fixed64.MaxValue)),
 420214            denominator);
 420215        if (CompareSigned(numerator, minimumNumerator) <= 0)
 1216            return Fixed64.MinValue;
 419217        if (CompareSigned(numerator, maximumNumerator) >= 0)
 2218            return Fixed64.MaxValue;
 219
 417220        _ = Fixed64.TryGetSignedRawRatio(
 417221            numerator,
 417222            Signed576.ExtendValue(denominator),
 417223            out Fixed64 endpoint);
 417224        Signed576 roundedNumerator = WideArithmetic.MultiplySigned320(
 417225            Signed320.ExtendValue(Signed192.Raw(endpoint)),
 417226            denominator);
 417227        int comparison = CompareSigned(roundedNumerator, numerator);
 417228        if (minimum && comparison > 0)
 132229            return Fixed64.FromRaw(endpoint.m_rawValue - 1L);
 285230        if (!minimum && comparison < 0)
 67231            return Fixed64.FromRaw(endpoint.m_rawValue + 1L);
 218232        return endpoint;
 233    }
 234
 235}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RigidAxisRelations.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.RigidAxisRelations.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 (wide arithmetic) computations for rigid axis relations,
 14/// including capsule overlap tests based on rotated local axes and segment distances.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    #region Nested Types
 19
 20    private readonly struct RigidSegmentAxis
 21    {
 22        internal readonly Signed320 X;
 23        internal readonly Signed320 Y;
 24        internal readonly Signed320 Z;
 25        internal readonly Signed320 Denominator;
 26
 27        internal RigidSegmentAxis(
 28            Signed192 x,
 29            Signed192 y,
 30            Signed192 z,
 31            Signed192 rotationDenominator,
 32            Fixed64 length)
 33        {
 180834            Signed192 rawLength = Signed192.Raw(length);
 180835            X = WideArithmetic.MultiplySigned192(x, rawLength);
 180836            Y = WideArithmetic.MultiplySigned192(y, rawLength);
 180837            Z = WideArithmetic.MultiplySigned192(z, rawLength);
 180838            Denominator = WideArithmetic.MultiplySigned192(
 180839                rotationDenominator,
 180840                Signed192.One);
 180841        }
 42    }
 43
 44    #endregion
 45
 46    internal static bool DoCenteredRigidCapsulesOverlap(
 47        Vector3d firstCenter,
 48        FixedQuaternion firstRotation,
 49        Vector3d firstLocalAxis,
 50        Fixed64 firstLength,
 51        Fixed64 firstRadius,
 52        Vector3d secondCenter,
 53        FixedQuaternion secondRotation,
 54        Vector3d secondLocalAxis,
 55        Fixed64 secondLength,
 56        Fixed64 secondRadius)
 57    {
 3258        GetRotatedLocalAxisNumerators(
 3259            firstRotation,
 3260            firstLocalAxis,
 3261            out Signed192 firstAxisX,
 3262            out Signed192 firstAxisY,
 3263            out Signed192 firstAxisZ,
 3264            out Signed192 firstRotationDenominator);
 3265        GetRotatedLocalAxisNumerators(
 3266            secondRotation,
 3267            secondLocalAxis,
 3268            out Signed192 secondAxisX,
 3269            out Signed192 secondAxisY,
 3270            out Signed192 secondAxisZ,
 3271            out Signed192 secondRotationDenominator);
 72
 3273        var firstAxis = new RigidSegmentAxis(
 3274            firstAxisX,
 3275            firstAxisY,
 3276            firstAxisZ,
 3277            firstRotationDenominator,
 3278            firstLength);
 3279        var secondAxis = new RigidSegmentAxis(
 3280            secondAxisX,
 3281            secondAxisY,
 3282            secondAxisZ,
 3283            secondRotationDenominator,
 3284            secondLength);
 3285        Signed576 relationDenominator = WideArithmetic.AddSigned576(
 3286            WideArithmetic.MultiplySigned320(
 3287                firstAxis.Denominator,
 3288                secondAxis.Denominator),
 3289            WideArithmetic.MultiplySigned320(
 3290                firstAxis.Denominator,
 3291                secondAxis.Denominator));
 3292        GetRigidSegmentLowerDifference(
 3293            firstCenter,
 3294            firstAxis,
 3295            secondCenter,
 3296            secondAxis,
 3297            relationDenominator,
 3298            out Signed576 relationX,
 3299            out Signed576 relationY,
 32100            out Signed576 relationZ);
 101
 32102        Signed576 firstSquared = Dot(firstAxis, firstAxis);
 32103        Signed576 directionsDot = Dot(firstAxis, secondAxis);
 32104        Signed576 secondSquared = Dot(secondAxis, secondAxis);
 32105        Signed704 firstDotDifference = Dot(
 32106            firstAxis,
 32107            relationX,
 32108            relationY,
 32109            relationZ);
 32110        Signed704 secondDotDifference = Dot(
 32111            secondAxis,
 32112            relationX,
 32113            relationY,
 32114            relationZ);
 115
 32116        Span<ulong> determinant = stackalloc ulong[TriangleSweepMagnitudeWords];
 32117        GetProductDifference(
 32118            firstSquared,
 32119            secondSquared,
 32120            directionsDot,
 32121            directionsDot,
 32122            determinant,
 32123            out int determinantSign);
 124
 32125        Span<ulong> firstNumerator = stackalloc ulong[TriangleSweepMagnitudeWords];
 32126        Span<ulong> firstDenominator = stackalloc ulong[TriangleSweepMagnitudeWords];
 32127        Span<ulong> secondNumerator = stackalloc ulong[TriangleSweepMagnitudeWords];
 32128        Span<ulong> secondDenominator = stackalloc ulong[TriangleSweepMagnitudeWords];
 129        int firstNumeratorSign;
 130        int secondNumeratorSign;
 131        int firstFeature;
 132        int secondFeature;
 32133        if (determinantSign > 0)
 134        {
 18135            Span<ulong> firstCore = stackalloc ulong[TriangleSweepMagnitudeWords];
 18136            GetProductDifference(
 18137                directionsDot,
 18138                secondDotDifference,
 18139                secondSquared,
 18140                firstDotDifference,
 18141                firstCore,
 18142                out int firstCoreSign);
 18143            SetRigidSegmentRatio(
 18144                firstCore,
 18145                firstAxis.Denominator,
 18146                determinant,
 18147                relationDenominator,
 18148                firstNumerator,
 18149                firstDenominator);
 18150            firstNumeratorSign = firstCoreSign;
 18151            firstFeature = ClampUnitRatio(
 18152                firstNumerator,
 18153                firstDenominator,
 18154                firstNumeratorSign);
 155
 18156            if (firstFeature == RigidSegmentLower)
 157            {
 6158                SetRigidSegmentProjectionRatio(
 6159                    secondDotDifference,
 6160                    secondAxis.Denominator,
 6161                    secondSquared,
 6162                    relationDenominator,
 6163                    secondNumerator,
 6164                    secondDenominator);
 6165                secondNumeratorSign = secondDotDifference.Sign;
 166            }
 12167            else if (firstFeature == RigidSegmentUpper)
 168            {
 6169                Signed704 upperProjection = WideArithmetic.AddSigned704(
 6170                    secondDotDifference,
 6171                    DoubleProduct(
 6172                        directionsDot,
 6173                        secondAxis.Denominator));
 6174                SetRigidSegmentProjectionRatio(
 6175                    upperProjection,
 6176                    secondAxis.Denominator,
 6177                    secondSquared,
 6178                    relationDenominator,
 6179                    secondNumerator,
 6180                    secondDenominator);
 6181                secondNumeratorSign = upperProjection.Sign;
 182            }
 183            else
 184            {
 6185                Span<ulong> secondCore = stackalloc ulong[TriangleSweepMagnitudeWords];
 6186                GetProductDifference(
 6187                    firstSquared,
 6188                    secondDotDifference,
 6189                    directionsDot,
 6190                    firstDotDifference,
 6191                    secondCore,
 6192                    out int secondCoreSign);
 6193                SetRigidSegmentRatio(
 6194                    secondCore,
 6195                    secondAxis.Denominator,
 6196                    determinant,
 6197                    relationDenominator,
 6198                    secondNumerator,
 6199                    secondDenominator);
 6200                secondNumeratorSign = secondCoreSign;
 201            }
 202        }
 203        else
 204        {
 14205            firstNumerator.Clear();
 14206            firstDenominator.Clear();
 14207            firstDenominator[0] = 1UL;
 14208            firstNumeratorSign = 0;
 14209            firstFeature = RigidSegmentLower;
 14210            SetRigidSegmentProjectionRatio(
 14211                secondDotDifference,
 14212                secondAxis.Denominator,
 14213                secondSquared,
 14214                relationDenominator,
 14215                secondNumerator,
 14216                secondDenominator);
 14217            secondNumeratorSign = secondDotDifference.Sign;
 218        }
 219
 32220        secondFeature = ClampUnitRatio(
 32221            secondNumerator,
 32222            secondDenominator,
 32223            secondNumeratorSign);
 32224        if (secondFeature == RigidSegmentLower)
 225        {
 19226            SetRigidSegmentProjectionRatio(
 19227                WideArithmetic.SubtractSigned704(
 19228                    default,
 19229                    firstDotDifference),
 19230                firstAxis.Denominator,
 19231                firstSquared,
 19232                relationDenominator,
 19233                firstNumerator,
 19234                firstDenominator);
 19235            firstNumeratorSign = -firstDotDifference.Sign;
 19236            firstFeature = ClampUnitRatio(
 19237                firstNumerator,
 19238                firstDenominator,
 19239                firstNumeratorSign);
 240        }
 13241        else if (secondFeature == RigidSegmentUpper)
 242        {
 6243            Signed704 upperProjection = WideArithmetic.SubtractSigned704(
 6244                DoubleProduct(
 6245                    directionsDot,
 6246                    firstAxis.Denominator),
 6247                firstDotDifference);
 6248            SetRigidSegmentProjectionRatio(
 6249                upperProjection,
 6250                firstAxis.Denominator,
 6251                firstSquared,
 6252                relationDenominator,
 6253                firstNumerator,
 6254                firstDenominator);
 6255            firstNumeratorSign = upperProjection.Sign;
 6256            firstFeature = ClampUnitRatio(
 6257                firstNumerator,
 6258                firstDenominator,
 6259                firstNumeratorSign);
 260        }
 261
 32262        if (firstFeature == RigidSegmentUpper)
 263        {
 6264            AddRigidSegmentDisplacement(
 6265                ref relationX,
 6266                firstAxis.X,
 6267                secondAxis.Denominator);
 6268            AddRigidSegmentDisplacement(
 6269                ref relationY,
 6270                firstAxis.Y,
 6271                secondAxis.Denominator);
 6272            AddRigidSegmentDisplacement(
 6273                ref relationZ,
 6274                firstAxis.Z,
 6275                secondAxis.Denominator);
 276        }
 32277        if (secondFeature == RigidSegmentUpper)
 278        {
 6279            SubtractRigidSegmentDisplacement(
 6280                ref relationX,
 6281                secondAxis.X,
 6282                firstAxis.Denominator);
 6283            SubtractRigidSegmentDisplacement(
 6284                ref relationY,
 6285                secondAxis.Y,
 6286                firstAxis.Denominator);
 6287            SubtractRigidSegmentDisplacement(
 6288                ref relationZ,
 6289                secondAxis.Z,
 6290                firstAxis.Denominator);
 291        }
 292
 32293        Signed192 combinedRadius = WideArithmetic.AddSigned192(
 32294            Signed192.Raw(firstRadius),
 32295            Signed192.Raw(secondRadius));
 32296        if (firstFeature == RigidSegmentInterior
 32297            && secondFeature == RigidSegmentInterior)
 298        {
 2299            return IsRigidLinePairWithinRadius(
 2300                relationX,
 2301                relationY,
 2302                relationZ,
 2303                firstSquared,
 2304                directionsDot,
 2305                secondSquared,
 2306                firstDotDifference,
 2307                secondDotDifference,
 2308                determinant,
 2309                relationDenominator,
 2310                combinedRadius);
 311        }
 30312        if (firstFeature == RigidSegmentInterior)
 313        {
 7314            Signed704 adjustedDot = Dot(
 7315                firstAxis,
 7316                relationX,
 7317                relationY,
 7318                relationZ);
 7319            return IsRigidPointLineWithinRadius(
 7320                relationX,
 7321                relationY,
 7322                relationZ,
 7323                firstSquared,
 7324                adjustedDot,
 7325                relationDenominator,
 7326                combinedRadius);
 327        }
 23328        if (secondFeature == RigidSegmentInterior)
 329        {
 5330            Signed704 adjustedDot = Dot(
 5331                secondAxis,
 5332                relationX,
 5333                relationY,
 5334                relationZ);
 5335            return IsRigidPointLineWithinRadius(
 5336                relationX,
 5337                relationY,
 5338                relationZ,
 5339                secondSquared,
 5340                adjustedDot,
 5341                relationDenominator,
 5342                combinedRadius);
 343        }
 344
 18345        return IsRigidPointWithinRadius(
 18346            relationX,
 18347            relationY,
 18348            relationZ,
 18349            relationDenominator,
 18350            combinedRadius);
 351    }
 352
 353    private const int RigidSegmentLower = -1;
 354    private const int RigidSegmentInterior = 0;
 355    private const int RigidSegmentUpper = 1;
 356
 357    private static int ClampUnitRatio(
 358        Span<ulong> numerator,
 359        Span<ulong> denominator,
 360        int numeratorSign)
 361    {
 2049362        if (numeratorSign <= 0)
 363        {
 703364            numerator.Clear();
 703365            denominator.Clear();
 703366            denominator[0] = 1UL;
 703367            return RigidSegmentLower;
 368        }
 369
 1346370        int comparison = WideArithmetic.CompareMagnitudeEqualLength(numerator, denominator);
 1346371        if (comparison < 0)
 1031372            return RigidSegmentInterior;
 373
 315374        denominator.CopyTo(numerator);
 315375        return RigidSegmentUpper;
 376    }
 377
 378    private static void SetRigidSegmentRatio(
 379        ReadOnlySpan<ulong> core,
 380        Signed320 axisDenominator,
 381        ReadOnlySpan<ulong> determinant,
 382        Signed576 relationDenominator,
 383        Span<ulong> numerator,
 384        Span<ulong> denominator)
 385    {
 967386        Span<ulong> axisDenominatorMagnitude = stackalloc ulong[5];
 967387        WideArithmetic.GetMagnitude(
 967388            axisDenominator,
 967389            out axisDenominatorMagnitude[4],
 967390            out axisDenominatorMagnitude[3],
 967391            out axisDenominatorMagnitude[2],
 967392            out axisDenominatorMagnitude[1],
 967393            out axisDenominatorMagnitude[0]);
 967394        WideArithmetic.MultiplyMagnitudes(core, axisDenominatorMagnitude, numerator);
 395
 967396        Span<ulong> relationDenominatorMagnitude = stackalloc ulong[9];
 967397        WideArithmetic.GetMagnitude(
 967398            relationDenominator,
 967399            relationDenominatorMagnitude);
 967400        WideArithmetic.MultiplyMagnitudes(
 967401            determinant,
 967402            relationDenominatorMagnitude,
 967403            denominator);
 967404    }
 405
 406    private static void SetRigidSegmentProjectionRatio(
 407        Signed704 projection,
 408        Signed320 axisDenominator,
 409        Signed576 axisSquared,
 410        Signed576 relationDenominator,
 411        Span<ulong> numerator,
 412        Span<ulong> denominator)
 413    {
 1082414        Span<ulong> projectionMagnitude = stackalloc ulong[11];
 1082415        Span<ulong> axisDenominatorMagnitude = stackalloc ulong[5];
 1082416        Span<ulong> axisSquaredMagnitude = stackalloc ulong[9];
 1082417        Span<ulong> relationDenominatorMagnitude = stackalloc ulong[9];
 1082418        WideArithmetic.GetMagnitude(projection, projectionMagnitude);
 1082419        WideArithmetic.GetMagnitude(
 1082420            axisDenominator,
 1082421            out axisDenominatorMagnitude[4],
 1082422            out axisDenominatorMagnitude[3],
 1082423            out axisDenominatorMagnitude[2],
 1082424            out axisDenominatorMagnitude[1],
 1082425            out axisDenominatorMagnitude[0]);
 1082426        WideArithmetic.GetMagnitude(axisSquared, axisSquaredMagnitude);
 1082427        WideArithmetic.GetMagnitude(
 1082428            relationDenominator,
 1082429            relationDenominatorMagnitude);
 1082430        WideArithmetic.MultiplyMagnitudes(
 1082431            projectionMagnitude,
 1082432            axisDenominatorMagnitude,
 1082433            numerator);
 1082434        WideArithmetic.MultiplyMagnitudes(
 1082435            axisSquaredMagnitude,
 1082436            relationDenominatorMagnitude,
 1082437            denominator);
 1082438    }
 439
 440    private static bool IsRigidLinePairWithinRadius(
 441        Signed576 relationX,
 442        Signed576 relationY,
 443        Signed576 relationZ,
 444        Signed576 firstSquared,
 445        Signed576 directionsDot,
 446        Signed576 secondSquared,
 447        Signed704 firstDotDifference,
 448        Signed704 secondDotDifference,
 449        ReadOnlySpan<ulong> determinant,
 450        Signed576 relationDenominator,
 451        Signed192 radius)
 452    {
 2453        Span<ulong> relationSquared = stackalloc ulong[13];
 2454        GetSquaredMagnitude(
 2455            relationX,
 2456            relationY,
 2457            relationZ,
 2458            relationSquared);
 2459        Span<ulong> relationTerm = stackalloc ulong[TriangleSweepMagnitudeWords];
 2460        WideArithmetic.MultiplyMagnitudes(
 2461            relationSquared,
 2462            determinant,
 2463            relationTerm);
 464
 2465        Span<ulong> firstCorrection = stackalloc ulong[TriangleSweepMagnitudeWords];
 2466        GetTripleProductMagnitude(
 2467            secondSquared,
 2468            firstDotDifference,
 2469            firstDotDifference,
 2470            firstCorrection);
 2471        Span<ulong> mixedCorrection = stackalloc ulong[TriangleSweepMagnitudeWords];
 2472        GetTripleProductMagnitude(
 2473            directionsDot,
 2474            firstDotDifference,
 2475            secondDotDifference,
 2476            mixedCorrection);
 2477        DoubleMagnitude(mixedCorrection);
 2478        Span<ulong> secondCorrection = stackalloc ulong[TriangleSweepMagnitudeWords];
 2479        GetTripleProductMagnitude(
 2480            firstSquared,
 2481            secondDotDifference,
 2482            secondDotDifference,
 2483            secondCorrection);
 484
 2485        Span<ulong> correction = stackalloc ulong[TriangleSweepMagnitudeWords];
 2486        Span<ulong> correctionScratch = stackalloc ulong[TriangleSweepMagnitudeWords];
 2487        CombineSignedMagnitudes(
 2488            firstCorrection,
 2489            1,
 2490            mixedCorrection,
 2491            -(directionsDot.Sign
 2492                * firstDotDifference.Sign
 2493                * secondDotDifference.Sign),
 2494            correctionScratch,
 2495            out int correctionSign);
 2496        CombineSignedMagnitudes(
 2497            correctionScratch,
 2498            correctionSign,
 2499            secondCorrection,
 2500            1,
 2501            correction,
 2502            out _);
 503
 2504        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 505        // An interior/interior closest pair has a strictly positive projected
 506        // correction. A zero parameter is classified as a cap before reaching
 507        // this branch.
 2508        WideArithmetic.SubtractEqualMagnitudes(relationTerm, correction, left);
 509
 2510        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 2511        GetRadiusThreshold(
 2512            radius,
 2513            relationDenominator,
 2514            determinant,
 2515            right);
 2516        return WideArithmetic.CompareMagnitudeEqualLength(left, right) <= 0;
 517    }
 518
 519    private static bool IsRigidPointLineWithinRadius(
 520        Signed576 relationX,
 521        Signed576 relationY,
 522        Signed576 relationZ,
 523        Signed576 axisSquared,
 524        Signed704 axisDotDifference,
 525        Signed576 relationDenominator,
 526        Signed192 radius)
 527    {
 12528        Span<ulong> relationSquared = stackalloc ulong[13];
 12529        GetSquaredMagnitude(
 12530            relationX,
 12531            relationY,
 12532            relationZ,
 12533            relationSquared);
 12534        Span<ulong> axisSquaredMagnitude = stackalloc ulong[9];
 12535        WideArithmetic.GetMagnitude(axisSquared, axisSquaredMagnitude);
 12536        Span<ulong> relationTerm = stackalloc ulong[TriangleSweepMagnitudeWords];
 12537        WideArithmetic.MultiplyMagnitudes(
 12538            relationSquared,
 12539            axisSquaredMagnitude,
 12540            relationTerm);
 12541        Span<ulong> dotMagnitude = stackalloc ulong[11];
 12542        WideArithmetic.GetMagnitude(axisDotDifference, dotMagnitude);
 12543        Span<ulong> dotSquared = stackalloc ulong[TriangleSweepMagnitudeWords];
 12544        WideArithmetic.MultiplyMagnitudes(dotMagnitude, dotMagnitude, dotSquared);
 12545        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 12546        WideArithmetic.SubtractEqualMagnitudes(relationTerm, dotSquared, left);
 547
 12548        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 12549        GetRadiusThreshold(
 12550            radius,
 12551            relationDenominator,
 12552            axisSquaredMagnitude,
 12553            right);
 12554        return WideArithmetic.CompareMagnitudeEqualLength(left, right) <= 0;
 555    }
 556
 557    private static bool IsRigidPointWithinRadius(
 558        Signed576 relationX,
 559        Signed576 relationY,
 560        Signed576 relationZ,
 561        Signed576 relationDenominator,
 562        Signed192 radius)
 563    {
 18564        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 18565        left.Clear();
 18566        GetSquaredMagnitude(
 18567            relationX,
 18568            relationY,
 18569            relationZ,
 18570            left);
 18571        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 18572        GetRadiusThreshold(
 18573            radius,
 18574            relationDenominator,
 18575            ReadOnlySpan<ulong>.Empty,
 18576            right);
 18577        return WideArithmetic.CompareMagnitudeEqualLength(left, right) <= 0;
 578    }
 579
 580    private static void GetRadiusThreshold(
 581        Signed192 radius,
 582        Signed576 relationDenominator,
 583        ReadOnlySpan<ulong> factor,
 584        Span<ulong> result)
 585    {
 32586        Span<ulong> radiusMagnitude = stackalloc ulong[3];
 32587        Span<ulong> denominatorMagnitude = stackalloc ulong[9];
 32588        WideArithmetic.GetMagnitude(
 32589            radius,
 32590            out radiusMagnitude[2],
 32591            out radiusMagnitude[1],
 32592            out radiusMagnitude[0]);
 32593        WideArithmetic.GetMagnitude(
 32594            relationDenominator,
 32595            denominatorMagnitude);
 32596        Span<ulong> radiusSquared = stackalloc ulong[6];
 32597        Span<ulong> denominatorSquared = stackalloc ulong[18];
 32598        WideArithmetic.MultiplyMagnitudes(radiusMagnitude, radiusMagnitude, radiusSquared);
 32599        WideArithmetic.MultiplyMagnitudes(
 32600            denominatorMagnitude,
 32601            denominatorMagnitude,
 32602            denominatorSquared);
 32603        Span<ulong> baseThreshold = stackalloc ulong[TriangleSweepMagnitudeWords];
 32604        WideArithmetic.MultiplyMagnitudes(
 32605            radiusSquared,
 32606            denominatorSquared,
 32607            baseThreshold);
 32608        if (factor.IsEmpty)
 609        {
 18610            baseThreshold.CopyTo(result);
 18611            return;
 612        }
 613
 14614        WideArithmetic.MultiplyMagnitudes(baseThreshold, factor, result);
 14615    }
 616
 617    private static void GetSquaredMagnitude(
 618        Signed576 x,
 619        Signed576 y,
 620        Signed576 z,
 621        Span<ulong> result)
 622    {
 32623        Signed832 squared = WideArithmetic.AddSigned832(
 32624            WideArithmetic.AddSigned832(
 32625                WideArithmetic.MultiplySigned576ToSigned832(x, x),
 32626                WideArithmetic.MultiplySigned576ToSigned832(y, y)),
 32627            WideArithmetic.MultiplySigned576ToSigned832(z, z));
 32628        WideArithmetic.GetMagnitude(squared, result);
 32629    }
 630
 631    private static void GetTripleProductMagnitude(
 632        Signed576 first,
 633        Signed704 second,
 634        Signed704 third,
 635        Span<ulong> result)
 636    {
 6637        Span<ulong> firstMagnitude = stackalloc ulong[9];
 6638        Span<ulong> secondMagnitude = stackalloc ulong[11];
 6639        Span<ulong> thirdMagnitude = stackalloc ulong[11];
 6640        WideArithmetic.GetMagnitude(first, firstMagnitude);
 6641        WideArithmetic.GetMagnitude(second, secondMagnitude);
 6642        WideArithmetic.GetMagnitude(third, thirdMagnitude);
 6643        Span<ulong> firstProduct = stackalloc ulong[20];
 6644        WideArithmetic.MultiplyMagnitudes(
 6645            firstMagnitude,
 6646            secondMagnitude,
 6647            firstProduct);
 6648        WideArithmetic.MultiplyMagnitudes(firstProduct, thirdMagnitude, result);
 6649    }
 650
 651    private static void GetProductDifference(
 652        Signed576 firstLeft,
 653        Signed576 firstRight,
 654        Signed576 secondLeft,
 655        Signed576 secondRight,
 656        Span<ulong> result,
 657        out int sign)
 658    {
 904659        Span<ulong> firstLeftMagnitude = stackalloc ulong[9];
 904660        Span<ulong> firstRightMagnitude = stackalloc ulong[9];
 904661        Span<ulong> secondLeftMagnitude = stackalloc ulong[9];
 904662        Span<ulong> secondRightMagnitude = stackalloc ulong[9];
 904663        WideArithmetic.GetMagnitude(firstLeft, firstLeftMagnitude);
 904664        WideArithmetic.GetMagnitude(firstRight, firstRightMagnitude);
 904665        WideArithmetic.GetMagnitude(secondLeft, secondLeftMagnitude);
 904666        WideArithmetic.GetMagnitude(secondRight, secondRightMagnitude);
 904667        Span<ulong> first = stackalloc ulong[TriangleSweepMagnitudeWords];
 904668        Span<ulong> second = stackalloc ulong[TriangleSweepMagnitudeWords];
 904669        WideArithmetic.MultiplyMagnitudes(
 904670            firstLeftMagnitude,
 904671            firstRightMagnitude,
 904672            first);
 904673        WideArithmetic.MultiplyMagnitudes(
 904674            secondLeftMagnitude,
 904675            secondRightMagnitude,
 904676            second);
 904677        CombineSignedMagnitudes(
 904678            first,
 904679            firstLeft.Sign * firstRight.Sign,
 904680            second,
 904681            -(secondLeft.Sign * secondRight.Sign),
 904682            result,
 904683            out sign);
 904684    }
 685
 686    private static void GetProductDifference(
 687        Signed576 firstLeft,
 688        Signed704 firstRight,
 689        Signed576 secondLeft,
 690        Signed704 secondRight,
 691        Span<ulong> result,
 692        out int sign)
 693    {
 967694        Span<ulong> firstLeftMagnitude = stackalloc ulong[9];
 967695        Span<ulong> firstRightMagnitude = stackalloc ulong[11];
 967696        Span<ulong> secondLeftMagnitude = stackalloc ulong[9];
 967697        Span<ulong> secondRightMagnitude = stackalloc ulong[11];
 967698        WideArithmetic.GetMagnitude(firstLeft, firstLeftMagnitude);
 967699        WideArithmetic.GetMagnitude(firstRight, firstRightMagnitude);
 967700        WideArithmetic.GetMagnitude(secondLeft, secondLeftMagnitude);
 967701        WideArithmetic.GetMagnitude(secondRight, secondRightMagnitude);
 967702        Span<ulong> first = stackalloc ulong[TriangleSweepMagnitudeWords];
 967703        Span<ulong> second = stackalloc ulong[TriangleSweepMagnitudeWords];
 967704        WideArithmetic.MultiplyMagnitudes(
 967705            firstLeftMagnitude,
 967706            firstRightMagnitude,
 967707            first);
 967708        WideArithmetic.MultiplyMagnitudes(
 967709            secondLeftMagnitude,
 967710            secondRightMagnitude,
 967711            second);
 967712        CombineSignedMagnitudes(
 967713            first,
 967714            firstLeft.Sign * firstRight.Sign,
 967715            second,
 967716            -(secondLeft.Sign * secondRight.Sign),
 967717            result,
 967718            out sign);
 967719    }
 720
 721    private static void DoubleMagnitude(Span<ulong> value)
 722    {
 2723        ulong carry = 0UL;
 148724        for (int index = 0; index < value.Length; index++)
 725        {
 72726            ulong nextCarry = value[index] >> 63;
 72727            value[index] = (value[index] << 1) | carry;
 72728            carry = nextCarry;
 729        }
 2730    }
 731
 732    private static Signed704 DoubleProduct(
 733        Signed576 value,
 734        Signed320 factor)
 735    {
 294736        Signed704 product =
 294737            WideArithmetic.MultiplySigned576ToSigned704(value, factor);
 294738        return WideArithmetic.AddSigned704(product, product);
 739    }
 740
 741    private static void GetRigidSegmentLowerDifference(
 742        Vector3d firstCenter,
 743        RigidSegmentAxis firstAxis,
 744        Vector3d secondCenter,
 745        RigidSegmentAxis secondAxis,
 746        Signed576 relationDenominator,
 747        out Signed576 x,
 748        out Signed576 y,
 749        out Signed576 z)
 750    {
 904751        x = GetRigidSegmentLowerDifference(
 904752            firstCenter.X,
 904753            firstAxis.X,
 904754            firstAxis.Denominator,
 904755            secondCenter.X,
 904756            secondAxis.X,
 904757            secondAxis.Denominator,
 904758            relationDenominator);
 904759        y = GetRigidSegmentLowerDifference(
 904760            firstCenter.Y,
 904761            firstAxis.Y,
 904762            firstAxis.Denominator,
 904763            secondCenter.Y,
 904764            secondAxis.Y,
 904765            secondAxis.Denominator,
 904766            relationDenominator);
 904767        z = GetRigidSegmentLowerDifference(
 904768            firstCenter.Z,
 904769            firstAxis.Z,
 904770            firstAxis.Denominator,
 904771            secondCenter.Z,
 904772            secondAxis.Z,
 904773            secondAxis.Denominator,
 904774            relationDenominator);
 904775    }
 776
 777    private static Signed576 GetRigidSegmentLowerDifference(
 778        Fixed64 firstCenter,
 779        Signed320 firstAxis,
 780        Signed320 firstDenominator,
 781        Fixed64 secondCenter,
 782        Signed320 secondAxis,
 783        Signed320 secondDenominator,
 784        Signed576 relationDenominator)
 785    {
 2712786        Signed576 centerTerm = WideArithmetic.MultiplySigned576(
 2712787            relationDenominator,
 2712788            WideArithmetic.SubtractSigned192(
 2712789                Signed192.Raw(firstCenter),
 2712790                Signed192.Raw(secondCenter)));
 2712791        Signed576 firstEndpoint = WideArithmetic.MultiplySigned320(
 2712792            firstAxis,
 2712793            secondDenominator);
 2712794        Signed576 secondEndpoint = WideArithmetic.MultiplySigned320(
 2712795            secondAxis,
 2712796            firstDenominator);
 2712797        return WideArithmetic.AddSigned576(
 2712798            WideArithmetic.SubtractSigned576(
 2712799                centerTerm,
 2712800                firstEndpoint),
 2712801            secondEndpoint);
 802    }
 803
 804    private static void AddRigidSegmentDisplacement(
 805        ref Signed576 relation,
 806        Signed320 axis,
 807        Signed320 otherDenominator)
 808    {
 216809        Signed576 displacement = WideArithmetic.MultiplySigned320(
 216810            axis,
 216811            otherDenominator);
 216812        relation = WideArithmetic.AddSigned576(
 216813            relation,
 216814            WideArithmetic.AddSigned576(displacement, displacement));
 216815    }
 816
 817    private static void SubtractRigidSegmentDisplacement(
 818        ref Signed576 relation,
 819        Signed320 axis,
 820        Signed320 otherDenominator)
 821    {
 522822        Signed576 displacement = WideArithmetic.MultiplySigned320(
 522823            axis,
 522824            otherDenominator);
 522825        relation = WideArithmetic.SubtractSigned576(
 522826            relation,
 522827            WideArithmetic.AddSigned576(displacement, displacement));
 522828    }
 829
 830    private static Signed576 Dot(
 831        RigidSegmentAxis first,
 832        RigidSegmentAxis second) =>
 2712833        WideArithmetic.AddSigned576(
 2712834            WideArithmetic.AddSigned576(
 2712835                WideArithmetic.MultiplySigned320(first.X, second.X),
 2712836                WideArithmetic.MultiplySigned320(first.Y, second.Y)),
 2712837            WideArithmetic.MultiplySigned320(first.Z, second.Z));
 838
 839    private static Signed704 Dot(
 840        RigidSegmentAxis axis,
 841        Signed576 x,
 842        Signed576 y,
 843        Signed576 z) =>
 2293844        WideArithmetic.AddSigned704(
 2293845            WideArithmetic.AddSigned704(
 2293846                WideArithmetic.MultiplySigned576ToSigned704(x, axis.X),
 2293847                WideArithmetic.MultiplySigned576ToSigned704(y, axis.Y)),
 2293848            WideArithmetic.MultiplySigned576ToSigned704(z, axis.Z));
 849}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RigidClosestCandidate.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.RigidClosestCandidate.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 rigid closest-axis/closest-point candidate resolution for cylinder-capsule
 14/// and cylinder-cylinder pairs, used to determine penetration depth and axis data
 15/// for collision response.
 16/// </content>
 17internal static partial class WideOrientedBox
 18{
 19    internal static bool TryKeepCenteredRigidCylinderCapsuleClosestAxis(
 20        Vector3d cylinderCenter,
 21        FixedQuaternion cylinderRotation,
 22        Vector3d cylinderLocalAxis,
 23        Fixed64 cylinderLength,
 24        Fixed64 cylinderRadius,
 25        Vector3d capsuleCenter,
 26        FixedQuaternion capsuleRotation,
 27        Vector3d capsuleLocalAxis,
 28        Fixed64 capsuleLength,
 29        Fixed64 capsuleRadius,
 30        ref WideConvexPrismRelations.CylinderCapsulePenetration best)
 31    {
 38232        var unused = default(
 38233            WideConvexPrismRelations.CylinderCylinderPenetration);
 38234        return TryKeepCenteredRigidCylinderClosestAxis(
 38235            cylinderCenter,
 38236            cylinderRotation,
 38237            cylinderLocalAxis,
 38238            cylinderLength,
 38239            cylinderRadius,
 38240            capsuleCenter,
 38241            capsuleRotation,
 38242            capsuleLocalAxis,
 38243            capsuleLength,
 38244            capsuleRadius,
 38245            RigidClosestPairKind.CylinderCapsule,
 38246            ref best,
 38247            ref unused);
 48    }
 49
 50    internal static bool TryKeepCenteredRigidCylinderCylinderClosestAxis(
 51        Vector3d firstCenter,
 52        FixedQuaternion firstRotation,
 53        Vector3d firstLocalAxis,
 54        Fixed64 firstLength,
 55        Fixed64 firstRadius,
 56        Vector3d secondCenter,
 57        FixedQuaternion secondRotation,
 58        Vector3d secondLocalAxis,
 59        Fixed64 secondLength,
 60        Fixed64 secondRadius,
 61        ref WideConvexPrismRelations.CylinderCylinderPenetration best)
 62    {
 49063        var unused = default(
 49064            WideConvexPrismRelations.CylinderCapsulePenetration);
 49065        return TryKeepCenteredRigidCylinderClosestAxis(
 49066            firstCenter,
 49067            firstRotation,
 49068            firstLocalAxis,
 49069            firstLength,
 49070            firstRadius,
 49071            secondCenter,
 49072            secondRotation,
 49073            secondLocalAxis,
 49074            secondLength,
 49075            secondRadius,
 49076            RigidClosestPairKind.CylinderCylinder,
 49077            ref unused,
 49078            ref best);
 79    }
 80
 81    private static bool TryKeepCenteredRigidCylinderClosestAxis(
 82        Vector3d cylinderCenter,
 83        FixedQuaternion cylinderRotation,
 84        Vector3d cylinderLocalAxis,
 85        Fixed64 cylinderLength,
 86        Fixed64 cylinderRadius,
 87        Vector3d capsuleCenter,
 88        FixedQuaternion capsuleRotation,
 89        Vector3d capsuleLocalAxis,
 90        Fixed64 capsuleLength,
 91        Fixed64 capsuleRadius,
 92        RigidClosestPairKind pairKind,
 93        ref WideConvexPrismRelations.CylinderCapsulePenetration
 94            cylinderCapsuleBest,
 95        ref WideConvexPrismRelations.CylinderCylinderPenetration
 96            cylinderCylinderBest)
 97    {
 87298        GetRotatedLocalAxisNumerators(
 87299            cylinderRotation,
 872100            cylinderLocalAxis,
 872101            out Signed192 firstAxisX,
 872102            out Signed192 firstAxisY,
 872103            out Signed192 firstAxisZ,
 872104            out Signed192 firstRotationDenominator);
 872105        GetRotatedLocalAxisNumerators(
 872106            capsuleRotation,
 872107            capsuleLocalAxis,
 872108            out Signed192 secondAxisX,
 872109            out Signed192 secondAxisY,
 872110            out Signed192 secondAxisZ,
 872111            out Signed192 secondRotationDenominator);
 872112        var firstAxis = new RigidSegmentAxis(
 872113            firstAxisX,
 872114            firstAxisY,
 872115            firstAxisZ,
 872116            firstRotationDenominator,
 872117            cylinderLength);
 872118        var secondAxis = new RigidSegmentAxis(
 872119            secondAxisX,
 872120            secondAxisY,
 872121            secondAxisZ,
 872122            secondRotationDenominator,
 872123            capsuleLength);
 872124        Signed576 relationDenominator = WideArithmetic.AddSigned576(
 872125            WideArithmetic.MultiplySigned320(
 872126                firstAxis.Denominator,
 872127                secondAxis.Denominator),
 872128            WideArithmetic.MultiplySigned320(
 872129                firstAxis.Denominator,
 872130                secondAxis.Denominator));
 872131        GetRigidSegmentLowerDifference(
 872132            cylinderCenter,
 872133            firstAxis,
 872134            capsuleCenter,
 872135            secondAxis,
 872136            relationDenominator,
 872137            out Signed576 relationX,
 872138            out Signed576 relationY,
 872139            out Signed576 relationZ);
 872140        Signed576 firstSquared = Dot(firstAxis, firstAxis);
 872141        Signed576 directionsDot = Dot(firstAxis, secondAxis);
 872142        Signed576 secondSquared = Dot(secondAxis, secondAxis);
 872143        Signed704 firstDotDifference = Dot(
 872144            firstAxis,
 872145            relationX,
 872146            relationY,
 872147            relationZ);
 872148        Signed704 secondDotDifference = Dot(
 872149            secondAxis,
 872150            relationX,
 872151            relationY,
 872152            relationZ);
 153
 872154        Span<ulong> determinant =
 872155            stackalloc ulong[TriangleSweepMagnitudeWords];
 872156        GetProductDifference(
 872157            firstSquared,
 872158            secondSquared,
 872159            directionsDot,
 872160            directionsDot,
 872161            determinant,
 872162            out int determinantSign);
 872163        Span<ulong> firstCore =
 872164            stackalloc ulong[TriangleSweepMagnitudeWords];
 872165        Span<ulong> secondCore =
 872166            stackalloc ulong[TriangleSweepMagnitudeWords];
 872167        int firstCoreSign = 0;
 872168        int secondCoreSign = 0;
 872169        Span<ulong> firstNumerator =
 872170            stackalloc ulong[TriangleSweepMagnitudeWords];
 872171        Span<ulong> firstDenominator =
 872172            stackalloc ulong[TriangleSweepMagnitudeWords];
 872173        Span<ulong> secondNumerator =
 872174            stackalloc ulong[TriangleSweepMagnitudeWords];
 872175        Span<ulong> secondDenominator =
 872176            stackalloc ulong[TriangleSweepMagnitudeWords];
 177        int firstNumeratorSign;
 178        int secondNumeratorSign;
 179        int firstFeature;
 180        int secondFeature;
 872181        if (determinantSign > 0)
 182        {
 598183            GetProductDifference(
 598184                directionsDot,
 598185                secondDotDifference,
 598186                secondSquared,
 598187                firstDotDifference,
 598188                firstCore,
 598189                out firstCoreSign);
 598190            SetRigidSegmentRatio(
 598191                firstCore,
 598192                firstAxis.Denominator,
 598193                determinant,
 598194                relationDenominator,
 598195                firstNumerator,
 598196                firstDenominator);
 598197            firstNumeratorSign = firstCoreSign;
 598198            firstFeature = ClampUnitRatio(
 598199                firstNumerator,
 598200                firstDenominator,
 598201                firstNumeratorSign);
 202
 598203            if (firstFeature == RigidSegmentLower)
 204            {
 139205                SetRigidSegmentProjectionRatio(
 139206                    secondDotDifference,
 139207                    secondAxis.Denominator,
 139208                    secondSquared,
 139209                    relationDenominator,
 139210                    secondNumerator,
 139211                    secondDenominator);
 139212                secondNumeratorSign = secondDotDifference.Sign;
 213            }
 459214            else if (firstFeature == RigidSegmentUpper)
 215            {
 114216                Signed704 upperProjection = WideArithmetic.AddSigned704(
 114217                    secondDotDifference,
 114218                    DoubleProduct(
 114219                        directionsDot,
 114220                        secondAxis.Denominator));
 114221                SetRigidSegmentProjectionRatio(
 114222                    upperProjection,
 114223                    secondAxis.Denominator,
 114224                    secondSquared,
 114225                    relationDenominator,
 114226                    secondNumerator,
 114227                    secondDenominator);
 114228                secondNumeratorSign = upperProjection.Sign;
 229            }
 230            else
 231            {
 345232                GetProductDifference(
 345233                    firstSquared,
 345234                    secondDotDifference,
 345235                    directionsDot,
 345236                    firstDotDifference,
 345237                    secondCore,
 345238                    out secondCoreSign);
 345239                SetRigidSegmentRatio(
 345240                    secondCore,
 345241                    secondAxis.Denominator,
 345242                    determinant,
 345243                    relationDenominator,
 345244                    secondNumerator,
 345245                    secondDenominator);
 345246                secondNumeratorSign = secondCoreSign;
 247            }
 248        }
 249        else
 250        {
 274251            firstNumerator.Clear();
 274252            firstDenominator.Clear();
 274253            firstDenominator[0] = 1UL;
 274254            firstNumeratorSign = 0;
 274255            firstFeature = RigidSegmentLower;
 274256            SetRigidSegmentProjectionRatio(
 274257                secondDotDifference,
 274258                secondAxis.Denominator,
 274259                secondSquared,
 274260                relationDenominator,
 274261                secondNumerator,
 274262                secondDenominator);
 274263            secondNumeratorSign = secondDotDifference.Sign;
 264        }
 265
 872266        secondFeature = ClampUnitRatio(
 872267            secondNumerator,
 872268            secondDenominator,
 872269            secondNumeratorSign);
 872270        if (secondFeature == RigidSegmentLower)
 271        {
 336272            SetRigidSegmentProjectionRatio(
 336273                WideArithmetic.SubtractSigned704(
 336274                    default,
 336275                    firstDotDifference),
 336276                firstAxis.Denominator,
 336277                firstSquared,
 336278                relationDenominator,
 336279                firstNumerator,
 336280                firstDenominator);
 336281            firstNumeratorSign = -firstDotDifference.Sign;
 336282            firstFeature = ClampUnitRatio(
 336283                firstNumerator,
 336284                firstDenominator,
 336285                firstNumeratorSign);
 286        }
 536287        else if (secondFeature == RigidSegmentUpper)
 288        {
 168289            Signed704 upperProjection = WideArithmetic.SubtractSigned704(
 168290                DoubleProduct(
 168291                    directionsDot,
 168292                    firstAxis.Denominator),
 168293                firstDotDifference);
 168294            SetRigidSegmentProjectionRatio(
 168295                upperProjection,
 168296                firstAxis.Denominator,
 168297                firstSquared,
 168298                relationDenominator,
 168299                firstNumerator,
 168300                firstDenominator);
 168301            firstNumeratorSign = upperProjection.Sign;
 168302            firstFeature = ClampUnitRatio(
 168303                firstNumerator,
 168304                firstDenominator,
 168305                firstNumeratorSign);
 306        }
 307
 872308        if (firstFeature == RigidSegmentUpper)
 309        {
 66310            AddRigidSegmentDisplacement(
 66311                ref relationX,
 66312                firstAxis.X,
 66313                secondAxis.Denominator);
 66314            AddRigidSegmentDisplacement(
 66315                ref relationY,
 66316                firstAxis.Y,
 66317                secondAxis.Denominator);
 66318            AddRigidSegmentDisplacement(
 66319                ref relationZ,
 66320                firstAxis.Z,
 66321                secondAxis.Denominator);
 322        }
 872323        if (secondFeature == RigidSegmentUpper)
 324        {
 168325            SubtractRigidSegmentDisplacement(
 168326                ref relationX,
 168327                secondAxis.X,
 168328                firstAxis.Denominator);
 168329            SubtractRigidSegmentDisplacement(
 168330                ref relationY,
 168331                secondAxis.Y,
 168332                firstAxis.Denominator);
 168333            SubtractRigidSegmentDisplacement(
 168334                ref relationZ,
 168335                secondAxis.Z,
 168336                firstAxis.Denominator);
 337        }
 338
 872339        Span<ulong> candidateX =
 872340            stackalloc ulong[TriangleSweepMagnitudeWords];
 872341        Span<ulong> candidateY =
 872342            stackalloc ulong[TriangleSweepMagnitudeWords];
 872343        Span<ulong> candidateZ =
 872344            stackalloc ulong[TriangleSweepMagnitudeWords];
 345        int candidateXSign;
 346        int candidateYSign;
 347        int candidateZSign;
 872348        if (firstFeature == RigidSegmentInterior
 872349            && secondFeature == RigidSegmentInterior)
 350        {
 193351            BuildRigidLinePairClosestComponent(
 193352                relationX,
 193353                determinant,
 193354                firstAxis.X,
 193355                firstCore,
 193356                firstCoreSign,
 193357                secondAxis.X,
 193358                secondCore,
 193359                secondCoreSign,
 193360                candidateX,
 193361                out candidateXSign);
 193362            BuildRigidLinePairClosestComponent(
 193363                relationY,
 193364                determinant,
 193365                firstAxis.Y,
 193366                firstCore,
 193367                firstCoreSign,
 193368                secondAxis.Y,
 193369                secondCore,
 193370                secondCoreSign,
 193371                candidateY,
 193372                out candidateYSign);
 193373            BuildRigidLinePairClosestComponent(
 193374                relationZ,
 193375                determinant,
 193376                firstAxis.Z,
 193377                firstCore,
 193378                firstCoreSign,
 193379                secondAxis.Z,
 193380                secondCore,
 193381                secondCoreSign,
 193382                candidateZ,
 193383                out candidateZSign);
 384        }
 679385        else if (firstFeature == RigidSegmentInterior)
 386        {
 298387            Signed704 adjustedDot = Dot(
 298388                firstAxis,
 298389                relationX,
 298390                relationY,
 298391                relationZ);
 298392            BuildRigidPointLineClosestComponent(
 298393                relationX,
 298394                firstSquared,
 298395                firstAxis.X,
 298396                adjustedDot,
 298397                candidateX,
 298398                out candidateXSign);
 298399            BuildRigidPointLineClosestComponent(
 298400                relationY,
 298401                firstSquared,
 298402                firstAxis.Y,
 298403                adjustedDot,
 298404                candidateY,
 298405                out candidateYSign);
 298406            BuildRigidPointLineClosestComponent(
 298407                relationZ,
 298408                firstSquared,
 298409                firstAxis.Z,
 298410                adjustedDot,
 298411                candidateZ,
 298412                out candidateZSign);
 413        }
 381414        else if (secondFeature == RigidSegmentInterior)
 415        {
 175416            Signed704 adjustedDot = Dot(
 175417                secondAxis,
 175418                relationX,
 175419                relationY,
 175420                relationZ);
 175421            BuildRigidPointLineClosestComponent(
 175422                relationX,
 175423                secondSquared,
 175424                secondAxis.X,
 175425                adjustedDot,
 175426                candidateX,
 175427                out candidateXSign);
 175428            BuildRigidPointLineClosestComponent(
 175429                relationY,
 175430                secondSquared,
 175431                secondAxis.Y,
 175432                adjustedDot,
 175433                candidateY,
 175434                out candidateYSign);
 175435            BuildRigidPointLineClosestComponent(
 175436                relationZ,
 175437                secondSquared,
 175438                secondAxis.Z,
 175439                adjustedDot,
 175440                candidateZ,
 175441                out candidateZSign);
 442        }
 443        else
 444        {
 206445            GetSignedMagnitude(
 206446                relationX,
 206447                candidateX,
 206448                out candidateXSign);
 206449            GetSignedMagnitude(
 206450                relationY,
 206451                candidateY,
 206452                out candidateYSign);
 206453            GetSignedMagnitude(
 206454                relationZ,
 206455                candidateZ,
 206456                out candidateZSign);
 457        }
 458
 872459        RemoveCommonPowerOfTwo(
 872460            candidateX,
 872461            candidateY,
 872462            candidateZ);
 872463        var candidate = new WideConvexPrismRelations.WideCandidateAxis3(
 872464            candidateX,
 872465            candidateXSign,
 872466            candidateY,
 872467            candidateYSign,
 872468            candidateZ,
 872469            candidateZSign);
 872470        if (pairKind == RigidClosestPairKind.CylinderCapsule)
 471        {
 382472            return WideConvexPrismRelations
 382473                .TryKeepWideCylinderCapsuleAxis(
 382474                    candidate,
 382475                    cylinderCenter,
 382476                    cylinderRotation,
 382477                    cylinderLocalAxis,
 382478                    cylinderLength,
 382479                    cylinderRadius,
 382480                    capsuleCenter,
 382481                    capsuleRotation,
 382482                    capsuleLocalAxis,
 382483                    capsuleLength,
 382484                    capsuleRadius,
 382485                    ref cylinderCapsuleBest);
 486        }
 490487        return WideConvexPrismRelations
 490488            .TryKeepWideCylinderCylinderAxis(
 490489                candidate,
 490490                cylinderCenter,
 490491                cylinderRotation,
 490492                cylinderLocalAxis,
 490493                cylinderLength,
 490494                cylinderRadius,
 490495                capsuleCenter,
 490496                capsuleRotation,
 490497                capsuleLocalAxis,
 490498                capsuleLength,
 490499                capsuleRadius,
 490500                ref cylinderCylinderBest);
 501    }
 502
 503    private enum RigidClosestPairKind
 504    {
 505        CylinderCapsule,
 506        CylinderCylinder,
 507    }
 508
 509    private static void BuildRigidPointLineClosestComponent(
 510        Signed576 relation,
 511        Signed576 axisSquared,
 512        Signed320 axisComponent,
 513        Signed704 axisDot,
 514        Span<ulong> result,
 515        out int resultSign)
 516    {
 1419517        Span<ulong> relationMagnitude = stackalloc ulong[9];
 1419518        Span<ulong> axisSquaredMagnitude = stackalloc ulong[9];
 1419519        Span<ulong> axisMagnitude = stackalloc ulong[5];
 1419520        Span<ulong> dotMagnitude = stackalloc ulong[11];
 1419521        WideArithmetic.GetMagnitude(
 1419522            relation,
 1419523            relationMagnitude);
 1419524        WideArithmetic.GetMagnitude(
 1419525            axisSquared,
 1419526            axisSquaredMagnitude);
 1419527        WideArithmetic.GetMagnitude(
 1419528            axisComponent,
 1419529            out axisMagnitude[4],
 1419530            out axisMagnitude[3],
 1419531            out axisMagnitude[2],
 1419532            out axisMagnitude[1],
 1419533            out axisMagnitude[0]);
 1419534        WideArithmetic.GetMagnitude(axisDot, dotMagnitude);
 1419535        Span<ulong> relationTerm =
 1419536            stackalloc ulong[TriangleSweepMagnitudeWords];
 1419537        Span<ulong> axisTerm =
 1419538            stackalloc ulong[TriangleSweepMagnitudeWords];
 1419539        WideArithmetic.MultiplyMagnitudes(
 1419540            relationMagnitude,
 1419541            axisSquaredMagnitude,
 1419542            relationTerm);
 1419543        WideArithmetic.MultiplyMagnitudes(
 1419544            axisMagnitude,
 1419545            dotMagnitude,
 1419546            axisTerm);
 1419547        CombineSignedMagnitudes(
 1419548            relationTerm,
 1419549            relation.Sign,
 1419550            axisTerm,
 1419551            -(axisComponent.Sign * axisDot.Sign),
 1419552            result,
 1419553            out resultSign);
 1419554    }
 555
 556    private static void BuildRigidLinePairClosestComponent(
 557        Signed576 relation,
 558        ReadOnlySpan<ulong> determinant,
 559        Signed320 firstAxisComponent,
 560        ReadOnlySpan<ulong> firstCore,
 561        int firstCoreSign,
 562        Signed320 secondAxisComponent,
 563        ReadOnlySpan<ulong> secondCore,
 564        int secondCoreSign,
 565        Span<ulong> result,
 566        out int resultSign)
 567    {
 579568        Span<ulong> relationMagnitude = stackalloc ulong[9];
 579569        Span<ulong> firstAxisMagnitude = stackalloc ulong[5];
 579570        Span<ulong> secondAxisMagnitude = stackalloc ulong[5];
 579571        WideArithmetic.GetMagnitude(
 579572            relation,
 579573            relationMagnitude);
 579574        WideArithmetic.GetMagnitude(
 579575            firstAxisComponent,
 579576            out firstAxisMagnitude[4],
 579577            out firstAxisMagnitude[3],
 579578            out firstAxisMagnitude[2],
 579579            out firstAxisMagnitude[1],
 579580            out firstAxisMagnitude[0]);
 579581        WideArithmetic.GetMagnitude(
 579582            secondAxisComponent,
 579583            out secondAxisMagnitude[4],
 579584            out secondAxisMagnitude[3],
 579585            out secondAxisMagnitude[2],
 579586            out secondAxisMagnitude[1],
 579587            out secondAxisMagnitude[0]);
 579588        Span<ulong> relationTerm =
 579589            stackalloc ulong[TriangleSweepMagnitudeWords];
 579590        Span<ulong> firstTerm =
 579591            stackalloc ulong[TriangleSweepMagnitudeWords];
 579592        Span<ulong> secondTerm =
 579593            stackalloc ulong[TriangleSweepMagnitudeWords];
 579594        Span<ulong> firstCombined =
 579595            stackalloc ulong[TriangleSweepMagnitudeWords];
 579596        WideArithmetic.MultiplyMagnitudes(
 579597            relationMagnitude,
 579598            determinant,
 579599            relationTerm);
 579600        WideArithmetic.MultiplyMagnitudes(
 579601            firstAxisMagnitude,
 579602            firstCore,
 579603            firstTerm);
 579604        WideArithmetic.MultiplyMagnitudes(
 579605            secondAxisMagnitude,
 579606            secondCore,
 579607            secondTerm);
 579608        CombineSignedMagnitudes(
 579609            relationTerm,
 579610            relation.Sign,
 579611            firstTerm,
 579612            firstAxisComponent.Sign * firstCoreSign,
 579613            firstCombined,
 579614            out int firstCombinedSign);
 579615        CombineSignedMagnitudes(
 579616            firstCombined,
 579617            firstCombinedSign,
 579618            secondTerm,
 579619            -(secondAxisComponent.Sign * secondCoreSign),
 579620            result,
 579621            out resultSign);
 579622    }
 623
 624    private static void GetSignedMagnitude(
 625        Signed576 value,
 626        Span<ulong> magnitude,
 627        out int sign)
 628    {
 618629        magnitude.Clear();
 618630        WideArithmetic.GetMagnitude(value, magnitude);
 618631        sign = value.Sign;
 618632    }
 633
 634    private static void RemoveCommonPowerOfTwo(
 635        Span<ulong> x,
 636        Span<ulong> y,
 637        Span<ulong> z)
 638    {
 872639        int shift = Math.Min(
 872640            GetTrailingZeroCount(x),
 872641            Math.Min(
 872642                GetTrailingZeroCount(y),
 872643                GetTrailingZeroCount(z)));
 644        // Rigid-frame terms retain at least one shared binary scale factor.
 645        // A zero vector is the only candidate that cannot be reduced.
 872646        if (shift == int.MaxValue)
 117647            return;
 755648        ShiftRightMagnitude(x, shift);
 755649        ShiftRightMagnitude(y, shift);
 755650        ShiftRightMagnitude(z, shift);
 755651    }
 652
 653    private static int GetTrailingZeroCount(
 654        ReadOnlySpan<ulong> value)
 655    {
 83418656        for (int index = 0; index < value.Length; index++)
 657        {
 40777658            ulong word = value[index];
 40777659            if (word == 0UL)
 660                continue;
 1684661            int count = index << 6;
 35953662            while ((word & 1UL) == 0UL)
 663            {
 34269664                count++;
 34269665                word >>= 1;
 666            }
 1684667            return count;
 668        }
 932669        return int.MaxValue;
 670    }
 671
 672    private static void ShiftRightMagnitude(
 673        Span<ulong> value,
 674        int shift)
 675    {
 2265676        int wordShift = shift >> 6;
 2265677        int bitShift = shift & 63;
 167610678        for (int index = 0; index < value.Length; index++)
 679        {
 81540680            int source = index + wordShift;
 81540681            ulong result = source < value.Length
 81540682                ? value[source] >> bitShift
 81540683                : 0UL;
 81540684            if (bitShift != 0
 81540685                && source + 1 < value.Length)
 686            {
 67539687                result |= value[source + 1] << (64 - bitShift);
 688            }
 81540689            value[index] = result;
 690        }
 2265691    }
 692}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RigidFiniteAxisQuery.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.RigidFiniteAxisQuery.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
 8namespace FixedMathSharp.Geometry;
 9
 10/// <content>
 11/// Rigid-transform (no-scale) finite axis intersection queries for oriented boxes,
 12/// including capsule distance interval and axial bounds computations.
 13/// </content>
 14internal static partial class WideOrientedBox
 15{
 16    #region Nested Types
 17
 18    private readonly struct RigidLocalRay
 19    {
 20        internal readonly Signed192 StartX;
 21        internal readonly Signed192 StartY;
 22        internal readonly Signed192 StartZ;
 23        internal readonly Signed192 EndX;
 24        internal readonly Signed192 EndY;
 25        internal readonly Signed192 EndZ;
 26        internal readonly Signed192 DeltaX;
 27        internal readonly Signed192 DeltaY;
 28        internal readonly Signed192 DeltaZ;
 29        internal readonly Signed192 Denominator;
 30
 31        internal RigidLocalRay(
 32            Signed192 startX,
 33            Signed192 startY,
 34            Signed192 startZ,
 35            Signed192 endX,
 36            Signed192 endY,
 37            Signed192 endZ,
 38            Signed192 denominator)
 39        {
 40340            StartX = startX;
 40341            StartY = startY;
 40342            StartZ = startZ;
 40343            EndX = endX;
 40344            EndY = endY;
 40345            EndZ = endZ;
 40346            DeltaX = WideArithmetic.SubtractSigned192(endX, startX);
 40347            DeltaY = WideArithmetic.SubtractSigned192(endY, startY);
 40348            DeltaZ = WideArithmetic.SubtractSigned192(endZ, startZ);
 40349            Denominator = denominator;
 40350        }
 51    }
 52
 53    private readonly struct RigidRayBound
 54    {
 55        internal readonly Signed192 Numerator;
 56        internal readonly Signed192 Denominator;
 57
 58        internal RigidRayBound(
 59            Signed192 numerator,
 60            Signed192 denominator)
 61        {
 160262            Numerator = numerator;
 160263            Denominator = denominator;
 160264        }
 65    }
 66
 67    #endregion
 68
 69    internal static bool TryGetRigidCapsuleDistanceInterval(
 70        FixedSegment query,
 71        Vector3d center,
 72        FixedQuaternion rotation,
 73        Fixed64 axisLength,
 74        Fixed64 radius,
 75        Fixed64 radiusExpansion,
 76        Fixed64 totalDistance,
 77        out Fixed64 entry,
 78        out Fixed64 exit,
 79        out bool startContained,
 80        out bool endContainedStrict)
 81    {
 14182        WideRationalBasis3d basis = new(rotation);
 14183        if (TryGetCardinalLocalYAxis(basis, out Vector3d axisDirection))
 84        {
 785            return WideFiniteAxisIntersection.TryGetCapsuleDistanceInterval(
 786                query,
 787                center,
 788                axisDirection,
 789                axisLength,
 790                radius,
 791                radiusExpansion,
 792                totalDistance,
 793                out entry,
 794                out exit,
 795                out startContained,
 796                out endContainedStrict);
 97        }
 98
 13499        RigidLocalRay ray = GetRigidLocalRay(query, center, basis);
 134100        Signed192 length = ScaleRigidDimension(axisLength, ray.Denominator);
 134101        Signed192 expandedRadius = ScaleRigidDimensionSum(
 134102            radius,
 134103            radiusExpansion,
 134104            ray.Denominator);
 134105        startContained = IsCapsuleContained(
 134106            ray.StartX,
 134107            ray.StartY,
 134108            ray.StartZ,
 134109            length,
 134110            expandedRadius,
 134111            strict: false);
 134112        endContainedStrict = IsCapsuleContained(
 134113            ray.EndX,
 134114            ray.EndY,
 134115            ray.EndZ,
 134116            length,
 134117            expandedRadius,
 134118            strict: true);
 119
 134120        bool found = false;
 134121        entry = default;
 134122        exit = default;
 134123        if (TryGetCenteredAxialBounds(
 134124                ray.StartY,
 134125                ray.DeltaY,
 134126                length,
 134127                out RigidRayBound lower,
 134128                out RigidRayBound upper))
 129        {
 131130            GetRadialPolynomial(
 131131                ray.StartX,
 131132                ray.StartZ,
 131133                ray.DeltaX,
 131134                ray.DeltaZ,
 131135                expandedRadius,
 131136                out Signed576 coefficient,
 131137                out Signed576 projection,
 131138                out Signed576 constant);
 131139            MergeRigidInterval(
 131140                WideFiniteConeIntersection.TrySolveBoundedUnitPolynomial(
 131141                    coefficient,
 131142                    projection,
 131143                    constant,
 131144                    lower.Numerator,
 131145                    lower.Denominator,
 131146                    upper.Numerator,
 131147                    upper.Denominator,
 131148                    totalDistance,
 131149                    out Fixed64 sideEntry,
 131150                    out Fixed64 sideExit),
 131151                sideEntry,
 131152                sideExit,
 131153                ref found,
 131154                ref entry,
 131155                ref exit);
 156        }
 157
 134158        MergeRigidCapsuleCap(
 134159            ray,
 134160            length,
 134161            expandedRadius,
 134162            positive: false,
 134163            totalDistance,
 134164            ref found,
 134165            ref entry,
 134166            ref exit);
 134167        MergeRigidCapsuleCap(
 134168            ray,
 134169            length,
 134170            expandedRadius,
 134171            positive: true,
 134172            totalDistance,
 134173            ref found,
 134174            ref entry,
 134175            ref exit);
 134176        return found;
 177    }
 178
 179    internal static bool TryGetRigidCylinderDistanceInterval(
 180        FixedSegment query,
 181        Vector3d center,
 182        FixedQuaternion rotation,
 183        Fixed64 axisLength,
 184        Fixed64 radius,
 185        Fixed64 radiusExpansion,
 186        Fixed64 axialExpansion,
 187        Fixed64 totalDistance,
 188        out Fixed64 entry,
 189        out Fixed64 exit,
 190        out bool startContained,
 191        out bool endContainedStrict)
 192    {
 136193        WideRationalBasis3d basis = new(rotation);
 136194        if (TryGetCardinalLocalYAxis(basis, out Vector3d axisDirection))
 195        {
 1196            return WideFiniteAxisIntersection.TryGetFiniteCylinderDistanceInterval(
 1197                query,
 1198                center,
 1199                axisDirection,
 1200                axisLength,
 1201                radius,
 1202                radiusExpansion,
 1203                axialExpansion,
 1204                totalDistance,
 1205                out entry,
 1206                out exit,
 1207                out startContained,
 1208                out endContainedStrict);
 209        }
 210
 135211        RigidLocalRay ray = GetRigidLocalRay(query, center, basis);
 135212        Signed192 length = ScaleRigidDimensionWithDoubleExpansion(
 135213            axisLength,
 135214            axialExpansion,
 135215            ray.Denominator);
 135216        Signed192 expandedRadius = ScaleRigidDimensionSum(
 135217            radius,
 135218            radiusExpansion,
 135219            ray.Denominator);
 135220        startContained = IsCylinderContained(
 135221            ray.StartX,
 135222            ray.StartY,
 135223            ray.StartZ,
 135224            length,
 135225            expandedRadius,
 135226            strict: false);
 135227        endContainedStrict = IsCylinderContained(
 135228            ray.EndX,
 135229            ray.EndY,
 135230            ray.EndZ,
 135231            length,
 135232            expandedRadius,
 135233            strict: true);
 234
 135235        if (!TryGetCenteredAxialBounds(
 135236                ray.StartY,
 135237                ray.DeltaY,
 135238                length,
 135239                out RigidRayBound lower,
 135240                out RigidRayBound upper))
 241        {
 3242            entry = default;
 3243            exit = default;
 3244            return false;
 245        }
 246
 132247        GetRadialPolynomial(
 132248            ray.StartX,
 132249            ray.StartZ,
 132250            ray.DeltaX,
 132251            ray.DeltaZ,
 132252            expandedRadius,
 132253            out Signed576 coefficient,
 132254            out Signed576 projection,
 132255            out Signed576 constant);
 132256        return WideFiniteConeIntersection.TrySolveBoundedUnitPolynomial(
 132257            coefficient,
 132258            projection,
 132259            constant,
 132260            lower.Numerator,
 132261            lower.Denominator,
 132262            upper.Numerator,
 132263            upper.Denominator,
 132264            totalDistance,
 132265            out entry,
 132266            out exit);
 267    }
 268
 269    internal static bool TryGetRigidConeDistanceInterval(
 270        FixedSegment query,
 271        Vector3d center,
 272        FixedQuaternion rotation,
 273        Fixed64 height,
 274        Fixed64 radius,
 275        Fixed64 totalDistance,
 276        out Fixed64 entry,
 277        out Fixed64 exit,
 278        out bool startContained,
 279        out bool endContainedStrict)
 280    {
 141281        WideRationalBasis3d basis = new(rotation);
 141282        if (TryGetCardinalLocalYAxis(basis, out Vector3d axisDirection))
 283        {
 7284            return WideFiniteConeIntersection.TryGetCenteredDistanceInterval(
 7285                query,
 7286                center,
 7287                axisDirection,
 7288                height,
 7289                radius,
 7290                totalDistance,
 7291                out entry,
 7292                out exit,
 7293                out startContained,
 7294                out endContainedStrict);
 295        }
 296
 134297        RigidLocalRay ray = GetRigidLocalRay(query, center, basis);
 134298        GetConePolynomial(
 134299            ray,
 134300            Signed192.Raw(height),
 134301            Signed192.Raw(radius),
 134302            out Signed192 startAxial,
 134303            out Signed192 axialVelocity,
 134304            out Signed192 maximumAxial,
 134305            out Signed576 coefficient,
 134306            out Signed576 projection,
 134307            out Signed576 constant);
 134308        startContained = IsConeContained(
 134309            startAxial,
 134310            maximumAxial,
 134311            constant.Sign,
 134312            strict: false);
 134313        Signed192 endAxial =
 134314            WideArithmetic.AddSigned192(startAxial, axialVelocity);
 134315        endContainedStrict = IsConeContained(
 134316            endAxial,
 134317            maximumAxial,
 134318            EvaluatePolynomialAtOne(
 134319                coefficient,
 134320                projection,
 134321                constant).Sign,
 134322            strict: true);
 323
 134324        if (!TryGetLinearBounds(
 134325                startAxial,
 134326                axialVelocity,
 134327                default,
 134328                maximumAxial,
 134329                out RigidRayBound lower,
 134330                out RigidRayBound upper))
 331        {
 1332            entry = default;
 1333            exit = default;
 1334            return false;
 335        }
 336
 133337        return WideFiniteConeIntersection.TrySolveBoundedUnitPolynomial(
 133338            coefficient,
 133339            projection,
 133340            constant,
 133341            lower.Numerator,
 133342            lower.Denominator,
 133343            upper.Numerator,
 133344            upper.Denominator,
 133345            totalDistance,
 133346            out entry,
 133347            out exit);
 348    }
 349
 350    private static RigidLocalRay GetRigidLocalRay(
 351        FixedSegment query,
 352        Vector3d center,
 353        WideRationalBasis3d basis)
 354    {
 403355        GetRelativeLocalPointNumerators(
 403356            query.Start,
 403357            center,
 403358            basis,
 403359            out Signed192 startX,
 403360            out Signed192 startY,
 403361            out Signed192 startZ);
 403362        GetRelativeLocalPointNumerators(
 403363            query.End,
 403364            center,
 403365            basis,
 403366            out Signed192 endX,
 403367            out Signed192 endY,
 403368            out Signed192 endZ);
 403369        return new RigidLocalRay(
 403370            startX,
 403371            startY,
 403372            startZ,
 403373            endX,
 403374            endY,
 403375            endZ,
 403376            basis.Denominator);
 377    }
 378
 379    private static bool TryGetCardinalLocalYAxis(
 380        WideRationalBasis3d basis,
 381        out Vector3d axisDirection)
 382    {
 418383        if (basis.Yy.IsZero
 418384            && basis.Yz.IsZero
 418385            && WideArithmetic.CompareMagnitude(basis.Yx, basis.Denominator) == 0)
 386        {
 4387            axisDirection = basis.Yx.Sign > 0 ? Vector3d.Right : Vector3d.Left;
 4388            return true;
 389        }
 390
 414391        if (basis.Yx.IsZero
 414392            && basis.Yz.IsZero
 414393            && WideArithmetic.CompareMagnitude(basis.Yy, basis.Denominator) == 0)
 394        {
 7395            axisDirection = basis.Yy.Sign > 0 ? Vector3d.Up : Vector3d.Down;
 7396            return true;
 397        }
 398
 407399        if (basis.Yx.IsZero
 407400            && basis.Yy.IsZero
 407401            && WideArithmetic.CompareMagnitude(basis.Yz, basis.Denominator) == 0)
 402        {
 4403            axisDirection = basis.Yz.Sign > 0 ? Vector3d.Forward : Vector3d.Backward;
 4404            return true;
 405        }
 406
 403407        axisDirection = default;
 403408        return false;
 409    }
 410
 411    private static Signed192 ScaleRigidDimension(
 412        Fixed64 value,
 413        Signed192 denominator) =>
 134414        NarrowRigidQueryValue(
 134415            WideArithmetic.MultiplySigned192(
 134416                Signed192.Raw(value),
 134417                denominator));
 418
 419    private static Signed192 ScaleRigidDimensionSum(
 420        Fixed64 first,
 421        Fixed64 second,
 422        Signed192 denominator) =>
 269423        NarrowRigidQueryValue(
 269424            WideArithmetic.MultiplySigned192(
 269425                WideArithmetic.AddSigned192(
 269426                    Signed192.Raw(first),
 269427                    Signed192.Raw(second)),
 269428                denominator));
 429
 430    private static Signed192 ScaleRigidDimensionWithDoubleExpansion(
 431        Fixed64 value,
 432        Fixed64 expansion,
 433        Signed192 denominator)
 434    {
 135435        Signed192 expanded = WideArithmetic.AddSigned192(
 135436            Signed192.Raw(value),
 135437            WideArithmetic.AddSigned192(
 135438                Signed192.Raw(expansion),
 135439                Signed192.Raw(expansion)));
 135440        return NarrowRigidQueryValue(
 135441            WideArithmetic.MultiplySigned192(expanded, denominator));
 442    }
 443
 444    private static Signed192 NarrowRigidQueryValue(Signed320 value)
 445    {
 672446        _ = Signed192.TryNarrowSigned(value, out Signed192 result);
 672447        return result;
 448    }
 449
 450    private static void GetRadialPolynomial(
 451        Signed192 startX,
 452        Signed192 startZ,
 453        Signed192 deltaX,
 454        Signed192 deltaZ,
 455        Signed192 radius,
 456        out Signed576 coefficient,
 457        out Signed576 projection,
 458        out Signed576 constant)
 459    {
 263460        Signed320 coefficientNarrow = AddRigidSquares(
 263461            deltaX,
 263462            deltaZ);
 263463        Signed320 projectionNarrow = AddRigidProducts(
 263464            startX,
 263465            deltaX,
 263466            startZ,
 263467            deltaZ);
 263468        Signed320 constantNarrow = WideArithmetic.SubtractSigned320(
 263469            AddRigidSquares(startX, startZ),
 263470            WideArithmetic.MultiplySigned192(radius, radius));
 263471        coefficient =
 263472            Signed576.ExtendValue(coefficientNarrow);
 263473        projection =
 263474            Signed576.ExtendValue(projectionNarrow);
 263475        constant =
 263476            Signed576.ExtendValue(constantNarrow);
 263477    }
 478
 479    private static void MergeRigidCapsuleCap(
 480        RigidLocalRay ray,
 481        Signed192 length,
 482        Signed192 radius,
 483        bool positive,
 484        Fixed64 totalDistance,
 485        ref bool found,
 486        ref Fixed64 entry,
 487        ref Fixed64 exit)
 488    {
 268489        Signed192 startX = WideArithmetic.Double(ray.StartX);
 268490        Signed192 startY = positive
 268491            ? WideArithmetic.SubtractSigned192(
 268492                WideArithmetic.Double(ray.StartY),
 268493                length)
 268494            : WideArithmetic.AddSigned192(
 268495                WideArithmetic.Double(ray.StartY),
 268496                length);
 268497        Signed192 startZ = WideArithmetic.Double(ray.StartZ);
 268498        Signed192 deltaX = WideArithmetic.Double(ray.DeltaX);
 268499        Signed192 deltaY = WideArithmetic.Double(ray.DeltaY);
 268500        Signed192 deltaZ = WideArithmetic.Double(ray.DeltaZ);
 268501        Signed192 doubledRadius = WideArithmetic.Double(radius);
 268502        GetSpherePolynomial(
 268503            startX,
 268504            startY,
 268505            startZ,
 268506            deltaX,
 268507            deltaY,
 268508            deltaZ,
 268509            doubledRadius,
 268510            out Signed576 coefficient,
 268511            out Signed576 projection,
 268512            out Signed576 constant);
 268513        MergeRigidInterval(
 268514            WideFiniteConeIntersection.TrySolveUnitPolynomial(
 268515                coefficient,
 268516                projection,
 268517                constant,
 268518                totalDistance,
 268519                out Fixed64 capEntry,
 268520                out Fixed64 capExit),
 268521            capEntry,
 268522            capExit,
 268523            ref found,
 268524            ref entry,
 268525            ref exit);
 268526    }
 527
 528    private static void GetSpherePolynomial(
 529        Signed192 startX,
 530        Signed192 startY,
 531        Signed192 startZ,
 532        Signed192 deltaX,
 533        Signed192 deltaY,
 534        Signed192 deltaZ,
 535        Signed192 radius,
 536        out Signed576 coefficient,
 537        out Signed576 projection,
 538        out Signed576 constant)
 539    {
 268540        coefficient = Signed576.ExtendValue(
 268541            AddRigidSquares(deltaX, deltaY, deltaZ));
 268542        projection = Signed576.ExtendValue(
 268543            AddRigidProducts(
 268544                startX,
 268545                deltaX,
 268546                startY,
 268547                deltaY,
 268548                startZ,
 268549                deltaZ));
 268550        constant = Signed576.ExtendValue(
 268551            WideArithmetic.SubtractSigned320(
 268552                AddRigidSquares(startX, startY, startZ),
 268553                WideArithmetic.MultiplySigned192(radius, radius)));
 268554    }
 555
 556    private static void GetConePolynomial(
 557        RigidLocalRay ray,
 558        Signed192 height,
 559        Signed192 radius,
 560        out Signed192 startAxial,
 561        out Signed192 axialVelocity,
 562        out Signed192 maximumAxial,
 563        out Signed576 coefficient,
 564        out Signed576 projection,
 565        out Signed576 constant)
 566    {
 134567        Signed192 doubledStartX = WideArithmetic.Double(ray.StartX);
 134568        Signed192 doubledStartZ = WideArithmetic.Double(ray.StartZ);
 134569        Signed192 doubledDeltaX = WideArithmetic.Double(ray.DeltaX);
 134570        Signed192 doubledDeltaZ = WideArithmetic.Double(ray.DeltaZ);
 134571        Signed192 scaledHeight = NarrowRigidQueryValue(
 134572            WideArithmetic.MultiplySigned192(
 134573                height,
 134574                ray.Denominator));
 134575        startAxial = WideArithmetic.SubtractSigned192(
 134576            scaledHeight,
 134577            WideArithmetic.Double(ray.StartY));
 134578        axialVelocity =
 134579            WideArithmetic.SubtractSigned192(
 134580                default,
 134581                WideArithmetic.Double(ray.DeltaY));
 134582        maximumAxial = WideArithmetic.Double(scaledHeight);
 583
 134584        Signed320 heightSquared =
 134585            WideArithmetic.MultiplySigned192(height, height);
 134586        Signed320 radiusSquared =
 134587            WideArithmetic.MultiplySigned192(radius, radius);
 134588        Signed320 radialCoefficient =
 134589            AddRigidSquares(doubledDeltaX, doubledDeltaZ);
 134590        Signed320 radialProjection =
 134591            AddRigidProducts(
 134592                doubledStartX,
 134593                doubledDeltaX,
 134594                doubledStartZ,
 134595                doubledDeltaZ);
 134596        Signed320 radialConstant =
 134597            AddRigidSquares(doubledStartX, doubledStartZ);
 598        // The local point numerators already carry one quaternion denominator.
 599        // Keeping height and radius unscaled cancels the common positive D²
 600        // factor before the quadratic is formed. Under IsNormalized, D has at
 601        // most 65 magnitude bits, each rigid local numerator has fewer than
 602        // 130, and these factored coefficients have fewer than 390.
 134603        coefficient = WideArithmetic.SubtractSigned576(
 134604            WideArithmetic.MultiplySigned320(
 134605                heightSquared,
 134606                radialCoefficient),
 134607            WideArithmetic.MultiplySigned320(
 134608                radiusSquared,
 134609                WideArithmetic.MultiplySigned192(
 134610                    axialVelocity,
 134611                    axialVelocity)));
 134612        projection = WideArithmetic.SubtractSigned576(
 134613            WideArithmetic.MultiplySigned320(
 134614                heightSquared,
 134615                radialProjection),
 134616            WideArithmetic.MultiplySigned320(
 134617                radiusSquared,
 134618                WideArithmetic.MultiplySigned192(
 134619                    startAxial,
 134620                    axialVelocity)));
 134621        constant = WideArithmetic.SubtractSigned576(
 134622            WideArithmetic.MultiplySigned320(
 134623                heightSquared,
 134624                radialConstant),
 134625            WideArithmetic.MultiplySigned320(
 134626                radiusSquared,
 134627                WideArithmetic.MultiplySigned192(
 134628                    startAxial,
 134629                    startAxial)));
 134630    }
 631
 632    private static bool TryGetCenteredAxialBounds(
 633        Signed192 startY,
 634        Signed192 deltaY,
 635        Signed192 length,
 636        out RigidRayBound lower,
 637        out RigidRayBound upper) =>
 269638        TryGetLinearBounds(
 269639            WideArithmetic.Double(startY),
 269640            WideArithmetic.Double(deltaY),
 269641            WideArithmetic.SubtractSigned192(default, length),
 269642            length,
 269643            out lower,
 269644            out upper);
 645
 646    private static bool TryGetLinearBounds(
 647        Signed192 start,
 648        Signed192 delta,
 649        Signed192 minimum,
 650        Signed192 maximum,
 651        out RigidRayBound lower,
 652        out RigidRayBound upper)
 653    {
 403654        Signed192 one = Signed192.Signed(1L);
 403655        lower = new RigidRayBound(default, one);
 403656        upper = new RigidRayBound(one, one);
 403657        if (delta.IsZero)
 658        {
 5659            return WideArithmetic.SubtractSigned192(
 5660                    start,
 5661                    minimum).Sign >= 0
 5662                && WideArithmetic.SubtractSigned192(
 5663                    start,
 5664                    maximum).Sign <= 0;
 665        }
 666
 398667        RigidRayBound first = NormalizeRigidBound(
 398668            WideArithmetic.SubtractSigned192(minimum, start),
 398669            delta);
 398670        RigidRayBound second = NormalizeRigidBound(
 398671            WideArithmetic.SubtractSigned192(maximum, start),
 398672            delta);
 398673        if (CompareRigidBounds(first, second) > 0)
 261674            (first, second) = (second, first);
 398675        if (CompareRigidBounds(second, lower) < 0
 398676            || CompareRigidBounds(first, upper) > 0)
 677        {
 3678            return false;
 679        }
 680
 395681        if (CompareRigidBounds(first, lower) > 0)
 4682            lower = first;
 395683        if (CompareRigidBounds(second, upper) < 0)
 4684            upper = second;
 395685        return CompareRigidBounds(lower, upper) <= 0;
 686    }
 687
 688    private static RigidRayBound NormalizeRigidBound(
 689        Signed192 numerator,
 690        Signed192 denominator)
 691    {
 796692        if (denominator.Sign >= 0)
 274693            return new RigidRayBound(numerator, denominator);
 694
 522695        return new RigidRayBound(
 522696            WideArithmetic.SubtractSigned192(default, numerator),
 522697            WideArithmetic.SubtractSigned192(default, denominator));
 698    }
 699
 700    private static int CompareRigidBounds(
 701        RigidRayBound left,
 702        RigidRayBound right) =>
 2376703        WideArithmetic.MultiplySubtract(
 2376704            left.Numerator,
 2376705            right.Denominator,
 2376706            right.Numerator,
 2376707            left.Denominator).Sign;
 708
 709    private static bool IsCylinderContained(
 710        Signed192 x,
 711        Signed192 y,
 712        Signed192 z,
 713        Signed192 length,
 714        Signed192 radius,
 715        bool strict)
 716    {
 538717        int lower = WideArithmetic.AddSigned192(
 538718            WideArithmetic.Double(y),
 538719            length).Sign;
 538720        int upper = WideArithmetic.SubtractSigned192(
 538721            WideArithmetic.Double(y),
 538722            length).Sign;
 538723        int radial = WideArithmetic.SubtractSigned320(
 538724            AddRigidSquares(x, z),
 538725            WideArithmetic.MultiplySigned192(radius, radius)).Sign;
 538726        return strict
 538727            ? lower > 0 && upper < 0 && radial < 0
 538728            : lower >= 0 && upper <= 0 && radial <= 0;
 729    }
 730
 731    private static bool IsCapsuleContained(
 732        Signed192 x,
 733        Signed192 y,
 734        Signed192 z,
 735        Signed192 length,
 736        Signed192 radius,
 737        bool strict)
 738    {
 268739        if (IsCylinderContained(x, y, z, length, radius, strict))
 2740            return true;
 741
 266742        Signed192 doubledX = WideArithmetic.Double(x);
 266743        Signed192 doubledY = WideArithmetic.Double(y);
 266744        Signed192 doubledZ = WideArithmetic.Double(z);
 266745        Signed192 doubledRadius = WideArithmetic.Double(radius);
 266746        Signed320 radiusSquared =
 266747            WideArithmetic.MultiplySigned192(
 266748                doubledRadius,
 266749                doubledRadius);
 266750        Signed320 negativeCap = AddRigidSquares(
 266751            doubledX,
 266752            WideArithmetic.AddSigned192(doubledY, length),
 266753            doubledZ);
 266754        Signed320 positiveCap = AddRigidSquares(
 266755            doubledX,
 266756            WideArithmetic.SubtractSigned192(doubledY, length),
 266757            doubledZ);
 266758        int negative = WideArithmetic.SubtractSigned320(
 266759            negativeCap,
 266760            radiusSquared).Sign;
 266761        int positive = WideArithmetic.SubtractSigned320(
 266762            positiveCap,
 266763            radiusSquared).Sign;
 266764        return strict
 266765            ? negative < 0 || positive < 0
 266766            : negative <= 0 || positive <= 0;
 767    }
 768
 769    private static bool IsConeContained(
 770        Signed192 axial,
 771        Signed192 maximumAxial,
 772        int polynomialSign,
 773        bool strict)
 774    {
 268775        int maximum =
 268776            WideArithmetic.SubtractSigned192(
 268777                axial,
 268778                maximumAxial).Sign;
 268779        return strict
 268780            ? axial.Sign > 0 && maximum < 0 && polynomialSign < 0
 268781            : axial.Sign >= 0 && maximum <= 0 && polynomialSign <= 0;
 782    }
 783
 784    private static Signed704 EvaluatePolynomialAtOne(
 785        Signed576 coefficient,
 786        Signed576 projection,
 787        Signed576 constant) =>
 134788        WideArithmetic.AddSigned704(
 134789            WideArithmetic.AddSigned704(
 134790                Signed704.ExtendValue(coefficient),
 134791                WideArithmetic.AddSigned704(
 134792                    Signed704.ExtendValue(projection),
 134793                    Signed704.ExtendValue(projection))),
 134794            Signed704.ExtendValue(constant));
 795
 796    private static Signed320 AddRigidSquares(
 797        Signed192 first,
 798        Signed192 second) =>
 2400799        WideArithmetic.AddSigned320(
 2400800            WideArithmetic.MultiplySigned192(first, first),
 2400801            WideArithmetic.MultiplySigned192(second, second));
 802
 803    private static Signed320 AddRigidSquares(
 804        Signed192 first,
 805        Signed192 second,
 806        Signed192 third) =>
 1068807        WideArithmetic.AddSigned320(
 1068808            AddRigidSquares(first, second),
 1068809            WideArithmetic.MultiplySigned192(third, third));
 810
 811    private static Signed320 AddRigidProducts(
 812        Signed192 firstLeft,
 813        Signed192 firstRight,
 814        Signed192 secondLeft,
 815        Signed192 secondRight) =>
 665816        WideArithmetic.AddSigned320(
 665817            WideArithmetic.MultiplySigned192(
 665818                firstLeft,
 665819                firstRight),
 665820            WideArithmetic.MultiplySigned192(
 665821                secondLeft,
 665822                secondRight));
 823
 824    private static Signed320 AddRigidProducts(
 825        Signed192 firstLeft,
 826        Signed192 firstRight,
 827        Signed192 secondLeft,
 828        Signed192 secondRight,
 829        Signed192 thirdLeft,
 830        Signed192 thirdRight) =>
 268831        WideArithmetic.AddSigned320(
 268832            AddRigidProducts(
 268833                firstLeft,
 268834                firstRight,
 268835                secondLeft,
 268836                secondRight),
 268837            WideArithmetic.MultiplySigned192(
 268838                thirdLeft,
 268839                thirdRight));
 840
 841    private static void MergeRigidInterval(
 842        bool candidateFound,
 843        Fixed64 candidateEntry,
 844        Fixed64 candidateExit,
 845        ref bool found,
 846        ref Fixed64 entry,
 847        ref Fixed64 exit)
 848    {
 399849        if (!candidateFound)
 4850            return;
 395851        if (!found)
 852        {
 133853            found = true;
 133854            entry = candidateEntry;
 133855            exit = candidateExit;
 133856            return;
 857        }
 858
 262859        if (candidateEntry < entry)
 1860            entry = candidateEntry;
 262861        if (candidateExit > exit)
 1862            exit = candidateExit;
 262863    }
 864}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Sphere.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.Sphere.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
 8namespace FixedMathSharp.Geometry;
 9
 10/// <content>
 11/// Provides high-precision (wide arithmetic) contact generation and
 12/// swept-sphere intersection tests between an oriented box and a sphere.
 13/// </content>
 14internal static partial class WideOrientedBox
 15{
 16    internal static bool TryGetSweptSphereIntersectionDistance(
 17        Vector3d center,
 18        FixedQuaternion orientation,
 19        Vector3d halfExtents,
 20        FixedSegment query,
 21        Fixed64 sphericalExpansion,
 22        Fixed64 segmentLength,
 23        out Fixed64 distance)
 24    {
 4725        WideRationalBasis3d basis = new(orientation);
 4726        GetPointProjections(
 4727            query.Start,
 4728            center,
 4729            basis,
 4730            out Signed320 startX,
 4731            out Signed320 startY,
 4732            out Signed320 startZ);
 4733        GetPointProjections(
 4734            query.End,
 4735            center,
 4736            basis,
 4737            out Signed320 endX,
 4738            out Signed320 endY,
 4739            out Signed320 endZ);
 4740        Signed192 narrowStartX = Signed192.NarrowValue(startX);
 4741        Signed192 narrowStartY = Signed192.NarrowValue(startY);
 4742        Signed192 narrowStartZ = Signed192.NarrowValue(startZ);
 4743        Signed192 narrowEndX = Signed192.NarrowValue(endX);
 4744        Signed192 narrowEndY = Signed192.NarrowValue(endY);
 4745        Signed192 narrowEndZ = Signed192.NarrowValue(endZ);
 4746        Signed192 extentX = Signed192.NarrowValue(
 4747            GetExtentNumerator(halfExtents.X, basis.Denominator));
 4748        Signed192 extentY = Signed192.NarrowValue(
 4749            GetExtentNumerator(halfExtents.Y, basis.Denominator));
 4750        Signed192 extentZ = Signed192.NarrowValue(
 4751            GetExtentNumerator(halfExtents.Z, basis.Denominator));
 52
 4753        return Geometry.WideFiniteAxisIntersection
 4754            .TryGetSphericallyExpandedProjectedBoxFirstDistance(
 4755                narrowStartX,
 4756                narrowStartY,
 4757                narrowStartZ,
 4758                narrowEndX,
 4759                narrowEndY,
 4760                narrowEndZ,
 4761                extentX,
 4762                extentY,
 4763                extentZ,
 4764                basis.Denominator,
 4765                sphericalExpansion,
 4766                segmentLength,
 4767                out distance);
 68    }
 69
 70    internal static bool TryGetSphereContact(
 71        Vector3d center,
 72        FixedQuaternion orientation,
 73        Vector3d halfExtents,
 74        Vector3d sphereCenter,
 75        FixedQuaternion sphereRotation,
 76        Fixed64 sphereRadius,
 77        out FixedContactAnchors contact)
 78    {
 1979        WideRationalBasis3d basis = new(orientation);
 1980        GetPointProjections(
 1981            sphereCenter,
 1982            center,
 1983            basis,
 1984            out Signed320 localX,
 1985            out Signed320 localY,
 1986            out Signed320 localZ);
 1987        Signed320 xExtent = GetExtentNumerator(halfExtents.X, basis.Denominator);
 1988        Signed320 yExtent = GetExtentNumerator(halfExtents.Y, basis.Denominator);
 1989        Signed320 zExtent = GetExtentNumerator(halfExtents.Z, basis.Denominator);
 1990        bool outsideX = WideArithmetic.CompareMagnitude(localX, xExtent) > 0;
 1991        bool outsideY = WideArithmetic.CompareMagnitude(localY, yExtent) > 0;
 1992        bool outsideZ = WideArithmetic.CompareMagnitude(localZ, zExtent) > 0;
 93
 1994        Signed320 boxLocalX = GetClampedNumerator(localX, xExtent, outsideX);
 1995        Signed320 boxLocalY = GetClampedNumerator(localY, yExtent, outsideY);
 1996        Signed320 boxLocalZ = GetClampedNumerator(localZ, zExtent, outsideZ);
 1997        if (!(outsideX || outsideY || outsideZ))
 98        {
 1199            return TryGetContainedSphereContact(
 11100                center,
 11101                orientation,
 11102                basis,
 11103                sphereCenter,
 11104                sphereRotation,
 11105                sphereRadius,
 11106                localX,
 11107                localY,
 11108                localZ,
 11109                xExtent,
 11110                yExtent,
 11111                zExtent,
 11112                boxLocalX,
 11113                boxLocalY,
 11114                boxLocalZ,
 11115                out contact);
 116        }
 117
 8118        Signed320 denominatorSquared = WideArithmetic.MultiplySigned192(
 8119            basis.Denominator,
 8120            basis.Denominator);
 8121        GetRationalLocalOffsetNumerators(
 8122            basis,
 8123            boxLocalX,
 8124            boxLocalY,
 8125            boxLocalZ,
 8126            out Signed576 boxOffsetX,
 8127            out Signed576 boxOffsetY,
 8128            out Signed576 boxOffsetZ);
 8129        Signed576 deltaX = GetOriginRelativeNumerator(
 8130            sphereCenter.X,
 8131            center.X,
 8132            denominatorSquared,
 8133            boxOffsetX);
 8134        Signed576 deltaY = GetOriginRelativeNumerator(
 8135            sphereCenter.Y,
 8136            center.Y,
 8137            denominatorSquared,
 8138            boxOffsetY);
 8139        Signed576 deltaZ = GetOriginRelativeNumerator(
 8140            sphereCenter.Z,
 8141            center.Z,
 8142            denominatorSquared,
 8143            boxOffsetZ);
 8144        Signed832 squaredDistance = SumSquares(deltaX, deltaY, deltaZ);
 8145        Signed576 scaledRadius = WideArithmetic.MultiplySigned320(
 8146            Signed320.ExtendValue(Signed192.Raw(sphereRadius)),
 8147            denominatorSquared);
 8148        Signed832 squaredRadius = WideArithmetic.MultiplySigned576ToSigned832(
 8149            scaledRadius,
 8150            scaledRadius);
 8151        if (WideArithmetic.SubtractSigned832(squaredDistance, squaredRadius).Sign > 0)
 152        {
 1153            contact = default;
 1154            return false;
 155        }
 156
 7157        Vector3d normal = WideNormalization.GetNormalized(deltaX, deltaY, deltaZ);
 7158        Vector3d boxLocalPoint = GetRationalLocalPoint(
 7159            basis,
 7160            boxLocalX,
 7161            boxLocalY,
 7162            boxLocalZ);
 7163        FixedPointAnchor sphereAnchor = GetSphereSurfaceAnchor(
 7164            sphereCenter,
 7165            sphereRotation,
 7166            sphereRadius,
 7167            deltaX,
 7168            deltaY,
 7169            deltaZ,
 7170            true);
 7171        Fixed64 depth = GetRoundedRadialDepth(
 7172            sphereRadius,
 7173            squaredDistance,
 7174            denominatorSquared);
 7175        contact = new FixedContactAnchors(
 7176            new FixedPointAnchor(
 7177                center,
 7178                orientation,
 7179                boxLocalPoint),
 7180            sphereAnchor,
 7181            normal,
 7182            depth,
 7183            false);
 7184        return true;
 185    }
 186
 187    private static bool TryGetContainedSphereContact(
 188        Vector3d center,
 189        FixedQuaternion orientation,
 190        WideRationalBasis3d basis,
 191        Vector3d sphereCenter,
 192        FixedQuaternion sphereRotation,
 193        Fixed64 sphereRadius,
 194        Signed320 localX,
 195        Signed320 localY,
 196        Signed320 localZ,
 197        Signed320 xExtent,
 198        Signed320 yExtent,
 199        Signed320 zExtent,
 200        Signed320 boxLocalX,
 201        Signed320 boxLocalY,
 202        Signed320 boxLocalZ,
 203        out FixedContactAnchors contact)
 204    {
 11205        Signed320 xClearance = WideArithmetic.SubtractSigned320(
 11206            xExtent,
 11207            GetMagnitude(localX));
 11208        Signed320 yClearance = WideArithmetic.SubtractSigned320(
 11209            yExtent,
 11210            GetMagnitude(localY));
 11211        Signed320 zClearance = WideArithmetic.SubtractSigned320(
 11212            zExtent,
 11213            GetMagnitude(localZ));
 214        int axis;
 215        bool negative;
 11216        if (WideArithmetic.CompareMagnitude(xClearance, yClearance) <= 0
 11217            && WideArithmetic.CompareMagnitude(xClearance, zClearance) <= 0)
 218        {
 7219            axis = 0;
 7220            negative = localX.Sign < 0;
 7221            boxLocalX = negative
 7222                ? WideArithmetic.SubtractSigned320(default, xExtent)
 7223                : xExtent;
 224        }
 4225        else if (WideArithmetic.CompareMagnitude(yClearance, zClearance) <= 0)
 226        {
 2227            axis = 1;
 2228            negative = localY.Sign < 0;
 2229            boxLocalY = negative
 2230                ? WideArithmetic.SubtractSigned320(default, yExtent)
 2231                : yExtent;
 232        }
 233        else
 234        {
 2235            axis = 2;
 2236            negative = localZ.Sign < 0;
 2237            boxLocalZ = negative
 2238                ? WideArithmetic.SubtractSigned320(default, zExtent)
 2239                : zExtent;
 240        }
 241
 11242        Vector3d boxLocalPoint = GetRationalLocalPoint(
 11243            basis,
 11244            boxLocalX,
 11245            boxLocalY,
 11246            boxLocalZ);
 247
 11248        Vector3d normal = axis switch
 11249        {
 7250            0 => GetAxis(
 7251                basis.Xx,
 7252                basis.Xy,
 7253                basis.Xz,
 7254                basis.Denominator,
 7255                negative),
 2256            1 => GetAxis(
 2257                basis.Yx,
 2258                basis.Yy,
 2259                basis.Yz,
 2260                basis.Denominator,
 2261                negative),
 2262            _ => GetAxis(
 2263                basis.Zx,
 2264                basis.Zy,
 2265                basis.Zz,
 2266                basis.Denominator,
 2267                negative),
 11268        };
 11269        FixedPointAnchor sphereAnchor = axis switch
 11270        {
 7271            0 => GetSphereSurfaceAnchor(
 7272                sphereCenter,
 7273                sphereRotation,
 7274                sphereRadius,
 7275                ToSigned576(basis.Xx),
 7276                ToSigned576(basis.Xy),
 7277                ToSigned576(basis.Xz),
 7278                !negative),
 2279            1 => GetSphereSurfaceAnchor(
 2280                sphereCenter,
 2281                sphereRotation,
 2282                sphereRadius,
 2283                ToSigned576(basis.Yx),
 2284                ToSigned576(basis.Yy),
 2285                ToSigned576(basis.Yz),
 2286                !negative),
 2287            _ => GetSphereSurfaceAnchor(
 2288                sphereCenter,
 2289                sphereRotation,
 2290                sphereRadius,
 2291                ToSigned576(basis.Zx),
 2292                ToSigned576(basis.Zy),
 2293                ToSigned576(basis.Zz),
 2294                !negative),
 11295        };
 11296        Signed320 clearance = axis switch
 11297        {
 7298            0 => xClearance,
 2299            1 => yClearance,
 2300            _ => zClearance,
 11301        };
 11302        Signed320 depthNumerator = WideArithmetic.AddSigned320(
 11303            WideArithmetic.MultiplySigned192(
 11304                Signed192.Raw(sphereRadius),
 11305                basis.Denominator),
 11306            clearance);
 11307        Signed320 maximumNumerator = WideArithmetic.MultiplySigned192(
 11308            Signed192.Raw(Fixed64.MaxValue),
 11309            basis.Denominator);
 11310        bool depthIsClamped = CompareSigned(
 11311            depthNumerator,
 11312            maximumNumerator) > 0;
 313        Fixed64 depth;
 11314        if (depthIsClamped)
 315        {
 1316            depth = Fixed64.MaxValue;
 317        }
 318        else
 319        {
 10320            _ = Fixed64.TryGetSignedRawRatio(
 10321                Signed576.ExtendValue(depthNumerator),
 10322                ToSigned576(basis.Denominator),
 10323                out depth);
 324        }
 325
 11326        contact = new FixedContactAnchors(
 11327            new FixedPointAnchor(
 11328                center,
 11329                orientation,
 11330                boxLocalPoint),
 11331            sphereAnchor,
 11332            normal,
 11333            depth,
 11334            depthIsClamped);
 11335        return true;
 336    }
 337
 338    private static FixedPointAnchor GetSphereSurfaceAnchor(
 339        Vector3d sphereCenter,
 340        FixedQuaternion rotation,
 341        Fixed64 radius,
 342        Signed576 directionX,
 343        Signed576 directionY,
 344        Signed576 directionZ,
 345        bool negate)
 346    {
 18347        if (negate)
 348        {
 15349            directionX = WideArithmetic.SubtractSigned576(
 15350                default,
 15351                directionX);
 15352            directionY = WideArithmetic.SubtractSigned576(
 15353                default,
 15354                directionY);
 15355            directionZ = WideArithmetic.SubtractSigned576(
 15356                default,
 15357                directionZ);
 358        }
 359
 18360        WideRationalBasis3d basis = new(rotation);
 18361        Signed576 localX = GetProjectionNumerator(
 18362            directionX,
 18363            directionY,
 18364            directionZ,
 18365            basis.Xx,
 18366            basis.Xy,
 18367            basis.Xz);
 18368        Signed576 localY = GetProjectionNumerator(
 18369            directionX,
 18370            directionY,
 18371            directionZ,
 18372            basis.Yx,
 18373            basis.Yy,
 18374            basis.Yz);
 18375        Signed576 localZ = GetProjectionNumerator(
 18376            directionX,
 18377            directionY,
 18378            directionZ,
 18379            basis.Zx,
 18380            basis.Zy,
 18381            basis.Zz);
 18382        Vector3d localDirection = WideNormalization.GetNormalized(
 18383            localX,
 18384            localY,
 18385            localZ);
 18386        Vector3d roundedOffset = localDirection * radius;
 18387        FixedPointAnchorTerm3d exactTerm =
 18388            FixedPointAnchorTerm3d.CreateRadialSupport(
 18389                localDirection,
 18390                radius,
 18391                roundedOffset);
 18392        return new FixedPointAnchor(
 18393            sphereCenter,
 18394            rotation,
 18395            Vector3d.Zero,
 18396            roundedOffset,
 18397            exactTerm);
 398    }
 399
 400    private static Signed576 GetProjectionNumerator(
 401        Signed576 directionX,
 402        Signed576 directionY,
 403        Signed576 directionZ,
 404        Signed192 axisX,
 405        Signed192 axisY,
 406        Signed192 axisZ) =>
 54407        WideArithmetic.AddSigned576(
 54408            WideArithmetic.AddSigned576(
 54409                WideArithmetic.MultiplySigned576(directionX, axisX),
 54410                WideArithmetic.MultiplySigned576(directionY, axisY)),
 54411            WideArithmetic.MultiplySigned576(directionZ, axisZ));
 412
 413    private static void GetRationalLocalOffsetNumerators(
 414        WideRationalBasis3d basis,
 415        Signed320 localX,
 416        Signed320 localY,
 417        Signed320 localZ,
 418        out Signed576 x,
 419        out Signed576 y,
 420        out Signed576 z)
 421    {
 8422        x = GetRationalLocalOffsetNumerator(
 8423            basis.Xx,
 8424            basis.Yx,
 8425            basis.Zx,
 8426            localX,
 8427            localY,
 8428            localZ);
 8429        y = GetRationalLocalOffsetNumerator(
 8430            basis.Xy,
 8431            basis.Yy,
 8432            basis.Zy,
 8433            localX,
 8434            localY,
 8435            localZ);
 8436        z = GetRationalLocalOffsetNumerator(
 8437            basis.Xz,
 8438            basis.Yz,
 8439            basis.Zz,
 8440            localX,
 8441            localY,
 8442            localZ);
 8443    }
 444
 445    private static Signed576 GetRationalLocalOffsetNumerator(
 446        Signed192 axisX,
 447        Signed192 axisY,
 448        Signed192 axisZ,
 449        Signed320 localX,
 450        Signed320 localY,
 451        Signed320 localZ) =>
 24452        WideArithmetic.AddSigned576(
 24453            WideArithmetic.AddSigned576(
 24454                WideArithmetic.MultiplySigned320(
 24455                    localX,
 24456                    Signed320.ExtendValue(axisX)),
 24457                WideArithmetic.MultiplySigned320(
 24458                    localY,
 24459                    Signed320.ExtendValue(axisY))),
 24460            WideArithmetic.MultiplySigned320(
 24461                localZ,
 24462                Signed320.ExtendValue(axisZ)));
 463
 464    private static Signed576 GetOriginRelativeNumerator(
 465        Fixed64 point,
 466        Fixed64 origin,
 467        Signed320 denominatorSquared,
 468        Signed576 offsetNumerator) =>
 24469        WideArithmetic.SubtractSigned576(
 24470            WideArithmetic.MultiplySigned320(
 24471                Signed320.ExtendValue(
 24472                    WideArithmetic.SubtractSigned192(Signed192.Raw(point), Signed192.Raw(origin))),
 24473                denominatorSquared),
 24474            offsetNumerator);
 475
 476    private static Signed832 SumSquares(
 477        Signed576 x,
 478        Signed576 y,
 479        Signed576 z) =>
 8480        WideArithmetic.AddSigned832(
 8481            WideArithmetic.AddSigned832(
 8482                WideArithmetic.MultiplySigned576ToSigned832(x, x),
 8483                WideArithmetic.MultiplySigned576ToSigned832(y, y)),
 8484            WideArithmetic.MultiplySigned576ToSigned832(z, z));
 485
 486    private static Fixed64 GetRoundedRadialDepth(
 487        Fixed64 radius,
 488        Signed832 squaredDistance,
 489        Signed320 denominator)
 490    {
 7491        Signed576 root = WideArithmetic.GetFloorSquareRootOfProduct(
 7492            squaredDistance,
 7493            Signed192.Signed(1L));
 7494        _ = Fixed64.TryGetSignedRawRatio(
 7495            root,
 7496            Signed576.ExtendValue(denominator),
 7497            out Fixed64 roundedDistance);
 7498        Fixed64 depth = radius - roundedDistance;
 7499        CorrectRoundedRadialDepth(
 7500            radius,
 7501            squaredDistance,
 7502            denominator,
 7503            ref depth);
 7504        return depth;
 505    }
 506
 507    private static void CorrectRoundedRadialDepth(
 508        Fixed64 radius,
 509        Signed832 squaredDistance,
 510        Signed320 denominator,
 511        ref Fixed64 depth)
 512    {
 7513        if (depth > Fixed64.Zero)
 514        {
 6515            Signed192 lowerMidpoint = WideArithmetic.SubtractSigned192(
 6516                WideArithmetic.AddSigned192(Signed192.Raw(depth), Signed192.Raw(depth)),
 6517                Signed192.Signed(1L));
 6518            int comparison = CompareRadialDepthToTwiceRaw(
 6519                radius,
 6520                squaredDistance,
 6521                denominator,
 6522                lowerMidpoint);
 6523            depth = Fixed64.FromRaw(
 6524                depth.m_rawValue
 6525                - GetLowerMidpointAdjustment(
 6526                    comparison,
 6527                    depth.m_rawValue));
 528        }
 529
 7530        Signed192 upperMidpoint = WideArithmetic.AddSigned192(
 7531            WideArithmetic.AddSigned192(Signed192.Raw(depth), Signed192.Raw(depth)),
 7532            Signed192.Signed(1L));
 7533        int upperComparison = CompareRadialDepthToTwiceRaw(
 7534            radius,
 7535            squaredDistance,
 7536            denominator,
 7537            upperMidpoint);
 7538        long remainingRaw = radius.m_rawValue - depth.m_rawValue;
 7539        long hasRoom =
 7540            (long)((ulong)(remainingRaw | -remainingRaw) >> 63);
 7541        depth = Fixed64.FromRaw(
 7542            depth.m_rawValue
 7543            + (GetUpperMidpointAdjustment(
 7544                upperComparison,
 7545                depth.m_rawValue) & hasRoom));
 7546    }
 547
 548    private static long GetLowerMidpointAdjustment(
 549        int comparison,
 550        long depthRaw)
 551    {
 6552        int negative = (int)((uint)comparison >> 31);
 6553        int nonzero = (int)((uint)(comparison | -comparison) >> 31);
 6554        int zero = nonzero ^ 1;
 6555        int oddTie = zero & (int)(depthRaw & 1L);
 6556        return negative | oddTie;
 557    }
 558
 559    private static long GetUpperMidpointAdjustment(
 560        int comparison,
 561        long depthRaw)
 562    {
 7563        int positive = (int)((uint)-comparison >> 31);
 7564        int nonzero = (int)((uint)(comparison | -comparison) >> 31);
 7565        int zero = nonzero ^ 1;
 7566        int oddTie = zero & (int)(depthRaw & 1L);
 7567        return positive | oddTie;
 568    }
 569
 570    private static int CompareRadialDepthToTwiceRaw(
 571        Fixed64 radius,
 572        Signed832 squaredDistance,
 573        Signed320 denominator,
 574        Signed192 twiceRaw)
 575    {
 13576        Signed192 twiceRadius = WideArithmetic.AddSigned192(
 13577            Signed192.Raw(radius),
 13578            Signed192.Raw(radius));
 13579        Signed192 remaining = WideArithmetic.SubtractSigned192(
 13580            twiceRadius,
 13581            twiceRaw);
 13582        Signed576 threshold = WideArithmetic.MultiplySigned320(
 13583            Signed320.ExtendValue(remaining),
 13584            denominator);
 13585        Signed832 thresholdSquared =
 13586            WideArithmetic.MultiplySigned576ToSigned832(threshold, threshold);
 13587        Signed832 fourSquaredDistance = WideArithmetic.AddSigned832(
 13588            WideArithmetic.AddSigned832(squaredDistance, squaredDistance),
 13589            WideArithmetic.AddSigned832(squaredDistance, squaredDistance));
 13590        return WideArithmetic.SubtractSigned832(
 13591            thresholdSquared,
 13592            fourSquaredDistance).Sign;
 593    }
 594}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Triangle.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.Triangle.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/// Oriented box vs. triangle contact generation using the separating axis theorem (SAT).
 14/// </content>
 15internal static partial class WideOrientedBox
 16{
 17    internal static bool TryGetTriangleContact(
 18        Vector3d boxCenter,
 19        FixedQuaternion boxOrientation,
 20        Vector3d boxHalfExtents,
 21        Vector3d triangleOrigin,
 22        FixedQuaternion triangleRotation,
 23        FixedTriangle triangle,
 24        out FixedContactAnchors contact)
 25    {
 15026        if (triangle.IsDegenerate)
 27        {
 128            contact = default;
 129            return false;
 30        }
 31
 14932        WideRationalBasis3d boxBasis = new(boxOrientation);
 14933        WideRationalBasis3d triangleBasis = new(triangleRotation);
 14934        WideRationalBasis3d relativeBasis =
 14935            WideRationalBasis3d.CreateRelative(boxBasis, triangleBasis);
 14936        Signed320 unit = Signed320.One;
 14937        Span<WideAxis3> boxAxes = stackalloc WideAxis3[3]
 14938        {
 14939            new(unit, default, default),
 14940            new(default, unit, default),
 14941            new(default, default, unit),
 14942        };
 14943        GetRelativeLocalPointNumerators(
 14944            triangleOrigin,
 14945            boxCenter,
 14946            boxBasis,
 14947            out Signed192 translationX,
 14948            out Signed192 translationY,
 14949            out Signed192 translationZ);
 14950        var triangleTranslation = new WideAxis3(
 14951            WideArithmetic.MultiplySigned192(
 14952                translationX,
 14953                triangleBasis.Denominator),
 14954            WideArithmetic.MultiplySigned192(
 14955                translationY,
 14956                triangleBasis.Denominator),
 14957            WideArithmetic.MultiplySigned192(
 14958                translationZ,
 14959                triangleBasis.Denominator));
 14960        var best = default(WidePointSpanPenetration);
 118861        for (int index = 0; index < boxAxes.Length; index++)
 62        {
 44763            if (!TryKeepTriangleAxis(
 44764                    boxAxes[index],
 44765                    boxHalfExtents,
 44766                    relativeBasis,
 44767                    triangleTranslation,
 44768                    triangle,
 44769                    ref best))
 70            {
 271                contact = default;
 272                return false;
 73            }
 74        }
 75
 14776        WideGeometry.GetDifferenceCrossProduct3D(
 14777            triangle.B.X,
 14778            triangle.A.X,
 14779            triangle.B.Y,
 14780            triangle.A.Y,
 14781            triangle.B.Z,
 14782            triangle.A.Z,
 14783            triangle.C.X,
 14784            triangle.A.X,
 14785            triangle.C.Y,
 14786            triangle.A.Y,
 14787            triangle.C.Z,
 14788            triangle.A.Z,
 14789            out Signed192 normalX,
 14790            out Signed192 normalY,
 14791            out Signed192 normalZ);
 14792        if (!TryKeepTriangleAxis(
 14793                WideRigidProjection.TransformLocalAxis(
 14794                    relativeBasis,
 14795                    normalX,
 14796                    normalY,
 14797                    normalZ),
 14798                boxHalfExtents,
 14799                relativeBasis,
 147100                triangleTranslation,
 147101                triangle,
 147102                ref best)
 147103            || !TryKeepTriangleEdgeAxes(
 147104                triangle.A,
 147105                triangle.B,
 147106                boxAxes,
 147107                boxHalfExtents,
 147108                relativeBasis,
 147109                triangleTranslation,
 147110                triangle,
 147111                ref best)
 147112            || !TryKeepTriangleEdgeAxes(
 147113                triangle.B,
 147114                triangle.C,
 147115                boxAxes,
 147116                boxHalfExtents,
 147117                relativeBasis,
 147118                triangleTranslation,
 147119                triangle,
 147120                ref best)
 147121            || !TryKeepTriangleEdgeAxes(
 147122                triangle.C,
 147123                triangle.A,
 147124                boxAxes,
 147125                boxHalfExtents,
 147126                relativeBasis,
 147127                triangleTranslation,
 147128                triangle,
 147129                ref best))
 130        {
 4131            contact = default;
 4132            return false;
 133        }
 134
 143135        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 143136        WideRigidProjection.TransformLocalAxis(
 143137            boxBasis,
 143138            orientedAxis,
 143139            out Signed576 worldX,
 143140            out Signed576 worldY,
 143141            out Signed576 worldZ);
 143142        Vector3d contactNormal = WideNormalization.GetNormalized(
 143143            worldX,
 143144            worldY,
 143145            worldZ);
 143146        Vector3d triangleLocalPoint = GetTriangleSupportLocalPoint(
 143147            triangle,
 143148            relativeBasis,
 143149            orientedAxis);
 143150        Fixed64 depth = best.GetRoundedDepth(out bool depthIsClamped);
 143151        contact = new FixedContactAnchors(
 143152            new FixedPointAnchor(
 143153                boxCenter,
 143154                boxOrientation,
 143155                GetLocalSupportPoint(
 143156                    contactNormal,
 143157                    boxOrientation,
 143158                    boxHalfExtents)),
 143159            new FixedPointAnchor(
 143160                triangleOrigin,
 143161                triangleRotation,
 143162                triangleLocalPoint),
 143163            contactNormal,
 143164            depth,
 143165            depthIsClamped);
 143166        return true;
 167    }
 168
 169    private static bool TryKeepTriangleEdgeAxes(
 170        Vector3d edgeStart,
 171        Vector3d edgeEnd,
 172        ReadOnlySpan<WideAxis3> boxAxes,
 173        Vector3d boxHalfExtents,
 174        in WideRationalBasis3d relativeBasis,
 175        in WideAxis3 triangleTranslation,
 176        in FixedTriangle triangle,
 177        ref WidePointSpanPenetration best)
 178    {
 435179        WideAxis3 edge = WideRigidProjection.TransformLocalAxis(
 435180            relativeBasis,
 435181            WideArithmetic.SubtractSigned192(
 435182                Signed192.Raw(edgeEnd.X),
 435183                Signed192.Raw(edgeStart.X)),
 435184            WideArithmetic.SubtractSigned192(
 435185                Signed192.Raw(edgeEnd.Y),
 435186                Signed192.Raw(edgeStart.Y)),
 435187            WideArithmetic.SubtractSigned192(
 435188                Signed192.Raw(edgeEnd.Z),
 435189                Signed192.Raw(edgeStart.Z)));
 3474190        for (int axisIndex = 0; axisIndex < boxAxes.Length; axisIndex++)
 191        {
 1305192            if (!TryKeepTriangleAxis(
 1305193                    WideAxis3.Cross(boxAxes[axisIndex], edge),
 1305194                    boxHalfExtents,
 1305195                    relativeBasis,
 1305196                    triangleTranslation,
 1305197                    triangle,
 1305198                    ref best))
 199            {
 3200                return false;
 201            }
 202        }
 432203        return true;
 204    }
 205
 206    private static bool TryKeepTriangleAxis(
 207        in WideAxis3 axis,
 208        Vector3d boxHalfExtents,
 209        in WideRationalBasis3d relativeBasis,
 210        in WideAxis3 triangleTranslation,
 211        in FixedTriangle triangle,
 212        ref WidePointSpanPenetration best)
 213    {
 1899214        if (axis.IsZero)
 20215            return true;
 216
 1879217        WideRigidProjection.GetLocalAxisProjections(
 1879218            axis,
 1879219            relativeBasis,
 1879220            out Signed576 localAxisX,
 1879221            out Signed576 localAxisY,
 1879222            out Signed576 localAxisZ);
 1879223        Signed576 first = WideRigidProjection.GetLocalOffsetProjection(
 1879224            triangle.A,
 1879225            localAxisX,
 1879226            localAxisY,
 1879227            localAxisZ);
 1879228        Signed576 second = WideRigidProjection.GetLocalOffsetProjection(
 1879229            triangle.B,
 1879230            localAxisX,
 1879231            localAxisY,
 1879232            localAxisZ);
 1879233        Signed576 third = WideRigidProjection.GetLocalOffsetProjection(
 1879234            triangle.C,
 1879235            localAxisX,
 1879236            localAxisY,
 1879237            localAxisZ);
 1879238        Signed576 minimum = first;
 1879239        Signed576 maximum = first;
 1879240        WideRigidProjection.IncludeProjection(second, ref minimum, ref maximum);
 1879241        WideRigidProjection.IncludeProjection(third, ref minimum, ref maximum);
 242
 1879243        Signed576 originProjection = WideAxis3.Dot(
 1879244            axis,
 1879245            triangleTranslation);
 1879246        minimum = WideArithmetic.AddSigned576(originProjection, minimum);
 1879247        maximum = WideArithmetic.AddSigned576(originProjection, maximum);
 1879248        Signed576 boxRadius = WideArithmetic.MultiplySigned576(
 1879249            GetLocalBoxProjectionRadiusNumerator(axis, boxHalfExtents),
 1879250            relativeBasis.Denominator);
 1879251        Signed576 pushBoxNegative = WideArithmetic.SubtractSigned576(
 1879252            boxRadius,
 1879253            minimum);
 1879254        Signed576 pushBoxPositive = WideArithmetic.AddSigned576(
 1879255            maximum,
 1879256            boxRadius);
 1879257        if (pushBoxNegative.Sign < 0 || pushBoxPositive.Sign < 0)
 6258            return false;
 259
 1873260        bool negate =
 1873261            CompareSigned(pushBoxPositive, pushBoxNegative) < 0;
 1873262        Signed576 overlap = negate
 1873263            ? pushBoxPositive
 1873264            : pushBoxNegative;
 1873265        Signed320 commonDenominator =
 1873266            Signed320.ExtendValue(relativeBasis.Denominator);
 1873267        Signed576 squaredAxisLength = axis.SquaredLength;
 1873268        if (best.ShouldReplace(
 1873269            overlap,
 1873270            squaredAxisLength,
 1873271            commonDenominator))
 272        {
 548273            best = new WidePointSpanPenetration(
 548274                axis,
 548275                negate,
 548276                overlap,
 548277                squaredAxisLength,
 548278                commonDenominator);
 279        }
 1873280        return true;
 281    }
 282
 283    private static Vector3d GetTriangleSupportLocalPoint(
 284        in FixedTriangle triangle,
 285        in WideRationalBasis3d relativeBasis,
 286        in WideAxis3 boxLocalAxis)
 287    {
 143288        WideRigidProjection.GetLocalAxisProjections(
 143289            boxLocalAxis,
 143290            relativeBasis,
 143291            out Signed576 localAxisX,
 143292            out Signed576 localAxisY,
 143293            out Signed576 localAxisZ);
 143294        Vector3d bestPoint = triangle.A;
 143295        Signed576 bestProjection = WideRigidProjection.GetLocalOffsetProjection(
 143296            bestPoint,
 143297            localAxisX,
 143298            localAxisY,
 143299            localAxisZ);
 143300        Signed576 secondProjection = WideRigidProjection.GetLocalOffsetProjection(
 143301            triangle.B,
 143302            localAxisX,
 143303            localAxisY,
 143304            localAxisZ);
 143305        if (CompareSigned(secondProjection, bestProjection) < 0)
 306        {
 1307            bestPoint = triangle.B;
 1308            bestProjection = secondProjection;
 309        }
 143310        Signed576 thirdProjection = WideRigidProjection.GetLocalOffsetProjection(
 143311            triangle.C,
 143312            localAxisX,
 143313            localAxisY,
 143314            localAxisZ);
 143315        if (CompareSigned(thirdProjection, bestProjection) < 0)
 1316            bestPoint = triangle.C;
 143317        return bestPoint;
 318    }
 319
 320    internal static void GetTriangleFaceContacts(
 321        Vector3d boxCenter,
 322        FixedQuaternion boxOrientation,
 323        Vector3d boxHalfExtents,
 324        Vector3d triangleOrigin,
 325        FixedQuaternion triangleRotation,
 326        FixedTriangle triangle,
 327        FixedContactAnchors primary,
 328        Span<FixedContactLocalPoints> contacts,
 329        out int count)
 330    {
 8331        count = 0;
 8332        WideRationalBasis3d boxBasis = new(boxOrientation);
 8333        WideRationalBasis3d triangleBasis = new(triangleRotation);
 8334        WideGeometry.GetDifferenceCrossProduct3D(
 8335            triangle.B.X,
 8336            triangle.A.X,
 8337            triangle.B.Y,
 8338            triangle.A.Y,
 8339            triangle.B.Z,
 8340            triangle.A.Z,
 8341            triangle.C.X,
 8342            triangle.A.X,
 8343            triangle.C.Y,
 8344            triangle.A.Y,
 8345            triangle.C.Z,
 8346            triangle.A.Z,
 8347            out Signed192 normalX,
 8348            out Signed192 normalY,
 8349            out Signed192 normalZ);
 8350        WideAxis3 triangleNormal = WideRigidProjection.TransformLocalAxis(
 8351            triangleBasis,
 8352            normalX,
 8353            normalY,
 8354            normalZ);
 8355        int faceAxis = GetParallelTriangleFaceAxis(
 8356            boxBasis,
 8357            triangleNormal,
 8358            primary.Normal);
 8359        if (faceAxis < 0)
 3360            return;
 361
 5362        WideAxis3 selectedAxis = boxBasis.GetAxis(faceAxis);
 5363        Fixed64 faceSign = GetDirectionProjection(
 5364                selectedAxis,
 5365                primary.Normal).Sign < 0
 5366            ? -Fixed64.One
 5367            : Fixed64.One;
 50368        for (int corner = 0; corner < 4; corner++)
 369        {
 20370            Fixed64 firstSign = (corner & 1) == 0
 20371                ? -Fixed64.One
 20372                : Fixed64.One;
 20373            Fixed64 secondSign = (corner & 2) == 0
 20374                ? -Fixed64.One
 20375                : Fixed64.One;
 20376            Vector3d boxLocalPoint = faceAxis switch
 20377            {
 4378                0 => new Vector3d(
 4379                    faceSign * boxHalfExtents.X,
 4380                    firstSign * boxHalfExtents.Y,
 4381                    secondSign * boxHalfExtents.Z),
 4382                1 => new Vector3d(
 4383                    firstSign * boxHalfExtents.X,
 4384                    faceSign * boxHalfExtents.Y,
 4385                    secondSign * boxHalfExtents.Z),
 12386                _ => new Vector3d(
 12387                    firstSign * boxHalfExtents.X,
 12388                    secondSign * boxHalfExtents.Y,
 12389                    faceSign * boxHalfExtents.Z),
 20390            };
 20391            var boxPoint = new FixedPointAnchor(
 20392                boxCenter,
 20393                boxOrientation,
 20394                boxLocalPoint);
 20395            if (!boxPoint.TryGetLocalPointIn(
 20396                    triangleOrigin,
 20397                    triangleRotation,
 20398                    out Vector3d pointInTriangleFrame)
 20399                || !triangle.ContainsProjection(pointInTriangleFrame))
 400            {
 401                continue;
 402            }
 403
 12404            contacts[count++] = new FixedContactLocalPoints(
 12405                boxLocalPoint,
 12406                triangle.ClosestPoint(pointInTriangleFrame));
 407        }
 5408    }
 409
 410    private static int GetParallelTriangleFaceAxis(
 411        WideRationalBasis3d boxBasis,
 412        WideAxis3 triangleNormal,
 413        Vector3d primaryNormal)
 414    {
 8415        int bestIndex = 0;
 8416        WideAxis3 bestAxis = boxBasis.GetAxis(0);
 8417        Signed576 bestAlignment = WideAxis3.Dot(
 8418            bestAxis,
 8419            triangleNormal);
 48420        for (int index = 1; index < 3; index++)
 421        {
 16422            WideAxis3 candidateAxis = boxBasis.GetAxis(index);
 16423            Signed576 candidateAlignment = WideAxis3.Dot(
 16424                candidateAxis,
 16425                triangleNormal);
 16426            if (CompareSigned(
 16427                    GetMagnitude(candidateAlignment),
 16428                    GetMagnitude(bestAlignment)) <= 0)
 429            {
 430                continue;
 431            }
 432
 5433            bestIndex = index;
 5434            bestAxis = candidateAxis;
 5435            bestAlignment = candidateAlignment;
 436        }
 437
 8438        Signed576 boxSquared = bestAxis.SquaredLength;
 8439        if (!IsParallel(
 8440                bestAlignment,
 8441                boxSquared,
 8442                triangleNormal.SquaredLength))
 443        {
 2444            return -1;
 445        }
 446
 6447        WideAxis3 primaryAxis = new(
 6448            Signed320.ExtendValue(Signed192.Raw(primaryNormal.X)),
 6449            Signed320.ExtendValue(Signed192.Raw(primaryNormal.Y)),
 6450            Signed320.ExtendValue(Signed192.Raw(primaryNormal.Z)));
 6451        return IsParallel(
 6452                WideAxis3.Dot(bestAxis, primaryAxis),
 6453                boxSquared,
 6454                primaryAxis.SquaredLength)
 6455            ? bestIndex
 6456            : -1;
 457    }
 458
 459    private static Signed576 GetDirectionProjection(
 460        in WideAxis3 axis,
 461        Vector3d direction) =>
 5462        WideAxis3.Dot(
 5463            axis,
 5464            new WideAxis3(
 5465                Signed320.ExtendValue(Signed192.Raw(direction.X)),
 5466                Signed320.ExtendValue(Signed192.Raw(direction.Y)),
 5467                Signed320.ExtendValue(Signed192.Raw(direction.Z))));
 468
 469    private static bool IsParallel(
 470        Signed576 alignment,
 471        Signed576 firstSquaredLength,
 472        Signed576 secondSquaredLength)
 473    {
 14474        Signed832 alignmentSquared =
 14475            WideArithmetic.MultiplySigned576ToSigned832(
 14476                alignment,
 14477                alignment);
 14478        Signed832 lengthProduct =
 14479            WideArithmetic.MultiplySigned576ToSigned832(
 14480                firstSquaredLength,
 14481                secondSquaredLength);
 14482        Signed320 thresholdSquared = WideArithmetic.MultiplySigned192(
 14483            Signed192.Raw(ParallelFaceAlignmentThreshold),
 14484            Signed192.Raw(ParallelFaceAlignmentThreshold));
 14485        Signed320 scaleSquared = WideArithmetic.MultiplySigned192(
 14486            Signed192.One,
 14487            Signed192.One);
 14488        return WideArithmetic.CompareNonNegativeProducts(
 14489                alignmentSquared,
 14490                Signed832.ExtendValue(
 14491                    Signed576.ExtendValue(scaleSquared)),
 14492                lengthProduct,
 14493                Signed832.ExtendValue(
 14494                    Signed576.ExtendValue(thresholdSquared))) >= 0;
 495    }
 496
 497}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.TriangleCapsuleSlab.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.TriangleCapsuleSlab.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/// Contains logic for detecting and resolving contact between a triangle and a capsule-shaped slab,
 14/// using wide (high-precision) arithmetic for robust deterministic collision resolution.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    internal static bool TryGetTriangleCapsuleSlabContact(
 19        Vector3d triangleOrigin,
 20        FixedQuaternion triangleRotation,
 21        FixedTriangle triangle,
 22        Vector3d slabCenter,
 23        Fixed64 capsuleFrameRotation,
 24        Vector2d localCapsuleAxisDirection,
 25        Fixed64 capsuleAxisLength,
 26        Fixed64 capsuleRadius,
 27        Fixed64 slabHalfThickness,
 28        out FixedContactAnchors contact)
 29    {
 8230        if (triangle.IsDegenerate)
 31        {
 132            contact = default;
 133            return false;
 34        }
 35
 8136        _ = Vector2d.TryRotate(
 8137            localCapsuleAxisDirection,
 8138            capsuleFrameRotation,
 8139            out Vector2d capsuleAxisDirection);
 8140        WideRationalBasis3d triangleBasis = new(triangleRotation);
 8141        Signed320 commonDenominatorWide =
 8142            WideArithmetic.MultiplySigned192(
 8143                triangleBasis.Denominator,
 8144                Signed192.Raw(Fixed64.Two));
 8145        Signed192 commonDenominator = new(
 8146            commonDenominatorWide.Word2,
 8147            commonDenominatorWide.Word1,
 8148            commonDenominatorWide.Word0);
 8149        Span<Vector3d> trianglePoints = stackalloc Vector3d[3]
 8150        {
 8151            triangle.A,
 8152            triangle.B,
 8153            triangle.C,
 8154        };
 8155        Span<WideAxis3> triangleEdges = stackalloc WideAxis3[3]
 8156        {
 8157            GetHullEdge(triangleBasis, triangle.A, triangle.B),
 8158            GetHullEdge(triangleBasis, triangle.B, triangle.C),
 8159            GetHullEdge(triangleBasis, triangle.C, triangle.A),
 8160        };
 8161        WideGeometry.GetDifferenceCrossProduct3D(
 8162            triangle.B.X,
 8163            triangle.A.X,
 8164            triangle.B.Y,
 8165            triangle.A.Y,
 8166            triangle.B.Z,
 8167            triangle.A.Z,
 8168            triangle.C.X,
 8169            triangle.A.X,
 8170            triangle.C.Y,
 8171            triangle.A.Y,
 8172            triangle.C.Z,
 8173            triangle.A.Z,
 8174            out Signed192 localNormalX,
 8175            out Signed192 localNormalY,
 8176            out Signed192 localNormalZ);
 8177        WideAxis3 triangleNormal = WideRigidProjection.TransformLocalAxis(
 8178            triangleBasis,
 8179            localNormalX,
 8180            localNormalY,
 8181            localNormalZ);
 8182        WideAxis3 up = new(default, Signed320.One, default);
 8183        WideAxis3 capsuleAxis = new(
 8184            Signed320.ExtendValue(
 8185                Signed192.Raw(capsuleAxisDirection.X)),
 8186            default,
 8187            Signed320.ExtendValue(
 8188                Signed192.Raw(capsuleAxisDirection.Y)));
 8189        WideAxis3 capsuleNormal = new(
 8190            Signed320.ExtendValue(
 8191                Signed192.Raw(capsuleAxisDirection.Y)),
 8192            default,
 8193            Signed320.ExtendValue(
 8194                WideArithmetic.SubtractSigned192(
 8195                    default,
 8196                    Signed192.Raw(capsuleAxisDirection.X))));
 8197        var best = default(RadialPenetration);
 8198        if (!TryKeepTriangleCapsuleSlabAxis(
 8199                up,
 81100                triangleOrigin,
 81101                triangleBasis,
 81102                trianglePoints,
 81103                commonDenominator,
 81104                slabCenter,
 81105                capsuleAxisDirection,
 81106                capsuleAxisLength,
 81107                capsuleRadius,
 81108                slabHalfThickness,
 81109                ref best)
 81110            || !TryKeepTriangleCapsuleSlabAxis(
 81111                triangleNormal,
 81112                triangleOrigin,
 81113                triangleBasis,
 81114                trianglePoints,
 81115                commonDenominator,
 81116                slabCenter,
 81117                capsuleAxisDirection,
 81118                capsuleAxisLength,
 81119                capsuleRadius,
 81120                slabHalfThickness,
 81121                ref best)
 81122            || !TryKeepTriangleCapsuleSlabAxis(
 81123                capsuleAxis,
 81124                triangleOrigin,
 81125                triangleBasis,
 81126                trianglePoints,
 81127                commonDenominator,
 81128                slabCenter,
 81129                capsuleAxisDirection,
 81130                capsuleAxisLength,
 81131                capsuleRadius,
 81132                slabHalfThickness,
 81133                ref best)
 81134            || !TryKeepTriangleCapsuleSlabAxis(
 81135                capsuleNormal,
 81136                triangleOrigin,
 81137                triangleBasis,
 81138                trianglePoints,
 81139                commonDenominator,
 81140                slabCenter,
 81141                capsuleAxisDirection,
 81142                capsuleAxisLength,
 81143                capsuleRadius,
 81144                slabHalfThickness,
 81145                ref best))
 146        {
 4147            contact = default;
 4148            return false;
 149        }
 150
 77151        for (int edgeIndex = 0;
 304152            edgeIndex < triangleEdges.Length;
 227153            edgeIndex++)
 154        {
 229155            WideAxis3 edge = triangleEdges[edgeIndex];
 229156            if (!TryKeepTriangleCapsuleSlabAxis(
 229157                    CrossWithUp(edge),
 229158                    triangleOrigin,
 229159                    triangleBasis,
 229160                    trianglePoints,
 229161                    commonDenominator,
 229162                    slabCenter,
 229163                    capsuleAxisDirection,
 229164                    capsuleAxisLength,
 229165                    capsuleRadius,
 229166                    slabHalfThickness,
 229167                    ref best)
 229168                || !TryKeepTriangleCapsuleSlabAxis(
 229169                    WideAxis3.Cross(edge, capsuleAxis),
 229170                    triangleOrigin,
 229171                    triangleBasis,
 229172                    trianglePoints,
 229173                    commonDenominator,
 229174                    slabCenter,
 229175                    capsuleAxisDirection,
 229176                    capsuleAxisLength,
 229177                    capsuleRadius,
 229178                    slabHalfThickness,
 229179                    ref best))
 180            {
 2181                contact = default;
 2182                return false;
 183            }
 184        }
 185
 75186        int endpointStart = capsuleAxisLength == Fixed64.Zero ? 1 : -1;
 75187        for (int vertexIndex = 0;
 298188            vertexIndex < trianglePoints.Length;
 223189            vertexIndex++)
 190        {
 224191            for (int endpointSign = endpointStart;
 550192                endpointSign <= 1;
 326193                endpointSign += 2)
 194            {
 327195                WideAxis3 endpointAxis =
 327196                    GetTriangleVertexToCapsuleEndpointAxis(
 327197                        triangleOrigin,
 327198                        slabCenter,
 327199                        triangleBasis,
 327200                        trianglePoints[vertexIndex],
 327201                        capsuleAxisDirection,
 327202                        capsuleAxisLength,
 327203                        endpointSign);
 327204                if (!TryKeepTriangleCapsuleSlabAxis(
 327205                        endpointAxis,
 327206                        triangleOrigin,
 327207                        triangleBasis,
 327208                        trianglePoints,
 327209                        commonDenominator,
 327210                        slabCenter,
 327211                        capsuleAxisDirection,
 327212                        capsuleAxisLength,
 327213                        capsuleRadius,
 327214                        slabHalfThickness,
 327215                        ref best))
 216                {
 1217                    contact = default;
 1218                    return false;
 219                }
 220            }
 221        }
 222
 74223        WideAxis3 orientedAxis =
 74224            best.Negate ? -best.Axis : best.Axis;
 74225        Vector3d normal = WideNormalization.GetNormalized(
 74226            Signed576.ExtendValue(orientedAxis.X),
 74227            Signed576.ExtendValue(orientedAxis.Y),
 74228            Signed576.ExtendValue(orientedAxis.Z));
 74229        FixedPointAnchor slabAnchor = GetCapsuleSlabSupportAnchor(
 74230            slabCenter,
 74231            capsuleFrameRotation,
 74232            localCapsuleAxisDirection,
 74233            orientedAxis,
 74234            capsuleAxisLength,
 74235            capsuleRadius,
 74236            slabHalfThickness);
 74237        FixedPointAnchor triangleAnchor = triangle.GetClosestPointAnchor(
 74238            triangleOrigin,
 74239            triangleRotation,
 74240            slabAnchor);
 74241        contact = new FixedContactAnchors(
 74242            triangleAnchor,
 74243            slabAnchor,
 74244            normal,
 74245            best.Depth,
 74246            best.DepthIsClamped);
 74247        return true;
 248    }
 249
 250    private static bool TryKeepTriangleCapsuleSlabAxis(
 251        WideAxis3 axis,
 252        Vector3d triangleOrigin,
 253        WideRationalBasis3d triangleBasis,
 254        ReadOnlySpan<Vector3d> trianglePoints,
 255        Signed192 commonDenominator,
 256        Vector3d slabCenter,
 257        Vector2d capsuleAxisDirection,
 258        Fixed64 capsuleAxisLength,
 259        Fixed64 capsuleRadius,
 260        Fixed64 slabHalfThickness,
 261        ref RadialPenetration best)
 262    {
 1102263        if (axis.IsZero)
 75264            return true;
 265
 1027266        GetHullProjectionInterval(
 1027267            trianglePoints,
 1027268            triangleBasis,
 1027269            axis,
 1027270            Signed192.One,
 1027271            out Signed576 triangleMinimum,
 1027272            out Signed576 triangleMaximum);
 1027273        Signed576 centerProjection = WideArithmetic.MultiplySigned576(
 1027274            WideArithmetic.MultiplySigned576(
 1027275                WideRigidProjection.GetWorldOriginDifferenceProjection(
 1027276                    slabCenter,
 1027277                    triangleOrigin,
 1027278                    axis),
 1027279                Signed192.One),
 1027280            triangleBasis.Denominator);
 1027281        Signed576 verticalRadius = WideArithmetic.MultiplySigned576(
 1027282            WideArithmetic.MultiplySigned576(
 1027283                WideArithmetic.MultiplySigned576(
 1027284                    Signed576.ExtendValue(
 1027285                        GetMagnitude(axis.Y)),
 1027286                    Signed192.Raw(slabHalfThickness)),
 1027287                Signed192.One),
 1027288            triangleBasis.Denominator);
 1027289        Signed576 axialRadius = WideArithmetic.MultiplySigned576(
 1027290            WideArithmetic.MultiplySigned576(
 1027291                GetMagnitude(
 1027292                    GetPlanarAxisProjection(
 1027293                        axis,
 1027294                        capsuleAxisDirection)),
 1027295                Signed192.Raw(capsuleAxisLength)),
 1027296            triangleBasis.Denominator);
 1027297        Signed576 doubledCenter = WideArithmetic.AddSigned576(
 1027298            centerProjection,
 1027299            centerProjection);
 1027300        Signed576 doubledVertical = WideArithmetic.AddSigned576(
 1027301            verticalRadius,
 1027302            verticalRadius);
 1027303        Signed576 positiveBase = WideArithmetic.AddSigned576(
 1027304            WideArithmetic.SubtractSigned576(
 1027305                WideArithmetic.AddSigned576(
 1027306                    triangleMaximum,
 1027307                    triangleMaximum),
 1027308                doubledCenter),
 1027309            WideArithmetic.AddSigned576(
 1027310                doubledVertical,
 1027311                axialRadius));
 1027312        Signed576 negativeBase = WideArithmetic.AddSigned576(
 1027313            WideArithmetic.SubtractSigned576(
 1027314                doubledCenter,
 1027315                WideArithmetic.AddSigned576(
 1027316                    triangleMinimum,
 1027317                    triangleMinimum)),
 1027318            WideArithmetic.AddSigned576(
 1027319                doubledVertical,
 1027320                axialRadius));
 1027321        Signed576 planarSquared = WideArithmetic.AddSigned576(
 1027322            WideArithmetic.MultiplySigned320(axis.X, axis.X),
 1027323            WideArithmetic.MultiplySigned320(axis.Z, axis.Z));
 1027324        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 1027325            Signed192.Raw(capsuleRadius),
 1027326            Signed192.Raw(capsuleRadius));
 1027327        Signed832 radialSquared =
 1027328            WideArithmetic.MultiplySigned576ToSigned832(
 1027329                Signed576.ExtendValue(radiusSquared),
 1027330                planarSquared);
 1027331        if (!DoesRadialOverlap(
 1027332                positiveBase,
 1027333                radialSquared,
 1027334                commonDenominator)
 1027335            || !DoesRadialOverlap(
 1027336                negativeBase,
 1027337                radialSquared,
 1027338                commonDenominator))
 339        {
 7340            return false;
 341        }
 342
 1020343        Signed576 squaredAxisLength = axis.SquaredLength;
 1020344        GetRadialDepth(
 1020345            positiveBase,
 1020346            radialSquared,
 1020347            squaredAxisLength,
 1020348            commonDenominator,
 1020349            out Fixed64 positiveDepth,
 1020350            out bool positiveClamped);
 1020351        GetRadialDepth(
 1020352            negativeBase,
 1020353            radialSquared,
 1020354            squaredAxisLength,
 1020355            commonDenominator,
 1020356            out Fixed64 negativeDepth,
 1020357            out bool negativeClamped);
 1020358        bool negate =
 1020359            negativeDepth < positiveDepth
 1020360            || negativeDepth == positiveDepth
 1020361            && WideArithmetic.SubtractSigned576(
 1020362                negativeBase,
 1020363                positiveBase).Sign < 0;
 1020364        Fixed64 depth = negate
 1020365            ? negativeDepth
 1020366            : positiveDepth;
 1020367        bool depthIsClamped = negate
 1020368            ? negativeClamped
 1020369            : positiveClamped;
 1020370        Signed576 rational = negate
 1020371            ? negativeBase
 1020372            : positiveBase;
 1020373        if (!best.HasValue
 1020374            || depth < best.Depth
 1020375            || (depth == best.Depth
 1020376                && WideArithmetic.CompareRadialProjectionDepths(
 1020377                    rational,
 1020378                    radialSquared,
 1020379                    ToSigned576(Signed192.Signed(1L)),
 1020380                    squaredAxisLength,
 1020381                    best.Rational,
 1020382                    best.RadialNumerator,
 1020383                    best.RadialDenominator,
 1020384                    best.AxisSquared,
 1020385                    commonDenominator) < 0))
 386        {
 159387            best = new RadialPenetration(
 159388                axis,
 159389                negate,
 159390                depth,
 159391                depthIsClamped,
 159392                rational,
 159393                radialSquared,
 159394                ToSigned576(Signed192.Signed(1L)),
 159395                squaredAxisLength);
 396        }
 1020397        return true;
 398    }
 399
 400    private static bool DoesRadialOverlap(
 401        Signed576 rational,
 402        Signed832 radialSquared,
 403        Signed192 commonDenominator) =>
 2050404        rational.Sign >= 0
 2050405        || IsRadicalAtLeastRatio(
 2050406            radialSquared,
 2050407            WideArithmetic.SubtractSigned576(
 2050408                default,
 2050409                rational),
 2050410            commonDenominator);
 411
 412    private static WideAxis3 GetTriangleVertexToCapsuleEndpointAxis(
 413        Vector3d triangleOrigin,
 414        Vector3d capsuleCenter,
 415        WideRationalBasis3d basis,
 416        Vector3d localVertex,
 417        Vector2d capsuleAxisDirection,
 418        Fixed64 capsuleAxisLength,
 419        int endpointSign)
 420    {
 327421        Signed320 vertexX = GetLocalOffsetNumerator(
 327422            basis.Xx,
 327423            basis.Yx,
 327424            basis.Zx,
 327425            localVertex);
 327426        Signed320 vertexZ = GetLocalOffsetNumerator(
 327427            basis.Xz,
 327428            basis.Yz,
 327429            basis.Zz,
 327430            localVertex);
 327431        Signed192 twiceScale = Signed192.Raw(Fixed64.Two);
 327432        Signed576 centerX = WideArithmetic.MultiplySigned576(
 327433            Signed576.ExtendValue(
 327434                WideArithmetic.MultiplySigned192(
 327435                    WideArithmetic.SubtractSigned192(
 327436                        Signed192.Raw(capsuleCenter.X),
 327437                        Signed192.Raw(triangleOrigin.X)),
 327438                    basis.Denominator)),
 327439            twiceScale);
 327440        Signed576 centerZ = WideArithmetic.MultiplySigned576(
 327441            Signed576.ExtendValue(
 327442                WideArithmetic.MultiplySigned192(
 327443                    WideArithmetic.SubtractSigned192(
 327444                        Signed192.Raw(capsuleCenter.Z),
 327445                        Signed192.Raw(triangleOrigin.Z)),
 327446                    basis.Denominator)),
 327447            twiceScale);
 327448        Signed576 endpointX = WideArithmetic.MultiplySigned576(
 327449            WideArithmetic.MultiplySigned576(
 327450                Signed576.ExtendValue(
 327451                    Signed320.ExtendValue(
 327452                        Signed192.Raw(capsuleAxisDirection.X))),
 327453                Signed192.Signed(
 327454                    endpointSign
 327455                    * capsuleAxisLength.m_rawValue)),
 327456            basis.Denominator);
 327457        Signed576 endpointZ = WideArithmetic.MultiplySigned576(
 327458            WideArithmetic.MultiplySigned576(
 327459                Signed576.ExtendValue(
 327460                    Signed320.ExtendValue(
 327461                        Signed192.Raw(capsuleAxisDirection.Y))),
 327462                Signed192.Signed(
 327463                    endpointSign
 327464                    * capsuleAxisLength.m_rawValue)),
 327465            basis.Denominator);
 327466        Signed576 vertexXWide = WideArithmetic.MultiplySigned576(
 327467            Signed576.ExtendValue(vertexX),
 327468            twiceScale);
 327469        Signed576 vertexZWide = WideArithmetic.MultiplySigned576(
 327470            Signed576.ExtendValue(vertexZ),
 327471            twiceScale);
 472        // A full-domain center difference multiplied by a normalized quaternion
 473        // basis and the Q32.32 factor for two uses at most 165 signed bits.
 327474        return new WideAxis3(
 327475            Signed320.NarrowValue(
 327476                WideArithmetic.SubtractSigned576(
 327477                    WideArithmetic.AddSigned576(
 327478                        centerX,
 327479                        endpointX),
 327480                    vertexXWide)),
 327481            default,
 327482            Signed320.NarrowValue(
 327483                WideArithmetic.SubtractSigned576(
 327484                    WideArithmetic.AddSigned576(
 327485                        centerZ,
 327486                        endpointZ),
 327487                    vertexZWide)));
 488    }
 489}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.TriangleCircleSlabSweep.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.TriangleCircleSlabSweep.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/// Computes swept-circle vs. triangle intersection within a bounded slab region,
 14/// using high-precision wide arithmetic for exact edge and interior overlap tests.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    #region Nested Types
 19
 20    private readonly struct TriangleSweepVertex
 21    {
 22        internal readonly Signed320 X;
 23        internal readonly Signed320 Y;
 24        internal readonly Signed320 Z;
 25        internal readonly Signed320 ReferenceYOffset;
 26        internal readonly Vector3d LocalPoint;
 27
 28        internal TriangleSweepVertex(
 29            Signed320 x,
 30            Signed320 y,
 31            Signed320 z,
 32            Signed320 referenceYOffset,
 33            Vector3d localPoint)
 34        {
 19835            X = x;
 19836            Y = y;
 19837            Z = z;
 19838            ReferenceYOffset = referenceYOffset;
 19839            LocalPoint = localPoint;
 19840        }
 41
 42        internal TriangleSweepPoint ToSweepPoint(
 43            Signed192 basisDenominator) =>
 63244            new(
 63245                new SweepRationalPoint(
 63246                    Signed576.ExtendValue(X),
 63247                    Signed576.ExtendValue(Z),
 63248                    Signed576.ExtendValue(
 63249                        Signed320.ExtendValue(
 63250                            basisDenominator))),
 63251                ReferenceYOffset,
 63252                LocalPoint);
 53
 54    }
 55
 56    private readonly struct TriangleSweepPoint
 57    {
 58        internal readonly SweepRationalPoint RationalPoint;
 59        internal readonly Signed320 ReferenceYOffset;
 60        internal readonly Vector3d LocalPoint;
 61
 62        internal TriangleSweepPoint(
 63            SweepRationalPoint rationalPoint,
 64            Signed320 referenceYOffset,
 65            Vector3d localPoint)
 66        {
 64667            RationalPoint = rationalPoint;
 64668            ReferenceYOffset = referenceYOffset;
 64669            LocalPoint = localPoint;
 64670        }
 71    }
 72
 73    #endregion
 74
 75    internal static bool TryGetFiniteSlabProjectedCircleSweep(
 76        FixedTriangle triangle,
 77        Vector3d triangleOrigin,
 78        FixedQuaternion triangleRotation,
 79        Vector2d circleStart,
 80        Vector2d direction,
 81        Fixed64 maximumDistance,
 82        Fixed64 circleRadius,
 83        Fixed64 slabCenterY,
 84        Fixed64 slabHalfThickness,
 85        out Fixed64 distance,
 86        out FixedPointAnchor triangleContact)
 87    {
 6688        WideRationalBasis3d basis = new(triangleRotation);
 6689        Signed320 referenceYNumerator =
 6690            WideArithmetic.MultiplySigned192(
 6691                Signed192.Raw(slabCenterY),
 6692                basis.Denominator);
 6693        TriangleSweepVertex first = GetTriangleSweepVertex(
 6694            triangleOrigin,
 6695            basis,
 6696            triangle.A,
 6697            referenceYNumerator);
 6698        TriangleSweepVertex second = GetTriangleSweepVertex(
 6699            triangleOrigin,
 66100            basis,
 66101            triangle.B,
 66102            referenceYNumerator);
 66103        TriangleSweepVertex third = GetTriangleSweepVertex(
 66104            triangleOrigin,
 66105            basis,
 66106            triangle.C,
 66107            referenceYNumerator);
 66108        Signed192 lowerY = WideArithmetic.SubtractSigned192(
 66109            Signed192.Raw(slabCenterY),
 66110            Signed192.Raw(slabHalfThickness));
 66111        Signed192 upperY = WideArithmetic.AddSigned192(
 66112            Signed192.Raw(slabCenterY),
 66113            Signed192.Raw(slabHalfThickness));
 66114        Signed320 lowerNumerator =
 66115            WideArithmetic.MultiplySigned192(lowerY, basis.Denominator);
 66116        Signed320 upperNumerator =
 66117            WideArithmetic.MultiplySigned192(upperY, basis.Denominator);
 66118        if (TryGetTriangleProjectionInteriorPoint(
 66119                first,
 66120                second,
 66121                third,
 66122                circleStart,
 66123                lowerNumerator,
 66124                upperNumerator,
 66125                basis.Denominator,
 66126                out Vector3d interiorLocalPoint))
 127        {
 1128            distance = Fixed64.Zero;
 1129            triangleContact = new FixedPointAnchor(
 1130                triangleOrigin,
 1131                triangleRotation,
 1132                interiorLocalPoint);
 1133            return true;
 134        }
 135
 65136        bool found = false;
 65137        Fixed64 bestDistance = default;
 65138        Vector3d bestLocalPoint = default;
 65139        Signed576 bestReferenceYOffset = default;
 65140        bool firstSecondCollapsed =
 65141            AreSameProjectedPoint(first, second);
 65142        bool secondThirdCollapsed =
 65143            AreSameProjectedPoint(second, third);
 65144        bool thirdFirstCollapsed =
 65145            AreSameProjectedPoint(third, first);
 65146        bool allCollapsed =
 65147            firstSecondCollapsed
 65148            && secondThirdCollapsed
 65149            && thirdFirstCollapsed;
 65150        if (allCollapsed || !firstSecondCollapsed)
 151        {
 61152            KeepTriangleEdgeSweep(
 61153                first,
 61154                second,
 61155                lowerNumerator,
 61156                upperNumerator,
 61157                basis.Denominator,
 61158                referenceYNumerator,
 61159                circleStart,
 61160                direction,
 61161                maximumDistance,
 61162                circleRadius,
 61163                ref found,
 61164                ref bestDistance,
 61165                ref bestLocalPoint,
 61166                ref bestReferenceYOffset);
 167        }
 65168        if (allCollapsed || !secondThirdCollapsed)
 169        {
 60170            KeepTriangleEdgeSweep(
 60171                second,
 60172                third,
 60173                lowerNumerator,
 60174                upperNumerator,
 60175                basis.Denominator,
 60176                referenceYNumerator,
 60177                circleStart,
 60178                direction,
 60179                maximumDistance,
 60180                circleRadius,
 60181                ref found,
 60182                ref bestDistance,
 60183                ref bestLocalPoint,
 60184                ref bestReferenceYOffset);
 185        }
 65186        if (allCollapsed || !thirdFirstCollapsed)
 187        {
 61188            KeepTriangleEdgeSweep(
 61189                third,
 61190                first,
 61191                lowerNumerator,
 61192                upperNumerator,
 61193                basis.Denominator,
 61194                referenceYNumerator,
 61195                circleStart,
 61196                direction,
 61197                maximumDistance,
 61198                circleRadius,
 61199                ref found,
 61200                ref bestDistance,
 61201                ref bestLocalPoint,
 61202                ref bestReferenceYOffset);
 203        }
 65204        KeepTrianglePlaneEdgeSweep(
 65205            first,
 65206            second,
 65207            third,
 65208            lowerNumerator,
 65209            basis.Denominator,
 65210            referenceYNumerator,
 65211            circleStart,
 65212            direction,
 65213            maximumDistance,
 65214            circleRadius,
 65215            ref found,
 65216            ref bestDistance,
 65217            ref bestLocalPoint,
 65218            ref bestReferenceYOffset);
 65219        if (CompareSigned(lowerNumerator, upperNumerator) != 0)
 220        {
 15221            KeepTrianglePlaneEdgeSweep(
 15222                first,
 15223                second,
 15224                third,
 15225                upperNumerator,
 15226                basis.Denominator,
 15227                referenceYNumerator,
 15228                circleStart,
 15229                direction,
 15230                maximumDistance,
 15231                circleRadius,
 15232                ref found,
 15233                ref bestDistance,
 15234                ref bestLocalPoint,
 15235                ref bestReferenceYOffset);
 236        }
 237
 65238        if (!found)
 239        {
 6240            distance = default;
 6241            triangleContact = default;
 6242            return false;
 243        }
 244
 59245        distance = bestDistance;
 59246        triangleContact = new FixedPointAnchor(
 59247            triangleOrigin,
 59248            triangleRotation,
 59249            bestLocalPoint);
 59250        return true;
 251    }
 252
 253    private static bool TryGetTriangleProjectionInteriorPoint(
 254        TriangleSweepVertex first,
 255        TriangleSweepVertex second,
 256        TriangleSweepVertex third,
 257        Vector2d point,
 258        Signed320 lowerY,
 259        Signed320 upperY,
 260        Signed192 basisDenominator,
 261        out Vector3d localPoint)
 262    {
 66263        Signed320 firstEdgeX =
 66264            WideArithmetic.SubtractSigned320(second.X, first.X);
 66265        Signed320 firstEdgeZ =
 66266            WideArithmetic.SubtractSigned320(second.Z, first.Z);
 66267        Signed320 secondEdgeX =
 66268            WideArithmetic.SubtractSigned320(third.X, first.X);
 66269        Signed320 secondEdgeZ =
 66270            WideArithmetic.SubtractSigned320(third.Z, first.Z);
 66271        Signed576 determinant = WideArithmetic.SubtractSigned576(
 66272            WideArithmetic.MultiplySigned320(
 66273                firstEdgeX,
 66274                secondEdgeZ),
 66275            WideArithmetic.MultiplySigned320(
 66276                firstEdgeZ,
 66277                secondEdgeX));
 66278        if (determinant.IsZero)
 279        {
 14280            localPoint = default;
 14281            return false;
 282        }
 283
 52284        Signed320 pointX = WideArithmetic.SubtractSigned320(
 52285            WideArithmetic.MultiplySigned192(
 52286                Signed192.Raw(point.X),
 52287                basisDenominator),
 52288            first.X);
 52289        Signed320 pointZ = WideArithmetic.SubtractSigned320(
 52290            WideArithmetic.MultiplySigned192(
 52291                Signed192.Raw(point.Y),
 52292                basisDenominator),
 52293            first.Z);
 52294        Signed576 firstParameter = WideArithmetic.SubtractSigned576(
 52295            WideArithmetic.MultiplySigned320(
 52296                pointX,
 52297                secondEdgeZ),
 52298            WideArithmetic.MultiplySigned320(
 52299                pointZ,
 52300                secondEdgeX));
 52301        Signed576 secondParameter = WideArithmetic.SubtractSigned576(
 52302            WideArithmetic.MultiplySigned320(
 52303                firstEdgeX,
 52304                pointZ),
 52305            WideArithmetic.MultiplySigned320(
 52306                firstEdgeZ,
 52307                pointX));
 52308        if (determinant.Sign < 0)
 309        {
 44310            determinant =
 44311                WideArithmetic.SubtractSigned576(default, determinant);
 44312            firstParameter =
 44313                WideArithmetic.SubtractSigned576(default, firstParameter);
 44314            secondParameter =
 44315                WideArithmetic.SubtractSigned576(default, secondParameter);
 316        }
 317
 52318        if (firstParameter.Sign < 0
 52319            || secondParameter.Sign < 0
 52320            || WideArithmetic.SubtractSigned576(
 52321                WideArithmetic.AddSigned576(
 52322                    firstParameter,
 52323                    secondParameter),
 52324                determinant).Sign > 0)
 325        {
 49326            localPoint = default;
 49327            return false;
 328        }
 329
 3330        Signed320 firstEdgeY =
 3331            WideArithmetic.SubtractSigned320(second.Y, first.Y);
 3332        Signed320 secondEdgeY =
 3333            WideArithmetic.SubtractSigned320(third.Y, first.Y);
 3334        Signed832 yNumerator = WideArithmetic.AddSigned832(
 3335            WideArithmetic.AddSigned832(
 3336                WideArithmetic.MultiplySigned576ToSigned832(
 3337                    Signed576.ExtendValue(first.Y),
 3338                    determinant),
 3339                WideArithmetic.MultiplySigned576ToSigned832(
 3340                    Signed576.ExtendValue(firstEdgeY),
 3341                    firstParameter)),
 3342            WideArithmetic.MultiplySigned576ToSigned832(
 3343                Signed576.ExtendValue(secondEdgeY),
 3344                secondParameter));
 3345        Signed832 lowerNumerator =
 3346            WideArithmetic.MultiplySigned576ToSigned832(
 3347                Signed576.ExtendValue(lowerY),
 3348                determinant);
 3349        Signed832 upperNumerator =
 3350            WideArithmetic.MultiplySigned576ToSigned832(
 3351                Signed576.ExtendValue(upperY),
 3352                determinant);
 3353        if (WideArithmetic.SubtractSigned832(
 3354                yNumerator,
 3355                lowerNumerator).Sign < 0
 3356            || WideArithmetic.SubtractSigned832(
 3357                yNumerator,
 3358                upperNumerator).Sign > 0)
 359        {
 2360            localPoint = default;
 2361            return false;
 362        }
 363
 1364        Signed320 firstLocalX =
 1365            Signed320.ExtendValue(
 1366                WideArithmetic.SubtractSigned192(
 1367                Signed192.Raw(second.LocalPoint.X),
 1368                Signed192.Raw(first.LocalPoint.X)));
 1369        Signed320 firstLocalY =
 1370            Signed320.ExtendValue(
 1371                WideArithmetic.SubtractSigned192(
 1372                Signed192.Raw(second.LocalPoint.Y),
 1373                Signed192.Raw(first.LocalPoint.Y)));
 1374        Signed320 firstLocalZ =
 1375            Signed320.ExtendValue(
 1376                WideArithmetic.SubtractSigned192(
 1377                Signed192.Raw(second.LocalPoint.Z),
 1378                Signed192.Raw(first.LocalPoint.Z)));
 1379        Signed320 secondLocalX =
 1380            Signed320.ExtendValue(
 1381                WideArithmetic.SubtractSigned192(
 1382                Signed192.Raw(third.LocalPoint.X),
 1383                Signed192.Raw(first.LocalPoint.X)));
 1384        Signed320 secondLocalY =
 1385            Signed320.ExtendValue(
 1386                WideArithmetic.SubtractSigned192(
 1387                Signed192.Raw(third.LocalPoint.Y),
 1388                Signed192.Raw(first.LocalPoint.Y)));
 1389        Signed320 secondLocalZ =
 1390            Signed320.ExtendValue(
 1391                WideArithmetic.SubtractSigned192(
 1392                Signed192.Raw(third.LocalPoint.Z),
 1393                Signed192.Raw(first.LocalPoint.Z)));
 1394        Signed832 denominator =
 1395            Signed832.ExtendValue(determinant);
 396        // A barycentric point lies inside the convex hull of three
 397        // representable local vertices, so every final local component is
 398        // representable by construction.
 1399        _ = TryGetTriangleInteriorLocalCoordinate(
 1400                first.LocalPoint.X,
 1401                firstLocalX,
 1402                secondLocalX,
 1403                firstParameter,
 1404                secondParameter,
 1405                determinant,
 1406                denominator,
 1407                out Fixed64 localX);
 1408        _ = TryGetTriangleInteriorLocalCoordinate(
 1409                first.LocalPoint.Y,
 1410                firstLocalY,
 1411                secondLocalY,
 1412                firstParameter,
 1413                secondParameter,
 1414                determinant,
 1415                denominator,
 1416                out Fixed64 localY);
 1417        _ = TryGetTriangleInteriorLocalCoordinate(
 1418                first.LocalPoint.Z,
 1419                firstLocalZ,
 1420                secondLocalZ,
 1421                firstParameter,
 1422                secondParameter,
 1423                determinant,
 1424                denominator,
 1425                out Fixed64 localZ);
 1426        localPoint = new Vector3d(localX, localY, localZ);
 1427        return true;
 428    }
 429
 430    private static bool TryGetTriangleInteriorLocalCoordinate(
 431        Fixed64 origin,
 432        Signed320 firstEdge,
 433        Signed320 secondEdge,
 434        Signed576 firstParameter,
 435        Signed576 secondParameter,
 436        Signed576 determinant,
 437        Signed832 denominator,
 438        out Fixed64 coordinate)
 439    {
 3440        Signed832 numerator = WideArithmetic.AddSigned832(
 3441            WideArithmetic.AddSigned832(
 3442                WideArithmetic.MultiplySigned576ToSigned832(
 3443                    Signed576.ExtendValue(
 3444                        Signed320.ExtendValue(Signed192.Raw(origin))),
 3445                    determinant),
 3446                WideArithmetic.MultiplySigned576ToSigned832(
 3447                    Signed576.ExtendValue(firstEdge),
 3448                    firstParameter)),
 3449            WideArithmetic.MultiplySigned576ToSigned832(
 3450                Signed576.ExtendValue(secondEdge),
 3451                secondParameter));
 3452        return Fixed64.TryGetSignedRawRatio(
 3453            numerator,
 3454            denominator,
 3455            numeratorLeftShift: 0,
 3456            out coordinate);
 457    }
 458
 459    private static TriangleSweepVertex GetTriangleSweepVertex(
 460        Vector3d origin,
 461        WideRationalBasis3d basis,
 462        Vector3d localPoint,
 463        Signed320 referenceYNumerator)
 464    {
 198465        Signed320 x = WideArithmetic.AddSigned320(
 198466            WideArithmetic.MultiplySigned192(
 198467                Signed192.Raw(origin.X),
 198468                basis.Denominator),
 198469            GetLocalOffsetNumerator(
 198470                basis.Xx,
 198471                basis.Yx,
 198472                basis.Zx,
 198473                localPoint));
 198474        Signed320 y = WideArithmetic.AddSigned320(
 198475            WideArithmetic.MultiplySigned192(
 198476                Signed192.Raw(origin.Y),
 198477                basis.Denominator),
 198478            GetLocalOffsetNumerator(
 198479                basis.Xy,
 198480                basis.Yy,
 198481                basis.Zy,
 198482                localPoint));
 198483        Signed320 z = WideArithmetic.AddSigned320(
 198484            WideArithmetic.MultiplySigned192(
 198485                Signed192.Raw(origin.Z),
 198486                basis.Denominator),
 198487            GetLocalOffsetNumerator(
 198488                basis.Xz,
 198489                basis.Yz,
 198490                basis.Zz,
 198491                localPoint));
 198492        return new TriangleSweepVertex(
 198493            x,
 198494            y,
 198495            z,
 198496            WideArithmetic.SubtractSigned320(
 198497                y,
 198498                referenceYNumerator),
 198499            localPoint);
 500    }
 501
 502    private static bool AreSameProjectedPoint(
 503        TriangleSweepVertex first,
 504        TriangleSweepVertex second) =>
 195505        CompareSigned(first.X, second.X) == 0
 195506        && CompareSigned(first.Z, second.Z) == 0;
 507
 508    private static void KeepTriangleEdgeSweep(
 509        TriangleSweepVertex first,
 510        TriangleSweepVertex second,
 511        Signed320 lowerY,
 512        Signed320 upperY,
 513        Signed192 basisDenominator,
 514        Signed320 referenceYNumerator,
 515        Vector2d circleStart,
 516        Vector2d direction,
 517        Fixed64 maximumDistance,
 518        Fixed64 radius,
 519        ref bool found,
 520        ref Fixed64 bestDistance,
 521        ref Vector3d bestLocalPoint,
 522        ref Signed576 bestReferenceYOffset)
 523    {
 182524        Signed320 minimum = CompareSigned(first.Y, second.Y) <= 0
 182525            ? first.Y
 182526            : second.Y;
 182527        Signed320 maximum = CompareSigned(first.Y, second.Y) <= 0
 182528            ? second.Y
 182529            : first.Y;
 182530        if (CompareSigned(maximum, lowerY) < 0
 182531            || CompareSigned(minimum, upperY) > 0)
 532        {
 12533            return;
 534        }
 535
 170536        TriangleSweepPoint clippedFirst =
 170537            GetClippedTriangleEdgeEndpoint(
 170538                first,
 170539                second,
 170540                lowerY,
 170541                upperY,
 170542                basisDenominator,
 170543                referenceYNumerator);
 170544        TriangleSweepPoint clippedSecond =
 170545            GetClippedTriangleEdgeEndpoint(
 170546                second,
 170547                first,
 170548                lowerY,
 170549                upperY,
 170550                basisDenominator,
 170551                referenceYNumerator);
 170552        KeepTriangleSweepFeature(
 170553            clippedFirst,
 170554            clippedSecond,
 170555            circleStart,
 170556            direction,
 170557            maximumDistance,
 170558            radius,
 170559            ref found,
 170560            ref bestDistance,
 170561            ref bestLocalPoint,
 170562            ref bestReferenceYOffset);
 170563    }
 564
 565    private static TriangleSweepPoint GetClippedTriangleEdgeEndpoint(
 566        TriangleSweepVertex endpoint,
 567        TriangleSweepVertex other,
 568        Signed320 lowerY,
 569        Signed320 upperY,
 570        Signed192 basisDenominator,
 571        Signed320 referenceYNumerator)
 572    {
 340573        if (CompareSigned(endpoint.Y, lowerY) >= 0
 340574            && CompareSigned(endpoint.Y, upperY) <= 0)
 575        {
 330576            return endpoint.ToSweepPoint(basisDenominator);
 577        }
 578
 10579        Signed320 plane = CompareSigned(endpoint.Y, lowerY) < 0
 10580            ? lowerY
 10581            : upperY;
 10582        return GetTrianglePlaneIntersection(
 10583            endpoint,
 10584            other,
 10585            plane,
 10586            basisDenominator,
 10587            referenceYNumerator);
 588    }
 589
 590    private static void KeepTrianglePlaneEdgeSweep(
 591        TriangleSweepVertex first,
 592        TriangleSweepVertex second,
 593        TriangleSweepVertex third,
 594        Signed320 planeY,
 595        Signed192 basisDenominator,
 596        Signed320 referenceYNumerator,
 597        Vector2d circleStart,
 598        Vector2d direction,
 599        Fixed64 maximumDistance,
 600        Fixed64 radius,
 601        ref bool found,
 602        ref Fixed64 bestDistance,
 603        ref Vector3d bestLocalPoint,
 604        ref Signed576 bestReferenceYOffset)
 605    {
 80606        Span<TriangleSweepPoint> intersections =
 80607            stackalloc TriangleSweepPoint[3];
 80608        int count = 0;
 80609        TryAddTrianglePlaneIntersection(
 80610            first,
 80611            second,
 80612            planeY,
 80613            basisDenominator,
 80614            referenceYNumerator,
 80615            intersections,
 80616            ref count);
 80617        TryAddTrianglePlaneIntersection(
 80618            second,
 80619            third,
 80620            planeY,
 80621            basisDenominator,
 80622            referenceYNumerator,
 80623            intersections,
 80624            ref count);
 80625        TryAddTrianglePlaneIntersection(
 80626            third,
 80627            first,
 80628            planeY,
 80629            basisDenominator,
 80630            referenceYNumerator,
 80631            intersections,
 80632            ref count);
 80633        if (count < 2)
 33634            return;
 635
 47636        KeepTriangleSweepFeature(
 47637            intersections[0],
 47638            intersections[1],
 47639            circleStart,
 47640            direction,
 47641            maximumDistance,
 47642            radius,
 47643            ref found,
 47644            ref bestDistance,
 47645            ref bestLocalPoint,
 47646            ref bestReferenceYOffset);
 47647    }
 648
 649    private static void TryAddTrianglePlaneIntersection(
 650        TriangleSweepVertex first,
 651        TriangleSweepVertex second,
 652        Signed320 planeY,
 653        Signed192 basisDenominator,
 654        Signed320 referenceYNumerator,
 655        Span<TriangleSweepPoint> intersections,
 656        ref int count)
 657    {
 240658        int firstSide = CompareSigned(first.Y, planeY);
 240659        int secondSide = CompareSigned(second.Y, planeY);
 240660        if (firstSide == 0)
 661        {
 151662            AddUniqueTriangleSweepPoint(
 151663                first.ToSweepPoint(basisDenominator),
 151664                intersections,
 151665                ref count);
 666        }
 240667        if (secondSide == 0)
 668        {
 151669            AddUniqueTriangleSweepPoint(
 151670                second.ToSweepPoint(basisDenominator),
 151671                intersections,
 151672                ref count);
 673        }
 240674        if (firstSide == 0
 240675            || secondSide == 0
 240676            || (firstSide < 0) == (secondSide < 0))
 677        {
 236678            return;
 679        }
 680
 4681        AddUniqueTriangleSweepPoint(
 4682            GetTrianglePlaneIntersection(
 4683                first,
 4684                second,
 4685                planeY,
 4686                basisDenominator,
 4687                referenceYNumerator),
 4688            intersections,
 4689            ref count);
 4690    }
 691
 692    private static TriangleSweepPoint GetTrianglePlaneIntersection(
 693        TriangleSweepVertex first,
 694        TriangleSweepVertex second,
 695        Signed320 planeY,
 696        Signed192 basisDenominator,
 697        Signed320 referenceYNumerator)
 698    {
 14699        Signed320 deltaY =
 14700            WideArithmetic.SubtractSigned320(second.Y, first.Y);
 14701        Signed320 firstWeight =
 14702            WideArithmetic.SubtractSigned320(second.Y, planeY);
 14703        Signed320 secondWeight =
 14704            WideArithmetic.SubtractSigned320(planeY, first.Y);
 14705        Signed576 x = WideArithmetic.AddSigned576(
 14706            WideArithmetic.MultiplySigned320(first.X, firstWeight),
 14707            WideArithmetic.MultiplySigned320(second.X, secondWeight));
 14708        Signed576 z = WideArithmetic.AddSigned576(
 14709            WideArithmetic.MultiplySigned320(first.Z, firstWeight),
 14710            WideArithmetic.MultiplySigned320(second.Z, secondWeight));
 14711        Signed576 denominator = WideArithmetic.MultiplySigned320(
 14712            Signed320.ExtendValue(basisDenominator),
 14713            deltaY);
 14714        if (denominator.Sign < 0)
 715        {
 8716            x = WideArithmetic.SubtractSigned576(default, x);
 8717            z = WideArithmetic.SubtractSigned576(default, z);
 8718            denominator =
 8719                WideArithmetic.SubtractSigned576(default, denominator);
 8720            firstWeight =
 8721                WideArithmetic.SubtractSigned320(default, firstWeight);
 8722            secondWeight =
 8723                WideArithmetic.SubtractSigned320(default, secondWeight);
 8724            deltaY = WideArithmetic.SubtractSigned320(default, deltaY);
 725        }
 726
 14727        Vector3d localPoint = GetWeightedLocalPoint(
 14728            first.LocalPoint,
 14729            second.LocalPoint,
 14730            secondWeight,
 14731            deltaY);
 14732        return new TriangleSweepPoint(
 14733            new SweepRationalPoint(x, z, denominator),
 14734            WideArithmetic.SubtractSigned320(
 14735                planeY,
 14736                referenceYNumerator),
 14737            localPoint);
 738    }
 739
 740    private static Vector3d GetWeightedLocalPoint(
 741        Vector3d first,
 742        Vector3d second,
 743        Signed320 secondWeight,
 744        Signed320 denominator)
 745    {
 14746        Span<Vector3d> points = stackalloc Vector3d[2]
 14747        {
 14748            first,
 14749            second,
 14750        };
 751        // This ratio is a dimensionless interpolation parameter, so promote
 752        // it to Q32.32 rather than treating the integer quotient as raw.
 14753        _ = Fixed64.TryGetSignedRawRatio(
 14754            Signed832.ExtendValue(
 14755                Signed576.ExtendValue(secondWeight)),
 14756            Signed832.ExtendValue(
 14757                Signed576.ExtendValue(denominator)),
 14758            FixedMath.SHIFT_AMOUNT_I,
 14759            out Fixed64 parameter);
 14760        Span<Fixed64> weights = stackalloc Fixed64[2]
 14761        {
 14762            Fixed64.One - parameter,
 14763            parameter,
 14764        };
 14765        _ = Vector3d.TryGetWeightedAverage(
 14766            points,
 14767            weights,
 14768            out Vector3d localPoint);
 14769        return localPoint;
 770    }
 771
 772    private static void AddUniqueTriangleSweepPoint(
 773        TriangleSweepPoint point,
 774        Span<TriangleSweepPoint> points,
 775        ref int count)
 776    {
 1156777        for (int index = 0; index < count; index++)
 778        {
 425779            if (AreSameSweepPoint(
 425780                    points[index].RationalPoint,
 425781                    point.RationalPoint))
 782            {
 153783                return;
 784            }
 785        }
 786
 153787        points[count++] = point;
 153788    }
 789
 790    private static void KeepTriangleSweepFeature(
 791        TriangleSweepPoint first,
 792        TriangleSweepPoint second,
 793        Vector2d circleStart,
 794        Vector2d direction,
 795        Fixed64 maximumDistance,
 796        Fixed64 radius,
 797        ref bool found,
 798        ref Fixed64 bestDistance,
 799        ref Vector3d bestLocalPoint,
 800        ref Signed576 bestReferenceYOffset)
 801    {
 217802        if (TryGetRationalPointSweepDistance(
 217803                first.RationalPoint,
 217804                circleStart,
 217805                direction,
 217806                maximumDistance,
 217807                radius,
 217808                out Fixed64 firstDistance))
 809        {
 61810            KeepTriangleSweepCandidate(
 61811                firstDistance,
 61812                first.LocalPoint,
 61813                ScaleReferenceYOffset(first.ReferenceYOffset),
 61814                ref found,
 61815                ref bestDistance,
 61816                ref bestLocalPoint,
 61817                ref bestReferenceYOffset);
 818        }
 217819        if (!AreSameSweepPoint(
 217820                first.RationalPoint,
 217821                second.RationalPoint)
 217822            && TryGetRationalPointSweepDistance(
 217823                second.RationalPoint,
 217824                circleStart,
 217825                direction,
 217826                maximumDistance,
 217827                radius,
 217828                out Fixed64 secondDistance))
 829        {
 51830            KeepTriangleSweepCandidate(
 51831                secondDistance,
 51832                second.LocalPoint,
 51833                ScaleReferenceYOffset(second.ReferenceYOffset),
 51834                ref found,
 51835                ref bestDistance,
 51836                ref bestLocalPoint,
 51837                ref bestReferenceYOffset);
 838        }
 217839        if (!TryGetRationalSegmentSweepDistance(
 217840                first.RationalPoint,
 217841                second.RationalPoint,
 217842                circleStart,
 217843                direction,
 217844                maximumDistance,
 217845                radius,
 217846                out Fixed64 segmentDistance,
 217847                out Fixed64 segmentParameter))
 848        {
 57849            return;
 850        }
 851
 160852        Span<Vector3d> points = stackalloc Vector3d[2]
 160853        {
 160854            first.LocalPoint,
 160855            second.LocalPoint,
 160856        };
 160857        Span<Fixed64> weights = stackalloc Fixed64[2]
 160858        {
 160859            Fixed64.One - segmentParameter,
 160860            segmentParameter,
 160861        };
 160862        _ = Vector3d.TryGetWeightedAverage(
 160863            points,
 160864            weights,
 160865            out Vector3d segmentLocalPoint);
 160866        Signed576 segmentReferenceYOffset =
 160867            WideArithmetic.AddSigned576(
 160868                WideArithmetic.MultiplySigned320(
 160869                    first.ReferenceYOffset,
 160870                    Signed320.ExtendValue(
 160871                        Signed192.Raw(weights[0]))),
 160872                WideArithmetic.MultiplySigned320(
 160873                    second.ReferenceYOffset,
 160874                    Signed320.ExtendValue(
 160875                        Signed192.Raw(weights[1]))));
 160876        KeepTriangleSweepCandidate(
 160877            segmentDistance,
 160878            segmentLocalPoint,
 160879            segmentReferenceYOffset,
 160880            ref found,
 160881            ref bestDistance,
 160882            ref bestLocalPoint,
 160883            ref bestReferenceYOffset);
 160884    }
 885
 886    private static void KeepTriangleSweepCandidate(
 887        Fixed64 candidateDistance,
 888        Vector3d candidateLocalPoint,
 889        Signed576 candidateReferenceYOffset,
 890        ref bool found,
 891        ref Fixed64 bestDistance,
 892        ref Vector3d bestLocalPoint,
 893        ref Signed576 bestReferenceYOffset)
 894    {
 272895        if (found)
 896        {
 213897            if (candidateDistance > bestDistance)
 147898                return;
 66899            if ((candidateDistance == bestDistance)
 66900                & (WideArithmetic.CompareNonNegative(
 66901                    GetAbsoluteReferenceYOffset(candidateReferenceYOffset),
 66902                    GetAbsoluteReferenceYOffset(bestReferenceYOffset)) >= 0))
 903            {
 60904                return;
 905            }
 906        }
 907
 65908        found = true;
 65909        bestDistance = candidateDistance;
 65910        bestLocalPoint = candidateLocalPoint;
 65911        bestReferenceYOffset = candidateReferenceYOffset;
 65912    }
 913
 914    private static Signed576 ScaleReferenceYOffset(
 915        Signed320 value) =>
 112916        WideArithmetic.MultiplySigned320(
 112917            value,
 112918            Signed320.ExtendValue(
 112919                Signed192.One));
 920
 921    private static Signed576 GetAbsoluteReferenceYOffset(Signed576 value) =>
 132922        value.Sign < 0
 132923            ? WideArithmetic.SubtractSigned576(default, value)
 132924            : value;
 925}

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.TrianglePrism.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.TrianglePrism.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/// Contains logic for detecting and resolving contact between a triangle
 14/// (used as a triangular prism cross-section) and an oriented box, using
 15/// separating axis tests over the prism and triangle edges/normals.
 16/// </content>
 17internal static partial class WideOrientedBox
 18{
 19    internal static bool TryGetTrianglePrismContact(
 20        Vector3d triangleOrigin,
 21        FixedQuaternion triangleRotation,
 22        FixedTriangle triangle,
 23        Vector3d prismOrigin,
 24        Fixed64 prismRotation,
 25        ReadOnlySpan<Vector2d> prismLocalOffsets,
 26        Fixed64 prismHalfThickness,
 27        out FixedContactAnchors contact)
 28    {
 7529        if (triangle.IsDegenerate)
 30        {
 231            contact = default;
 232            return false;
 33        }
 34
 7335        Span<Vector3d> trianglePoints = stackalloc Vector3d[3]
 7336        {
 7337            triangle.A,
 7338            triangle.B,
 7339            triangle.C,
 7340        };
 7341        WideRationalBasis3d triangleBasis = new(triangleRotation);
 7342        var best = default(WidePointSpanPenetration);
 7343        WideAxis3 up = new(default, Signed320.One, default);
 7344        WideAxis3 firstEdge = GetHullEdge(
 7345            triangleBasis,
 7346            triangle.A,
 7347            triangle.B);
 7348        WideAxis3 secondEdge = GetHullEdge(
 7349            triangleBasis,
 7350            triangle.A,
 7351            triangle.C);
 7352        WideGeometry.GetDifferenceCrossProduct3D(
 7353            triangle.B.X,
 7354            triangle.A.X,
 7355            triangle.B.Y,
 7356            triangle.A.Y,
 7357            triangle.B.Z,
 7358            triangle.A.Z,
 7359            triangle.C.X,
 7360            triangle.A.X,
 7361            triangle.C.Y,
 7362            triangle.A.Y,
 7363            triangle.C.Z,
 7364            triangle.A.Z,
 7365            out Signed192 localNormalX,
 7366            out Signed192 localNormalY,
 7367            out Signed192 localNormalZ);
 7368        if (!TryKeepTrianglePrismAxis(
 7369                up,
 7370                triangleOrigin,
 7371                triangleBasis,
 7372                trianglePoints,
 7373                prismOrigin,
 7374                prismRotation,
 7375                prismLocalOffsets,
 7376                prismHalfThickness,
 7377                ref best)
 7378            || !TryKeepTrianglePrismAxis(
 7379                WideRigidProjection.TransformLocalAxis(
 7380                    triangleBasis,
 7381                    localNormalX,
 7382                    localNormalY,
 7383                    localNormalZ),
 7384                triangleOrigin,
 7385                triangleBasis,
 7386                trianglePoints,
 7387                prismOrigin,
 7388                prismRotation,
 7389                prismLocalOffsets,
 7390                prismHalfThickness,
 7391                ref best))
 92        {
 293            contact = default;
 294            return false;
 95        }
 96
 7197        Span<WideAxis3> triangleEdges = stackalloc WideAxis3[3]
 7198        {
 7199            firstEdge,
 71100            GetHullEdge(triangleBasis, triangle.B, triangle.C),
 71101            GetHullEdge(triangleBasis, triangle.C, triangle.A),
 71102        };
 71103        for (int prismIndex = 0;
 347104            prismIndex < prismLocalOffsets.Length;
 276105            prismIndex++)
 106        {
 278107            Vector2d prismStart = prismLocalOffsets[prismIndex];
 278108            Vector2d prismEnd = prismLocalOffsets[
 278109                prismIndex + 1 == prismLocalOffsets.Length
 278110                    ? 0
 278111                    : prismIndex + 1];
 278112            GetRotatedPlanarEdge(
 278113                prismRotation,
 278114                prismStart,
 278115                prismEnd,
 278116                out Signed192 prismEdgeX,
 278117                out Signed192 prismEdgeZ);
 278118            WideAxis3 prismEdge = new(
 278119                Signed320.ExtendValue(prismEdgeX),
 278120                default,
 278121                Signed320.ExtendValue(prismEdgeZ));
 278122            WideAxis3 prismFace = new(
 278123                prismEdge.Z,
 278124                default,
 278125                WideArithmetic.SubtractSigned320(
 278126                    default,
 278127                    prismEdge.X));
 278128            if (!TryKeepTrianglePrismAxis(
 278129                    prismFace,
 278130                    triangleOrigin,
 278131                    triangleBasis,
 278132                    trianglePoints,
 278133                    prismOrigin,
 278134                    prismRotation,
 278135                    prismLocalOffsets,
 278136                    prismHalfThickness,
 278137                    ref best))
 138            {
 1139                contact = default;
 1140                return false;
 141            }
 142
 277143            for (int triangleIndex = 0;
 1105144                triangleIndex < triangleEdges.Length;
 828145                triangleIndex++)
 146            {
 829147                WideAxis3 triangleEdge = triangleEdges[triangleIndex];
 829148                if (!TryKeepTrianglePrismAxis(
 829149                        CrossWithUp(triangleEdge),
 829150                        triangleOrigin,
 829151                        triangleBasis,
 829152                        trianglePoints,
 829153                        prismOrigin,
 829154                        prismRotation,
 829155                        prismLocalOffsets,
 829156                        prismHalfThickness,
 829157                        ref best)
 829158                    || !TryKeepTrianglePrismAxis(
 829159                        WideAxis3.Cross(triangleEdge, prismEdge),
 829160                        triangleOrigin,
 829161                        triangleBasis,
 829162                        trianglePoints,
 829163                        prismOrigin,
 829164                        prismRotation,
 829165                        prismLocalOffsets,
 829166                        prismHalfThickness,
 829167                        ref best))
 168                {
 1169                    contact = default;
 1170                    return false;
 171                }
 172            }
 173        }
 174
 69175        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 69176        Vector3d normal = WideNormalization.GetNormalized(
 69177            Signed576.ExtendValue(orientedAxis.X),
 69178            Signed576.ExtendValue(orientedAxis.Y),
 69179            Signed576.ExtendValue(orientedAxis.Z));
 69180        Vector3d triangleLocalPoint = GetHullSupportLocalPoint(
 69181            triangleBasis,
 69182            trianglePoints,
 69183            orientedAxis,
 69184            maximize: true);
 69185        Vector3d prismLocalPoint = GetPrismSupportOffset(
 69186            prismLocalOffsets,
 69187            prismHalfThickness,
 69188            prismRotation,
 69189            orientedAxis);
 69190        Fixed64 depth = best.GetRoundedDepth(out bool depthIsClamped);
 69191        contact = new FixedContactAnchors(
 69192            new FixedPointAnchor(
 69193                triangleOrigin,
 69194                triangleRotation,
 69195                triangleLocalPoint),
 69196            new FixedPointAnchor(
 69197                prismOrigin,
 69198                FixedQuaternion.FromAxisAngle(
 69199                    Vector3d.Up,
 69200                    -prismRotation),
 69201                prismLocalPoint),
 69202            normal,
 69203            depth,
 69204            depthIsClamped);
 69205        return true;
 206    }
 207
 208    private static bool TryKeepTrianglePrismAxis(
 209        WideAxis3 axis,
 210        Vector3d triangleOrigin,
 211        WideRationalBasis3d triangleBasis,
 212        ReadOnlySpan<Vector3d> trianglePoints,
 213        Vector3d prismOrigin,
 214        Fixed64 prismRotation,
 215        ReadOnlySpan<Vector2d> prismLocalOffsets,
 216        Fixed64 prismHalfThickness,
 217        ref WidePointSpanPenetration best)
 218    {
 2080219        if (axis.IsZero)
 274220            return true;
 221
 1806222        GetHullProjectionInterval(
 1806223            trianglePoints,
 1806224            triangleBasis,
 1806225            axis,
 1806226            Signed192.One,
 1806227            out Signed576 triangleMinimum,
 1806228            out Signed576 triangleMaximum);
 1806229        Signed576 originProjection = WideArithmetic.MultiplySigned576(
 1806230            WideRigidProjection.GetWorldOriginDifferenceProjection(
 1806231                prismOrigin,
 1806232                triangleOrigin,
 1806233                axis),
 1806234            Signed192.One);
 1806235        Signed576 prismMinimum = default;
 1806236        Signed576 prismMaximum = default;
 1806237        bool hasPlanarProjection = false;
 18060238        for (int index = 0; index < prismLocalOffsets.Length; index++)
 239        {
 7224240            Signed576 projection = GetRotatedPlanarOffsetProjection(
 7224241                prismLocalOffsets[index],
 7224242                prismRotation,
 7224243                axis);
 7224244            if (!hasPlanarProjection)
 245            {
 1806246                prismMinimum = projection;
 1806247                prismMaximum = projection;
 1806248                hasPlanarProjection = true;
 249            }
 250            else
 251            {
 5418252                if (CompareSigned(projection, prismMinimum) < 0)
 839253                    prismMinimum = projection;
 5418254                if (CompareSigned(projection, prismMaximum) > 0)
 898255                    prismMaximum = projection;
 256            }
 257        }
 258
 1806259        Signed576 verticalRadius = WideArithmetic.MultiplySigned576(
 1806260            WideArithmetic.MultiplySigned576(
 1806261                Signed576.ExtendValue(
 1806262                    GetMagnitude(axis.Y)),
 1806263                Signed192.Raw(prismHalfThickness)),
 1806264            Signed192.One);
 1806265        prismMinimum = WideArithmetic.MultiplySigned576(
 1806266            WideArithmetic.SubtractSigned576(
 1806267                WideArithmetic.AddSigned576(
 1806268                    originProjection,
 1806269                    prismMinimum),
 1806270                verticalRadius),
 1806271            triangleBasis.Denominator);
 1806272        prismMaximum = WideArithmetic.MultiplySigned576(
 1806273            WideArithmetic.AddSigned576(
 1806274                WideArithmetic.AddSigned576(
 1806275                    originProjection,
 1806276                    prismMaximum),
 1806277                verticalRadius),
 1806278            triangleBasis.Denominator);
 1806279        Signed576 positiveOverlap = WideArithmetic.SubtractSigned576(
 1806280            triangleMaximum,
 1806281            prismMinimum);
 1806282        Signed576 negativeOverlap = WideArithmetic.SubtractSigned576(
 1806283            prismMaximum,
 1806284            triangleMinimum);
 1806285        if (positiveOverlap.Sign < 0 || negativeOverlap.Sign < 0)
 4286            return false;
 287
 1802288        bool negate =
 1802289            CompareSigned(positiveOverlap, negativeOverlap) > 0;
 1802290        Signed576 overlap = negate
 1802291            ? negativeOverlap
 1802292            : positiveOverlap;
 1802293        Signed320 commonDenominator = WideArithmetic.MultiplySigned192(
 1802294            triangleBasis.Denominator,
 1802295            Signed192.One);
 1802296        Signed576 squaredAxisLength = axis.SquaredLength;
 1802297        if (best.ShouldReplace(
 1802298            overlap,
 1802299            squaredAxisLength,
 1802300            commonDenominator))
 301        {
 140302            best = new WidePointSpanPenetration(
 140303                axis,
 140304                negate,
 140305                overlap,
 140306                squaredAxisLength,
 140307                commonDenominator);
 308        }
 309
 1802310        return true;
 311    }
 312}

Methods/Properties

GetBoxProjectionRadiusNumerator(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&)
GetLocalBoxProjectionRadiusNumerator(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Vector3d)
GetRotatedLocalProjectionSign(FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetRotatedLocalAxisNumerators(FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetRelativeLocalPointNumerators(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetRelativeLocalPointNumerators(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
.ctor(System.Int32,System.Int32,System.Boolean,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
TryGetContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepFirstFaceAxis(System.Int32,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Signed192>,System.ReadOnlySpan`1<FixedMathSharp.Signed192>,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideOrientedBox/BoxPenetration&)
TryKeepSecondFaceAxis(System.Int32,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Signed192>,System.ReadOnlySpan`1<FixedMathSharp.Signed192>,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideOrientedBox/BoxPenetration&)
TryKeepCrossAxis(System.Int32,System.Int32,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Signed192>,System.ReadOnlySpan`1<FixedMathSharp.Signed192>,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideOrientedBox/BoxPenetration&)
TryKeepBoxPenetration(System.Int32,System.Int32,System.Boolean,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Geometry.WideOrientedBox/BoxPenetration&)
CompareBoxDepth(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
.ctor(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3,System.Boolean,FixedMathSharp.Signed704,FixedMathSharp.Signed832,System.Int32)
TryGetCenteredCapsuleContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
CanOverlapCenteredCapsule(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
CanOverlapCenteredCapsule(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TryGetCenteredCapsulePenetration(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed192,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192&,FixedMathSharp.Geometry.WideOrientedBox/CapsulePenetration&)
GetLocalEdgeCenter(FixedMathSharp.Vector3d,System.Int32,System.Int32,System.Int32)
GetMatchedBoxSupportLocalPoint(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedPointAnchor&,FixedMathSharp.Geometry.WideAxis3)
GetMatchedBoxSupportLocalPoint(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedPointAnchor&,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
GetMatchedCapsuleSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,System.Boolean)
GetMatchedSupportCoordinate(FixedMathSharp.Geometry.FixedPointAnchor&,FixedMathSharp.Geometry.FixedPointAnchor&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Signed576)
.ctor(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
get_IsZero()
op_UnaryNegation(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3)
GetVertexToCapsuleAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Signed192,FixedMathSharp.Fixed64)
GetLocalVertexToCapsuleAxis(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed704&)
GetCapsuleEndpointToBoxEdgeAxis(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,System.Int32,System.Int32,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320&)
GetLocalPointToCapsuleCenterAxis(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed192,FixedMathSharp.Vector3d)
GetLocalPointToCapsuleEndpointAxis(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Geometry.WideAxis3&,System.Int32)
GetLocalEndpointComponent(FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,System.Int32)
GetScaledCapsuleAxisSquared(FixedMathSharp.Vector3d,FixedMathSharp.Signed192)
GetCapsuleCenterAxisProjection(FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Vector3d)
GetCornerToAxisCenterAxis3D(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Signed192)
GetCornerToAxisCenterComponent(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Signed192)
GetPerpendicularAxis(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
GetPerpendicularComponent(FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
TryKeepCapsuleAxis(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320&,FixedMathSharp.Fixed64,System.Int32,FixedMathSharp.Geometry.WideOrientedBox/CapsulePenetration&)
GetLocalCapsuleBoxRadius(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3&,FixedMathSharp.Geometry.WideAxis3&)
GetLocalCapsuleCenterProjection(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3&,FixedMathSharp.Geometry.WideAxis3&)
GetCapsuleBasisProjection(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3&,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
GetCapsuleAxisProjection(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3&,FixedMathSharp.Geometry.WideAxis3&)
GetCapsuleSquaredLength(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3&)
IsWideCapsuleRadicalAtLeastRational(FixedMathSharp.Signed832,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Signed704)
GetWideCapsuleDepth(FixedMathSharp.Signed704,FixedMathSharp.Signed832,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,System.Boolean&)
CompareWideCapsuleDepth(FixedMathSharp.Signed704,FixedMathSharp.Signed832,FixedMathSharp.Signed704,FixedMathSharp.Signed832)
ToCapsuleAxis(FixedMathSharp.Geometry.WideAxis3&)
TryGetCenteredCapsuleSlabContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepCapsuleSlabAxis(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideOrientedBox/RadialPenetration&)
GetPlanarAxisProjection(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector2d)
GetCornerToCapsuleEndpointAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.Int32)
GetCapsuleSlabSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TryGetCircleSlabContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
GetCircleSlabBoxContactPoint(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Geometry.WideAxis3)
TryKeepCircleSlabAxis(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideOrientedBox/RadialPenetration&)
IsRadicalAtLeastRatio(FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed192)
GetRadialDepth(FixedMathSharp.Signed576,FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed192,FixedMathSharp.Fixed64&,System.Boolean&)
GetCornerToOriginAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d)
GetLocalOffsetNumerator(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector3d)
GetCircleSlabSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
GetLocalPlanarSupportDirection(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Fixed64)
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed320)
.ctor(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576)
.ctor(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
.ctor(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
TryBuildCircleSlabProjectionConstraints(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint>,System.Int32&)
AddBoxAxisConstraints(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/SweepSpatialConstraint>,System.Int32&)
TryAddProjectionConstraint(FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint>,System.Int32&)
BuildCircleSlabProjectionVertices(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint>,System.Int32&)
GetSweepBoxCorner(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d)
TryAddPlaneIntersection(FixedMathSharp.Geometry.WideOrientedBox/SweepBoxCorner,FixedMathSharp.Geometry.WideOrientedBox/SweepBoxCorner,FixedMathSharp.Signed320,FixedMathSharp.Signed192,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint>,System.Int32&)
AddUniqueSweepPoint(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint>,System.Int32&)
AreSameSweepPoint(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint)
.cctor()
.ctor(FixedMathSharp.Signed576,FixedMathSharp.Signed832)
TryGetCircleSlabSweepDistance(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
GetCircleSlabSeparationLowerBound(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
IsClosestProjectionOnConstraint(System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint>,System.Int32,System.Int32,FixedMathSharp.Vector2d,FixedMathSharp.Signed576,FixedMathSharp.Signed320)
GetClosestProjectionVertexDistanceLowerBound(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector2d)
GetRationalPointDistance(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Vector2d)
CompareRationalPointDistances(FixedMathSharp.Geometry.WideOrientedBox/RationalPointDistance,FixedMathSharp.Geometry.WideOrientedBox/RationalPointDistance)
GetRationalPointDistanceLowerBound(FixedMathSharp.Geometry.WideOrientedBox/RationalPointDistance)
GetCircleSlabVerticalSeparationLowerBound(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
TryGetExpandedEdgeSweepDistance(System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint>,System.Int32,System.Int32,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
CompareExpandedEdgeAtHalf(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Fixed64,System.Int64)
CompareExpandedEdgeAt(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
IsRoundedEdgeFeatureValid(System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint>,System.Int32,System.Int32,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TryGetRationalPointSweepDistance(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
GetHalfToEvenIncrement(System.Int32,System.Int64)
CompareRationalPointAtHalf(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Int64)
CompareRationalPointAt(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
GetSweepProjection(FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint,FixedMathSharp.Vector2d)
TryGetConvexHullContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepPointSpanAxis(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Geometry.WideAxis3&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Geometry.WidePointSpanPenetration&)
TryGetConvexHullCenteredCapsuleContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepHullCapsuleCandidate(FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate&,System.Boolean&)
EvaluateHullCapsuleCandidate(FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Span`1<System.UInt64>,System.Int32&,System.Span`1<System.UInt64>,FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3&,System.Boolean&,FixedMathSharp.Signed192&)
BuildHullCapsuleCandidateAxis(FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Signed192,FixedMathSharp.Fixed64)
GetCapsuleEndpointToHullEdgeAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,System.Int32)
.ctor(FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidateKind,System.Int32,System.Int32)
GetHullCapsuleProjectionInterval(System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3,System.Span`1<System.UInt64>,System.Int32&,System.Span`1<System.UInt64>,System.Int32&)
BuildHullCapsuleLocalProjection(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3,System.Span`1<System.UInt64>,System.Int32&)
BuildHullCapsuleProjectionTerm(FixedMathSharp.Signed704,FixedMathSharp.Signed192,System.Span`1<System.UInt64>,System.Int32&)
GetHullCapsuleCenterProjection(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3)
BuildHullCapsuleAxisSquared(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3,System.Span`1<System.UInt64>)
GetMatchedHullCapsuleSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.WideRationalBasis3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3,FixedMathSharp.Geometry.FixedPointAnchor&)
IsHullCapsuleSupportPoint(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3,System.ReadOnlySpan`1<System.UInt64>,System.Int32)
GetHullCapsuleDepth(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,System.Boolean&)
CompareHullCapsuleDepthToTwiceRaw(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
MultiplyHullCapsuleMagnitude(System.Span`1<System.UInt64>,FixedMathSharp.Signed192,System.Span`1<System.UInt64>)
MultiplyHullCapsuleMagnitude(System.Span`1<System.UInt64>,FixedMathSharp.Signed320,System.Span`1<System.UInt64>)
GetHullCapsuleMagnitude(FixedMathSharp.Signed192,System.Span`1<System.UInt64>)
GetHullCapsuleMagnitude(FixedMathSharp.Signed320,System.Span`1<System.UInt64>)
GetHullCapsuleMagnitude(FixedMathSharp.Signed576,System.Span`1<System.UInt64>)
GetHullCapsuleMagnitude(FixedMathSharp.Signed704,System.Span`1<System.UInt64>)
CompareHullCapsuleSignedMagnitudes(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32)
CombineHullCapsuleSignedMagnitudes(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.Span`1<System.UInt64>,System.Int32&)
ContainsConvexHullPoint(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.FixedPointAnchor)
TryGetConvexHullContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepHullFaceAxes(System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Geometry.WidePointSpanPenetration&)
TryKeepHullPairAxis(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Geometry.WidePointSpanPenetration&)
GetHullProjectionInterval(System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed192,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
GetHullEdge(FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetHullSupportLocalPoint(FixedMathSharp.Geometry.WideRationalBasis3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Geometry.WideAxis3&,System.Boolean)
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
ToWide()
TryGetConvexPrismContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepConvexPrismAxis(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WidePointSpanPenetration&)
GetRotatedPlanarOffsetProjection(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideAxis3)
GetRotatedPlanarEdge(FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&)
GetLocalAxisSupportPoint(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3)
GetPrismSupportOffset(System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideAxis3)
ShouldNegateCanonicalAxis(FixedMathSharp.Geometry.WideAxis3)
IsLexicographicallyEarlier(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
CrossWithUp(FixedMathSharp.Geometry.WideAxis3)
CrossWithPlanarEdge(FixedMathSharp.Geometry.WideOrientedBox/RationalAxis3,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
.ctor(FixedMathSharp.Geometry.WideAxis3,System.Boolean,FixedMathSharp.Fixed64,System.Boolean,FixedMathSharp.Signed576,FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
GetAxes(FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&,FixedMathSharp.Vector3d&)
GetLocalSupportPoint(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
GetBoundsClippedToDomain(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
Contains(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
GetClosestPointAnchor(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
GetNearestFaceNormal(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
TryMaterializeLocalPoint(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&)
TryMaterializeLocalPoint(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&)
TryTransformLocalOffset(FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&)
TryGetRelativeOffset(FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&)
TryGetSupportOffset(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&)
TryGetSupportDifference(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&)
TryGetSupportDifference(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&)
GetDirectionProjections(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
GetPointProjections(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
IsWithinExtent(FixedMathSharp.Signed320,FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
GetClampedNumerator(FixedMathSharp.Signed320,FixedMathSharp.Signed320,System.Boolean)
GetSignedExtent(FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetExtentNumerator(FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
GetMagnitude(FixedMathSharp.Signed576)
GetMagnitude(FixedMathSharp.Signed320)
GetMagnitude(FixedMathSharp.Signed192)
GetExtentNumerator(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector3d)
GetClippedEndpoint(FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed320,System.Boolean)
GetAxis(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Boolean)
CompareSigned(FixedMathSharp.Signed320,FixedMathSharp.Signed320)
CompareSigned(FixedMathSharp.Signed576,FixedMathSharp.Signed576)
ToSigned576(FixedMathSharp.Signed192)
.ctor(FixedMathSharp.Geometry.WideAxis3,System.Boolean,FixedMathSharp.Fixed64,System.Boolean,FixedMathSharp.Signed576,FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
.ctor(System.Int32,System.Int32,System.Int32)
TryGetCenteredCylinderContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
TryGetCenteredCylinderContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&,FixedMathSharp.Geometry.WideOrientedBox/CenteredCylinderContactFeature&)
GetCenteredCylinderContactFeature(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideRationalBasis3d)
AreParallel(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Geometry.WideAxis3)
GetCornerToAxisEndpointAxis3D(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,System.Int32)
GetCornerToAxisEndpointComponent(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,System.Int32)
TryKeepCylinderAxis(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideOrientedBox/CylinderPenetration&)
IsCylinderRadicalAtLeastRatio(FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192)
GetCylinderDepth(FixedMathSharp.Signed576,FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192,FixedMathSharp.Fixed64&,System.Boolean&)
.ctor(FixedMathSharp.Signed320,FixedMathSharp.Signed320)
Equals(FixedMathSharp.Geometry.WideOrientedBox/LocalCapContact)
.cctor()
GetCenteredCylinderCapFaceContacts(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors,FixedMathSharp.Geometry.WideOrientedBox/CenteredCylinderContactFeature,System.Span`1<FixedMathSharp.Geometry.FixedContactLocalPoints>,System.Int32&)
GetRationalLocalPoint(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192)
GetFaceCoordinates(System.Int32,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
KeepCapExtreme(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,System.Boolean,System.Boolean,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/LocalCapContact>,System.Int32&)
GetSignedFaceExtent(System.Int32,System.Int32,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetLocalCoordinates(System.Int32,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&,FixedMathSharp.Signed320&)
ClampToExtent(FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetRationalLocalPoint(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
TryMaterializeCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed576,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64&)
TryMaterializeCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed576,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64&)
TryMaterializeRationalOffset(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d&)
TryMaterializeSupportDifferenceCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed576,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64&)
TryMaterializeBoxSupportDifferenceCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Fixed64&)
TryGetRelativeOffsetCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed576,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64&)
TryGetRationalSegmentSweepDistance(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&)
CompareApproachingLineAt(System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,System.Int64,System.ReadOnlySpan`1<System.UInt64>)
CompareRationalSegmentLineAtHalf(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,System.Int64)
CompareRationalSegmentLineAt(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
TryGetRationalSegmentParameter(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
GetEdgeSquaredMagnitude(FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.Span`1<System.UInt64>)
GetCrossMagnitude(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Span`1<System.UInt64>,System.Int32&)
GetCrossMagnitude(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Span`1<System.UInt64>,System.Int32&)
GetCrossMagnitude(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.Span`1<System.UInt64>,System.Int32&)
GetDotMagnitude(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Span`1<System.UInt64>,System.Int32&)
CombineSignedMagnitudes(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.Span`1<System.UInt64>,System.Int32&)
CopyMagnitude(System.ReadOnlySpan`1<System.UInt64>,System.Span`1<System.UInt64>)
.ctor(FixedMathSharp.Signed320,FixedMathSharp.Signed320)
TryGetRayIntersectionInterval(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&)
TryClipRayAxis(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideOrientedBox/RayBound&,FixedMathSharp.Geometry.WideOrientedBox/RayBound&)
NormalizeRayBound(FixedMathSharp.Signed192,FixedMathSharp.Signed192)
CompareRayBounds(FixedMathSharp.Geometry.WideOrientedBox/RayBound,FixedMathSharp.Geometry.WideOrientedBox/RayBound)
RoundRayBound(FixedMathSharp.Geometry.WideOrientedBox/RayBound)
GetRelativeRotatedBoundsClippedToDomain(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion)
GetRelativeBoundsCoordinate(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&)
GetRelativeEndpointNumerator(FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean)
SelectEndpoint(FixedMathSharp.Signed320,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean)
GetRelativeEndpointClippedToDomain(FixedMathSharp.Signed576,FixedMathSharp.Signed320,System.Boolean)
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64)
DoCenteredRigidCapsulesOverlap(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
ClampUnitRatio(System.Span`1<System.UInt64>,System.Span`1<System.UInt64>,System.Int32)
SetRigidSegmentRatio(System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed320,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed576,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>)
SetRigidSegmentProjectionRatio(FixedMathSharp.Signed704,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>)
IsRigidLinePairWithinRadius(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed704,FixedMathSharp.Signed704,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed576,FixedMathSharp.Signed192)
IsRigidPointLineWithinRadius(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed704,FixedMathSharp.Signed576,FixedMathSharp.Signed192)
IsRigidPointWithinRadius(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192)
GetRadiusThreshold(FixedMathSharp.Signed192,FixedMathSharp.Signed576,System.ReadOnlySpan`1<System.UInt64>,System.Span`1<System.UInt64>)
GetSquaredMagnitude(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Span`1<System.UInt64>)
GetTripleProductMagnitude(FixedMathSharp.Signed576,FixedMathSharp.Signed704,FixedMathSharp.Signed704,System.Span`1<System.UInt64>)
GetProductDifference(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Span`1<System.UInt64>,System.Int32&)
GetProductDifference(FixedMathSharp.Signed576,FixedMathSharp.Signed704,FixedMathSharp.Signed576,FixedMathSharp.Signed704,System.Span`1<System.UInt64>,System.Int32&)
DoubleMagnitude(System.Span`1<System.UInt64>)
DoubleProduct(FixedMathSharp.Signed576,FixedMathSharp.Signed320)
GetRigidSegmentLowerDifference(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideOrientedBox/RigidSegmentAxis,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideOrientedBox/RigidSegmentAxis,FixedMathSharp.Signed576,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
GetRigidSegmentLowerDifference(FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576)
AddRigidSegmentDisplacement(FixedMathSharp.Signed576&,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
SubtractRigidSegmentDisplacement(FixedMathSharp.Signed576&,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
Dot(FixedMathSharp.Geometry.WideOrientedBox/RigidSegmentAxis,FixedMathSharp.Geometry.WideOrientedBox/RigidSegmentAxis)
Dot(FixedMathSharp.Geometry.WideOrientedBox/RigidSegmentAxis,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
TryKeepCenteredRigidCylinderCapsuleClosestAxis(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideConvexPrismRelations/CylinderCapsulePenetration&)
TryKeepCenteredRigidCylinderCylinderClosestAxis(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideConvexPrismRelations/CylinderCylinderPenetration&)
TryKeepCenteredRigidCylinderClosestAxis(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideOrientedBox/RigidClosestPairKind,FixedMathSharp.Geometry.WideConvexPrismRelations/CylinderCapsulePenetration&,FixedMathSharp.Geometry.WideConvexPrismRelations/CylinderCylinderPenetration&)
BuildRigidPointLineClosestComponent(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Signed704,System.Span`1<System.UInt64>,System.Int32&)
BuildRigidLinePairClosestComponent(FixedMathSharp.Signed576,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed320,System.ReadOnlySpan`1<System.UInt64>,System.Int32,FixedMathSharp.Signed320,System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.Span`1<System.UInt64>,System.Int32&)
GetSignedMagnitude(FixedMathSharp.Signed576,System.Span`1<System.UInt64>,System.Int32&)
RemoveCommonPowerOfTwo(System.Span`1<System.UInt64>,System.Span`1<System.UInt64>,System.Span`1<System.UInt64>)
GetTrailingZeroCount(System.ReadOnlySpan`1<System.UInt64>)
ShiftRightMagnitude(System.Span`1<System.UInt64>,System.Int32)
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
.ctor(FixedMathSharp.Signed192,FixedMathSharp.Signed192)
TryGetRigidCapsuleDistanceInterval(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&,System.Boolean&,System.Boolean&)
TryGetRigidCylinderDistanceInterval(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&,System.Boolean&,System.Boolean&)
TryGetRigidConeDistanceInterval(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&,System.Boolean&,System.Boolean&)
GetRigidLocalRay(FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d)
TryGetCardinalLocalYAxis(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d&)
ScaleRigidDimension(FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
ScaleRigidDimensionSum(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
ScaleRigidDimensionWithDoubleExpansion(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
NarrowRigidQueryValue(FixedMathSharp.Signed320)
GetRadialPolynomial(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
MergeRigidCapsuleCap(FixedMathSharp.Geometry.WideOrientedBox/RigidLocalRay,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Boolean,FixedMathSharp.Fixed64,System.Boolean&,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&)
GetSpherePolynomial(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
GetConePolynomial(FixedMathSharp.Geometry.WideOrientedBox/RigidLocalRay,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed192&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
TryGetCenteredAxialBounds(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideOrientedBox/RigidRayBound&,FixedMathSharp.Geometry.WideOrientedBox/RigidRayBound&)
TryGetLinearBounds(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideOrientedBox/RigidRayBound&,FixedMathSharp.Geometry.WideOrientedBox/RigidRayBound&)
NormalizeRigidBound(FixedMathSharp.Signed192,FixedMathSharp.Signed192)
CompareRigidBounds(FixedMathSharp.Geometry.WideOrientedBox/RigidRayBound,FixedMathSharp.Geometry.WideOrientedBox/RigidRayBound)
IsCylinderContained(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Boolean)
IsCapsuleContained(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Boolean)
IsConeContained(FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Int32,System.Boolean)
EvaluatePolynomialAtOne(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
AddRigidSquares(FixedMathSharp.Signed192,FixedMathSharp.Signed192)
AddRigidSquares(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
AddRigidProducts(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
AddRigidProducts(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
MergeRigidInterval(System.Boolean,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean&,FixedMathSharp.Fixed64&,FixedMathSharp.Fixed64&)
TryGetSweptSphereIntersectionDistance(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.FixedSegment,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
TryGetSphereContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
TryGetContainedSphereContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Geometry.FixedContactAnchors&)
GetSphereSurfaceAnchor(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Boolean)
GetProjectionNumerator(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
GetRationalLocalOffsetNumerators(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&,FixedMathSharp.Signed576&)
GetRationalLocalOffsetNumerator(FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetOriginRelativeNumerator(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed576)
SumSquares(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
GetRoundedRadialDepth(FixedMathSharp.Fixed64,FixedMathSharp.Signed832,FixedMathSharp.Signed320)
CorrectRoundedRadialDepth(FixedMathSharp.Fixed64,FixedMathSharp.Signed832,FixedMathSharp.Signed320,FixedMathSharp.Fixed64&)
GetLowerMidpointAdjustment(System.Int32,System.Int64)
GetUpperMidpointAdjustment(System.Int32,System.Int64)
CompareRadialDepthToTwiceRaw(FixedMathSharp.Fixed64,FixedMathSharp.Signed832,FixedMathSharp.Signed320,FixedMathSharp.Signed192)
TryGetTriangleContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepTriangleEdgeAxes(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideAxis3>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.FixedTriangle&,FixedMathSharp.Geometry.WidePointSpanPenetration&)
TryKeepTriangleAxis(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.FixedTriangle&,FixedMathSharp.Geometry.WidePointSpanPenetration&)
GetTriangleSupportLocalPoint(FixedMathSharp.Geometry.FixedTriangle&,FixedMathSharp.Geometry.WideRationalBasis3d&,FixedMathSharp.Geometry.WideAxis3&)
GetTriangleFaceContacts(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Geometry.FixedContactAnchors,System.Span`1<FixedMathSharp.Geometry.FixedContactLocalPoints>,System.Int32&)
GetParallelTriangleFaceAxis(FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector3d)
GetDirectionProjection(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Vector3d)
IsParallel(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
TryGetTriangleCapsuleSlabContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepTriangleCapsuleSlabAxis(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Signed192,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WideOrientedBox/RadialPenetration&)
DoesRadialOverlap(FixedMathSharp.Signed576,FixedMathSharp.Signed832,FixedMathSharp.Signed192)
GetTriangleVertexToCapsuleEndpointAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.Int32)
.ctor(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Vector3d)
ToSweepPoint(FixedMathSharp.Signed192)
.ctor(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Signed320,FixedMathSharp.Vector3d)
TryGetFiniteSlabProjectedCircleSweep(FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Geometry.FixedPointAnchor&)
TryGetTriangleProjectionInteriorPoint(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Vector2d,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Vector3d&)
TryGetTriangleInteriorLocalCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed832,FixedMathSharp.Fixed64&)
GetTriangleSweepVertex(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,FixedMathSharp.Vector3d,FixedMathSharp.Signed320)
AreSameProjectedPoint(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex)
KeepTriangleEdgeSweep(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean&,FixedMathSharp.Fixed64&,FixedMathSharp.Vector3d&,FixedMathSharp.Signed576&)
GetClippedTriangleEdgeEndpoint(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed320)
KeepTrianglePlaneEdgeSweep(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed320,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean&,FixedMathSharp.Fixed64&,FixedMathSharp.Vector3d&,FixedMathSharp.Signed576&)
TryAddTrianglePlaneIntersection(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed320,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepPoint>,System.Int32&)
GetTrianglePlaneIntersection(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepVertex,FixedMathSharp.Signed320,FixedMathSharp.Signed192,FixedMathSharp.Signed320)
GetWeightedLocalPoint(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
AddUniqueTriangleSweepPoint(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepPoint,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepPoint>,System.Int32&)
KeepTriangleSweepFeature(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepPoint,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepPoint,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Boolean&,FixedMathSharp.Fixed64&,FixedMathSharp.Vector3d&,FixedMathSharp.Signed576&)
KeepTriangleSweepCandidate(FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Signed576,System.Boolean&,FixedMathSharp.Fixed64&,FixedMathSharp.Vector3d&,FixedMathSharp.Signed576&)
ScaleReferenceYOffset(FixedMathSharp.Signed320)
GetAbsoluteReferenceYOffset(FixedMathSharp.Signed576)
TryGetTrianglePrismContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedContactAnchors&)
TryKeepTrianglePrismAxis(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.WidePointSpanPenetration&)