< 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.ScaledFrame.cs
File 12: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHullCapsule.Support.cs
File 13: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexHullPair.cs
File 14: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ConvexPrism.cs
File 15: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.cs
File 16: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Cylinder.cs
File 17: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CylinderCapFace.cs
File 18: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.CylinderStrictOverlap.cs
File 19: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Materialization.cs
File 20: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RationalSegmentSweep.cs
File 21: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Ray.cs
File 22: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RelativeBounds.cs
File 23: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RigidAxisRelations.cs
File 24: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.RigidFiniteAxisQuery.cs
File 25: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.ScaledHull.cs
File 26: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Sphere.cs
File 27: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.Triangle.cs
File 28: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.TriangleCircleSlabSweep.cs
File 29: /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Wide/OrientedBox/WideOrientedBox.TrianglePrism.cs
Line coverage
100%
Covered lines: 10177
Uncovered lines: 0
Coverable lines: 10177
Total lines: 15344
Line coverage: 100%
Branch coverage
100%
Covered branches: 2346
Total branches: 2346
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: DoesCenteredCapsulePenetrate(...)100%22100%
File 3: .ctor(...)100%11100%
File 3: TryGetCenteredCapsuleContact(...)100%2626100%
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%1212100%
File 3: GetMatchedCapsuleSupportAnchor(...)100%22100%
File 3: GetMatchedSupportCoordinate(...)100%1010100%
File 4: .ctor(...)100%11100%
File 4: get_IsZero()100%44100%
File 4: op_UnaryNegation(...)100%11100%
File 4: GetCornerToAxisEndpointAxis3D(...)100%11100%
File 4: GetCornerToAxisEndpointComponent(...)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%2424100%
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: CompareWideCapsuleRadicalToRational(...)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: .ctor(...)100%22100%
File 8: get_DoubleTimeScale()100%11100%
File 8: .ctor(...)100%11100%
File 8: TryGetCircleSlabSweepDistance(...)100%11100%
File 8: TryGetCircleSlabSweepDistance(...)100%11100%
File 8: TryGetCircleSlabSweepDistanceCore(...)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%66100%
File 8: IsExactEdgeFeatureValid(...)100%44100%
File 8: TryGetRationalPointSweepDistance(...)100%1010100%
File 8: GetHalfToEvenIncrement(...)100%11100%
File 8: CompareRationalPointAt(...)100%22100%
File 8: GetSweepProjection(...)100%11100%
File 8: GetSweepProjection(...)100%11100%
File 9: TryGetConvexHullContact(...)100%1616100%
File 9: TryKeepPointSpanAxis(...)100%1212100%
File 10: TryGetConvexHullCenteredCapsuleContact(...)100%66100%
File 10: DoesConvexHullCenteredCapsuleStrictlyOverlap(...)100%11100%
File 10: TryFindHullCapsuleCandidate(...)100%3838100%
File 10: TryGetClosestHullSphereFeature(...)100%2020100%
File 10: TryKeepHullCapsuleCandidate(...)100%1010100%
File 10: EvaluateHullCapsuleCandidate(...)100%1616100%
File 10: GetHullTriangleNormal(...)100%11100%
File 10: BuildHullCapsuleCandidateAxis(...)100%66100%
File 10: GetCapsuleEndpointToHullEdgeAxis(...)100%66100%
File 11: .ctor(...)100%11100%
File 11: Point(...)100%11100%
File 11: Endpoint(...)100%22100%
File 11: Relative(...)100%11100%
File 11: Coordinate(...)100%11100%
File 11: TryGetConvexHullCenteredCapsuleContact(...)100%66100%
File 11: DoesConvexHullCenteredCapsuleStrictlyOverlap(...)100%22100%
File 11: GetScaledHullCapsuleSupportAnchor(...)100%5252100%
File 11: IsScaledHullCapsuleSupport(...)100%11100%
File 11: FindScaledHullCapsuleCandidate(...)100%3232100%
File 11: EvaluateScaledHullCapsuleCandidate(...)100%1818100%
File 11: GetScaledHullCapsuleOverlapSign(...)100%11100%
File 11: BuildScaledHullCapsuleAxis(...)100%2626100%
File 11: SetScaledHullCross(...)100%2222100%
File 11: Subtract(...)100%11100%
File 11: CompareScaledHullValues(...)100%11100%
File 11: SetScaledHullVectorDot(...)100%11100%
File 11: SetScaledHullAxisDot(...)100%11100%
File 11: NormalizeScaledHullAxis(...)100%1010100%
File 12: .ctor(...)100%11100%
File 12: GetHullCapsuleProjectionInterval(...)100%66100%
File 12: BuildHullCapsuleLocalProjection(...)100%11100%
File 12: GetHullCapsuleCenterProjection(...)100%11100%
File 12: BuildHullCapsuleAxisSquared(...)100%11100%
File 12: ContainsHullSphereSupportProjection(...)100%1010100%
File 12: GetMatchedHullCapsuleSupportAnchor(...)100%6060100%
File 12: KeepHullCapsuleCoreMatch(...)100%66100%
File 12: IsHullCapsuleSupportPoint(...)100%11100%
File 12: GetHullCapsuleDepth(...)100%11100%
File 12: GetHullCapsuleDepth(...)100%88100%
File 12: CompareHullCapsuleDepthToTwiceRaw(...)100%11100%
File 12: MultiplyHullCapsuleMagnitude(...)100%11100%
File 12: MultiplyHullCapsuleMagnitude(...)100%11100%
File 12: GetHullCapsuleMagnitude(...)100%11100%
File 12: GetHullCapsuleMagnitude(...)100%11100%
File 12: GetHullCapsuleMagnitude(...)100%11100%
File 12: GetHullCapsuleMagnitude(...)100%11100%
File 12: CompareHullCapsuleSignedMagnitudes(...)100%88100%
File 12: CombineHullCapsuleSignedMagnitudes(...)100%1616100%
File 13: ContainsConvexHullPoint(...)100%1010100%
File 13: TryGetConvexHullContact(...)100%44100%
File 13: TryGetConvexHullPenetration(...)100%11100%
File 13: TryGetConvexHullPenetration(...)100%4444100%
File 13: VisitConvexHullContacts(...)100%140140100%
File 13: TryKeepHullFaceAxes(...)100%1616100%
File 13: GetLocalHullFaceAxis(...)100%11100%
File 13: IsFirstHullEdgeDirection(...)100%88100%
File 13: TryKeepHullPairAxis(...)100%2222100%
File 13: GetHullProjectionInterval(...)100%22100%
File 13: GetHullEdge(...)100%11100%
File 13: GetHullSupportLocalPoint(...)100%66100%
File 14: .ctor(...)100%11100%
File 14: ToWide()100%11100%
File 14: TryGetConvexPrismContact(...)100%2020100%
File 14: TryKeepConvexPrismAxis(...)100%2222100%
File 14: GetRotatedPlanarOffsetProjection(...)100%11100%
File 14: GetRotatedPlanarEdge(...)100%11100%
File 14: GetLocalAxisSupportPoint(...)100%66100%
File 14: GetPrismSupportOffset(...)100%1010100%
File 14: ShouldNegateCanonicalAxis(...)100%44100%
File 14: IsLexicographicallyEarlier(...)100%44100%
File 14: CrossWithUp(...)100%11100%
File 14: CrossWithPlanarEdge(...)100%11100%
File 15: .ctor(...)100%11100%
File 15: GetAxes(...)100%11100%
File 15: GetLocalSupportPoint(...)100%66100%
File 15: GetBoundsClippedToDomain(...)100%11100%
File 15: Contains(...)100%44100%
File 15: GetClosestPointAnchor(...)100%88100%
File 15: GetNearestFaceNormal(...)100%1212100%
File 15: TryMaterializeLocalPoint(...)100%22100%
File 15: TryMaterializeLocalPoint(...)100%22100%
File 15: TryTransformLocalOffset(...)100%11100%
File 15: TryGetRelativeOffset(...)100%22100%
File 15: TryGetSupportOffset(...)100%11100%
File 15: TryGetSupportDifference(...)100%22100%
File 15: TryGetSupportDifference(...)100%22100%
File 15: GetDirectionProjections(...)100%11100%
File 15: GetPointProjections(...)100%11100%
File 15: IsWithinExtent(...)100%11100%
File 15: GetClampedNumerator(...)100%22100%
File 15: GetSignedExtent(...)100%22100%
File 15: GetExtentNumerator(...)100%11100%
File 15: GetMagnitude(...)100%22100%
File 15: GetMagnitude(...)100%22100%
File 15: GetMagnitude(...)100%22100%
File 15: GetExtentNumerator(...)100%11100%
File 15: GetClippedEndpoint(...)100%1414100%
File 15: GetAxis(...)100%22100%
File 15: CompareSigned(...)100%44100%
File 15: CompareSigned(...)100%11100%
File 15: ToSigned576(...)100%11100%
File 16: TryGetCenteredCylinderContact(...)100%11100%
File 16: TryGetCenteredCylinderContact(...)100%1818100%
File 16: GetCylinderCapFace(...)100%3030100%
File 17: .ctor(...)100%11100%
File 17: Equals(...)100%22100%
File 17: .cctor()100%11100%
File 17: GetCenteredCylinderCapFaceContacts(...)100%44100%
File 17: GetRationalLocalPoint(...)100%11100%
File 17: GetFaceCoordinates(...)100%44100%
File 17: KeepCapExtreme(...)100%1212100%
File 17: GetSignedFaceExtent(...)100%66100%
File 17: GetLocalCoordinates(...)100%44100%
File 17: ClampToExtent(...)100%44100%
File 18: DoesCenteredCylinderPenetrateBox(...)100%1818100%
File 18: DoesCenteredCylinderPenetrateTriangle(...)100%11100%
File 18: DoesCenteredCylinderPenetrateConvexHull(...)100%88100%
File 18: DoesCenteredCylinderPenetrateTriangle(...)100%22100%
File 18: DoesCenteredCylinderPenetrateConvexHull(...)100%1010100%
File 18: IsStrictCylinderBoxCoordinateInside(...)100%11100%
File 18: IsCylinderCenterStrictlyInsideHull(...)100%1212100%
File 18: ContainsConvexHullPoint(...)100%1414100%
File 18: DoesCylinderTrianglePenetrate(...)100%2222100%
File 18: IsCylinderAxisInsideTriangleProjection(...)100%1818100%
File 18: GetCylinderRadialCross(...)100%11100%
File 18: DoesCylinderClippedEdgePenetrate(...)100%88100%
File 18: GetCylinderClippedEndpoint(...)100%44100%
File 18: GetCylinderRadialPoint(...)100%11100%
File 18: GetCylinderPlaneIntersection(...)100%22100%
File 18: DoesCylinderCapSectionPenetrate(...)100%44100%
File 18: AddCylinderPlaneIntersection(...)100%1010100%
File 18: IsCylinderRadialPointInside(...)100%11100%
File 18: IsCylinderRadialSegmentInside(...)100%1212100%
File 19: GetRationalLocalPoint(...)100%11100%
File 19: TryMaterializeCoordinate(...)100%11100%
File 19: TryMaterializeCoordinate(...)100%11100%
File 19: TryMaterializeRationalOffset(...)100%22100%
File 19: TryMaterializeSupportDifferenceCoordinate(...)100%11100%
File 19: TryMaterializeBoxSupportDifferenceCoordinate(...)100%11100%
File 19: TryGetRelativeOffsetCoordinate(...)100%11100%
File 20: TryGetRationalSegmentSweepDistance(...)100%2020100%
File 20: CompareRationalSegmentLineAt(...)100%11100%
File 20: TryGetExactRationalSegmentWitness(...)100%88100%
File 20: RoundRationalSegmentCoordinate(...)100%11100%
File 20: GetEdgeSquaredMagnitude(...)100%11100%
File 20: GetCrossMagnitude(...)100%11100%
File 20: GetCrossMagnitude(...)100%11100%
File 20: GetCrossMagnitude(...)100%11100%
File 20: GetDotMagnitude(...)100%11100%
File 20: CombineSignedMagnitudes(...)100%1010100%
File 20: CopyMagnitude(...)100%11100%
File 21: .ctor(...)100%11100%
File 21: TryGetRayIntersectionInterval(...)100%66100%
File 21: TryClipRayAxis(...)100%1414100%
File 21: NormalizeRayBound(...)100%22100%
File 21: CompareRayBounds(...)100%11100%
File 21: RoundRayBound(...)100%11100%
File 22: GetRelativeRotatedBoundsClippedToDomain(...)100%11100%
File 22: GetRelativeBoundsCoordinate(...)100%11100%
File 22: GetRelativeEndpointNumerator(...)100%11100%
File 22: SelectEndpoint(...)100%22100%
File 22: GetRelativeEndpointClippedToDomain(...)100%1212100%
File 23: .ctor(...)100%11100%
File 23: DoCenteredRigidCapsulesOverlap(...)100%2828100%
File 23: ClampUnitRatio(...)100%44100%
File 23: SetRigidSegmentRatio(...)100%11100%
File 23: SetRigidSegmentProjectionRatio(...)100%11100%
File 23: IsRigidLinePairWithinRadius(...)100%22100%
File 23: IsRigidPointLineWithinRadius(...)100%22100%
File 23: IsRigidPointWithinRadius(...)100%22100%
File 23: GetRadiusThreshold(...)100%22100%
File 23: GetSquaredMagnitude(...)100%11100%
File 23: GetTripleProductMagnitude(...)100%11100%
File 23: GetProductDifference(...)100%11100%
File 23: GetProductDifference(...)100%11100%
File 23: DoubleMagnitude(...)100%22100%
File 23: DoubleProduct(...)100%11100%
File 23: GetRigidSegmentLowerDifference(...)100%11100%
File 23: GetRigidSegmentLowerDifference(...)100%11100%
File 23: AddRigidSegmentDisplacement(...)100%11100%
File 23: SubtractRigidSegmentDisplacement(...)100%11100%
File 23: Dot(...)100%11100%
File 23: Dot(...)100%11100%
File 24: .ctor(...)100%11100%
File 24: .ctor(...)100%11100%
File 24: TryGetRigidCapsuleDistanceInterval(...)100%44100%
File 24: TryGetRigidCylinderDistanceInterval(...)100%44100%
File 24: TryGetRigidConeDistanceInterval(...)100%44100%
File 24: GetRigidLocalRay(...)100%11100%
File 24: TryGetCardinalLocalYAxis(...)100%2424100%
File 24: ScaleRigidDimension(...)100%11100%
File 24: ScaleRigidDimensionSum(...)100%11100%
File 24: ScaleRigidDimensionWithDoubleExpansion(...)100%11100%
File 24: NarrowRigidQueryValue(...)100%11100%
File 24: GetRadialPolynomial(...)100%11100%
File 24: MergeRigidCapsuleCap(...)100%22100%
File 24: GetSpherePolynomial(...)100%11100%
File 24: GetConePolynomial(...)100%11100%
File 24: TryGetCenteredAxialBounds(...)100%11100%
File 24: TryGetLinearBounds(...)100%1414100%
File 24: NormalizeRigidBound(...)100%22100%
File 24: CompareRigidBounds(...)100%11100%
File 24: IsCylinderContained(...)100%1010100%
File 24: IsCapsuleContained(...)100%88100%
File 24: IsConeContained(...)100%1010100%
File 24: EvaluatePolynomialAtOne(...)100%11100%
File 24: AddRigidSquares(...)100%11100%
File 24: AddRigidSquares(...)100%11100%
File 24: AddRigidProducts(...)100%11100%
File 24: AddRigidProducts(...)100%11100%
File 24: MergeRigidInterval(...)100%88100%
File 25: get_BoxHullTriangles()100%11100%
File 25: get_BoxHullEdges()100%11100%
File 25: GetBoxHullVertices(...)100%88100%
File 25: TryGetConvexHullContact(...)100%22100%
File 25: TryGetConvexHullContact(...)100%1616100%
File 25: VisitConvexHullContacts(...)100%11100%
File 25: VisitConvexHullContacts(...)100%4040100%
File 25: VisitProjectedHullRectangleContacts(...)100%102102100%
File 25: VisitScaledHullSide(...)100%9090100%
File 25: HasScaledHullEdge(...)100%1010100%
File 25: GetScaledHullSupport(...)100%66100%
File 25: IsScaledHullSupport(...)100%11100%
File 25: IntersectScaledHullInterval(...)100%66100%
File 25: TryGetConvexHullPenetration(...)100%11100%
File 25: TryGetConvexHullPenetration(...)100%2020100%
File 25: TryKeepScaledHullFaceAxes(...)100%2424100%
File 25: TryKeepScaledHullAxis(...)100%1212100%
File 25: GetScaledHullProjection(...)100%66100%
File 25: ProjectScaledHullPoint(...)100%11100%
File 26: DoesSpherePenetrate(...)100%1212100%
File 26: TryGetSweptSphereIntersectionDistance(...)100%11100%
File 26: TryGetSphereContact(...)100%44100%
File 26: TryGetContainedSphereContact(...)100%2626100%
File 26: GetSphereSurfaceAnchor(...)100%22100%
File 26: GetProjectionNumerator(...)100%11100%
File 26: GetRationalLocalOffsetNumerators(...)100%11100%
File 26: GetRationalLocalOffsetNumerator(...)100%11100%
File 26: GetOriginRelativeNumerator(...)100%11100%
File 26: SumSquares(...)100%11100%
File 26: GetRoundedRadialDepth(...)100%11100%
File 26: CorrectRoundedRadialDepth(...)100%22100%
File 26: GetLowerMidpointAdjustment(...)100%11100%
File 26: GetUpperMidpointAdjustment(...)100%11100%
File 26: CompareRadialDepthToTwiceRaw(...)100%11100%
File 27: TryGetTriangleContact(...)100%1616100%
File 27: TryKeepTriangleEdgeAxes(...)100%44100%
File 27: TryKeepTriangleAxis(...)100%1010100%
File 27: GetTriangleSupportLocalPoint(...)100%44100%
File 27: GetTriangleFaceContacts(...)100%1818100%
File 27: GetParallelTriangleFaceAxis(...)100%88100%
File 27: GetDirectionProjection(...)100%11100%
File 27: IsParallel(...)100%11100%
File 28: .ctor(...)100%11100%
File 28: ToSweepPoint(...)100%11100%
File 28: .ctor(...)100%11100%
File 28: TryGetFiniteSlabProjectedCircleSweep(...)100%11100%
File 28: TryGetFiniteSlabProjectedCircleSweep(...)100%11100%
File 28: TryGetFiniteSlabProjectedCircleSweepCore(...)100%1818100%
File 28: TryGetTriangleProjectionInteriorPoint(...)100%1414100%
File 28: TryGetTriangleInteriorLocalCoordinate(...)100%11100%
File 28: GetTriangleSweepVertex(...)100%11100%
File 28: AreSameProjectedPoint(...)100%22100%
File 28: KeepTriangleEdgeSweep(...)100%88100%
File 28: GetClippedTriangleEdgeEndpoint(...)100%66100%
File 28: KeepTrianglePlaneEdgeSweep(...)100%22100%
File 28: TryAddTrianglePlaneIntersection(...)100%1010100%
File 28: GetTrianglePlaneIntersection(...)100%22100%
File 28: GetWeightedLocalPoint(...)100%11100%
File 28: AddUniqueTriangleSweepPoint(...)100%44100%
File 28: KeepTriangleSweepFeature(...)100%88100%
File 28: KeepTriangleSweepCandidate(...)100%66100%
File 28: ScaleReferenceYOffset(...)100%11100%
File 28: GetAbsoluteReferenceYOffset(...)100%22100%
File 28: TryGetFiniteSlabProjectedCircleSweep(...)100%3030100%
File 28: AffineSlabField(...)100%11100%
File 28: TryGetAffineSlabSweepInterior(...)100%1616100%
File 28: KeepAffineSlabSweepFeature(...)100%7878100%
File 28: ContainsAffineSlabSweepFace(...)100%44100%
File 28: ReduceAffineSlabDirection(...)100%22100%
File 28: AffineSlabDifference(...)100%11100%
File 28: AffineSlabDot(...)100%11100%
File 28: AffineSlabCross(...)100%11100%
File 28: AffineSlabNegate(...)100%11100%
File 28: AffineSlabProduct(...)100%11100%
File 29: TryGetTrianglePrismContact(...)100%2020100%
File 29: 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) =>
 136621        WideArithmetic.AddSigned576(
 136622            WideArithmetic.AddSigned576(
 136623                WideArithmetic.MultiplySigned576(
 136624                    GetMagnitude(WideRigidProjection.GetBasisAxisProjection(
 136625                        axis,
 136626                        basis.Xx,
 136627                        basis.Xy,
 136628                        basis.Xz)),
 136629                    Signed192.Raw(halfExtents.X)),
 136630                WideArithmetic.MultiplySigned576(
 136631                    GetMagnitude(WideRigidProjection.GetBasisAxisProjection(
 136632                        axis,
 136633                        basis.Yx,
 136634                        basis.Yy,
 136635                        basis.Yz)),
 136636                    Signed192.Raw(halfExtents.Y))),
 136637            WideArithmetic.MultiplySigned576(
 136638                GetMagnitude(WideRigidProjection.GetBasisAxisProjection(
 136639                    axis,
 136640                    basis.Zx,
 136641                    basis.Zy,
 136642                    basis.Zz)),
 136643                Signed192.Raw(halfExtents.Z)));
 44
 45    private static Signed576 GetLocalBoxProjectionRadiusNumerator(
 46        in WideAxis3 axis,
 47        Vector3d halfExtents) =>
 562748        WideArithmetic.AddSigned576(
 562749            WideArithmetic.AddSigned576(
 562750                WideArithmetic.MultiplySigned576(
 562751                    Signed576.ExtendValue(GetMagnitude(axis.X)),
 562752                    halfExtents.X.m_rawValue),
 562753                WideArithmetic.MultiplySigned576(
 562754                    Signed576.ExtendValue(GetMagnitude(axis.Y)),
 562755                    halfExtents.Y.m_rawValue)),
 562756            WideArithmetic.MultiplySigned576(
 562757                Signed576.ExtendValue(GetMagnitude(axis.Z)),
 562758                halfExtents.Z.m_rawValue));
 59
 60    internal static int GetRotatedLocalProjectionSign(
 61        FixedQuaternion rotation,
 62        Vector3d localDirection,
 63        Vector3d worldDirection)
 64    {
 323765        WideRationalBasis3d basis = new(rotation);
 323766        WideAxis3 rotated = WideRigidProjection.TransformLocalAxis(
 323767            basis,
 323768            Signed192.Raw(localDirection.X),
 323769            Signed192.Raw(localDirection.Y),
 323770            Signed192.Raw(localDirection.Z));
 323771        return WideArithmetic.AddSigned576(
 323772            WideArithmetic.AddSigned576(
 323773                WideArithmetic.MultiplySigned320(
 323774                    rotated.X,
 323775                    Signed320.ExtendValue(
 323776                        Signed192.Raw(worldDirection.X))),
 323777                WideArithmetic.MultiplySigned320(
 323778                    rotated.Y,
 323779                    Signed320.ExtendValue(
 323780                        Signed192.Raw(worldDirection.Y)))),
 323781            WideArithmetic.MultiplySigned320(
 323782                rotated.Z,
 323783                Signed320.ExtendValue(
 323784                    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    {
 680695        WideRationalBasis3d basis = new(rotation);
 680696        WideAxis3 rotated = WideRigidProjection.TransformLocalAxis(
 680697            basis,
 680698            Signed192.Raw(localDirection.X),
 680699            Signed192.Raw(localDirection.Y),
 6806100            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.
 6806103        _ = Signed192.TryNarrowSigned(rotated.X, out x);
 6806104        _ = Signed192.TryNarrowSigned(rotated.Y, out y);
 6806105        _ = Signed192.TryNarrowSigned(rotated.Z, out z);
 6806106        rotationDenominator = basis.Denominator;
 6806107    }
 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    {
 6152118        WideRationalBasis3d basis = new(rotation);
 6152119        GetRelativeLocalPointNumerators(
 6152120            point,
 6152121            origin,
 6152122            basis,
 6152123            out x,
 6152124            out y,
 6152125            out z);
 6152126        rotationDenominator = basis.Denominator;
 6152127    }
 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    {
 17325137        GetPointProjections(
 17325138            point,
 17325139            origin,
 17325140            basis,
 17325141            out Signed320 wideX,
 17325142            out Signed320 wideY,
 17325143            out Signed320 wideZ);
 144        // A full raw-domain point difference projected through a normalized
 145        // quaternion basis remains below the Signed192 limit.
 17325146        x = Signed192.NarrowProven(wideX);
 17325147        y = Signed192.NarrowProven(wideY);
 17325148        z = Signed192.NarrowProven(wideZ);
 17325149    }
 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    internal static bool DoesCenteredCapsulePenetrate(
 18        Vector3d center, FixedQuaternion orientation, Vector3d halfExtents,
 19        Vector3d capsuleCenter, FixedQuaternion capsuleRotation,
 20        Vector3d localCapsuleAxisDirection, Fixed64 capsuleAxisLength, Fixed64 capsuleRadius)
 21    {
 11422        if (capsuleAxisLength == Fixed64.Zero)
 8623            return DoesSpherePenetrate(center, orientation, halfExtents, capsuleCenter, capsuleRadius);
 24
 2825        WideRationalBasis3d boxBasis = new(orientation);
 2826        WideRationalBasis3d capsuleBasis = new(capsuleRotation);
 2827        WideRationalBasis3d relativeBasis = WideRationalBasis3d.CreateRelative(boxBasis, capsuleBasis);
 2828        WideAxis3 capsuleAxis = WideRigidProjection.TransformLocalAxis(
 2829            relativeBasis, Signed192.Raw(localCapsuleAxisDirection.X),
 2830            Signed192.Raw(localCapsuleAxisDirection.Y), Signed192.Raw(localCapsuleAxisDirection.Z));
 2831        return TryGetCenteredCapsulePenetration(
 2832                center, halfExtents, capsuleCenter, boxBasis, capsuleBasis.Denominator,
 2833                capsuleAxis, relativeBasis.Denominator,
 2834                GetScaledCapsuleAxisSquared(localCapsuleAxisDirection, capsuleBasis.Denominator),
 2835                GetCapsuleCenterAxisProjection(boxBasis.Denominator, center, capsuleCenter,
 2836                    capsuleBasis, localCapsuleAxisDirection),
 2837                capsuleAxisLength, capsuleRadius, out _, out _, strict: true);
 38    }
 39
 40    #region Nested Types
 41
 42    private readonly struct CapsulePenetration
 43    {
 44        internal readonly CapsuleAxis3 Axis;
 45        internal readonly bool Negate;
 46        internal readonly Signed704 WideRational;
 47        internal readonly Signed832 WideSquaredAxisLength;
 48        internal readonly int FeatureRank;
 49
 50        internal CapsulePenetration(
 51            CapsuleAxis3 axis,
 52            bool negate,
 53            Signed704 rational,
 54            Signed832 squaredAxisLength,
 55            int featureRank)
 56        {
 309257            Axis = axis;
 309258            Negate = negate;
 309259            WideRational = rational;
 309260            WideSquaredAxisLength = squaredAxisLength;
 309261            FeatureRank = featureRank;
 309262            HasValue = true;
 309263        }
 64
 65        internal bool HasValue { get; }
 66    }
 67
 68    #endregion
 69
 70    internal static bool TryGetCenteredCapsuleContact(
 71        Vector3d center,
 72        FixedQuaternion orientation,
 73        Vector3d halfExtents,
 74        Vector3d capsuleCenter,
 75        FixedQuaternion capsuleRotation,
 76        Vector3d localCapsuleAxisDirection,
 77        Fixed64 capsuleAxisLength,
 78        Fixed64 capsuleRadius,
 79        out FixedContactAnchors contact)
 80    {
 23781        WideRationalBasis3d boxBasis = new(orientation);
 23782        WideRationalBasis3d capsuleBasis = new(capsuleRotation);
 23783        WideRationalBasis3d relativeBasis =
 23784            WideRationalBasis3d.CreateRelative(boxBasis, capsuleBasis);
 23785        WideAxis3 capsuleAxis = WideRigidProjection.TransformLocalAxis(
 23786            relativeBasis,
 23787            Signed192.Raw(localCapsuleAxisDirection.X),
 23788            Signed192.Raw(localCapsuleAxisDirection.Y),
 23789            Signed192.Raw(localCapsuleAxisDirection.Z));
 23790        if (!TryGetCenteredCapsulePenetration(
 23791                center,
 23792                halfExtents,
 23793                capsuleCenter,
 23794                boxBasis,
 23795                capsuleBasis.Denominator,
 23796                capsuleAxis,
 23797                relativeBasis.Denominator,
 23798                GetScaledCapsuleAxisSquared(
 23799                    localCapsuleAxisDirection,
 237100                    capsuleBasis.Denominator),
 237101                GetCapsuleCenterAxisProjection(
 237102                    boxBasis.Denominator,
 237103                    center,
 237104                    capsuleCenter,
 237105                    capsuleBasis,
 237106                    localCapsuleAxisDirection),
 237107                capsuleAxisLength,
 237108                capsuleRadius,
 237109                out Signed192 commonDenominator,
 237110                out CapsulePenetration best))
 111        {
 44112            contact = default;
 44113            return false;
 114        }
 115
 193116        GetWideCapsuleDepth(
 193117            best.WideRational,
 193118            best.WideSquaredAxisLength,
 193119            commonDenominator,
 193120            capsuleRadius,
 193121            out Fixed64 depth,
 193122            out bool depthIsClamped);
 193123        CapsuleAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 193124        Signed576 worldX = Signed576.NarrowValue(
 193125            GetCapsuleBasisProjection(
 193126                orientedAxis,
 193127                boxBasis.Xx,
 193128                boxBasis.Yx,
 193129                boxBasis.Zx));
 193130        Signed576 worldY = Signed576.NarrowValue(
 193131            GetCapsuleBasisProjection(
 193132                orientedAxis,
 193133                boxBasis.Xy,
 193134                boxBasis.Yy,
 193135                boxBasis.Zy));
 193136        Signed576 worldZ = Signed576.NarrowValue(
 193137            GetCapsuleBasisProjection(
 193138                orientedAxis,
 193139                boxBasis.Xz,
 193140                boxBasis.Yz,
 193141                boxBasis.Zz));
 193142        Vector3d normal = WideNormalization.GetNormalized(
 193143            worldX,
 193144            worldY,
 193145            worldZ);
 193146        int axialSign = -GetCapsuleAxisProjection(orientedAxis, capsuleAxis).Sign;
 193147        FixedPointAnchor capsuleAnchor = GetMatchedCapsuleSupportAnchor(
 193148            center, capsuleCenter, capsuleRotation, localCapsuleAxisDirection,
 193149            capsuleAxisLength, capsuleRadius, normal, axialSign);
 193150        Vector3d boxLocalPoint = GetMatchedBoxSupportLocalPoint(
 193151            halfExtents, center, orientation, capsuleAnchor,
 193152            orientedAxis.X, orientedAxis.Y, orientedAxis.Z, out bool needsCoreMatch);
 193153        FixedPointAnchor boxAnchor = new(center, orientation, boxLocalPoint);
 193154        int freeCount = (orientedAxis.X.IsZero ? 1 : 0)
 193155            + (orientedAxis.Y.IsZero ? 1 : 0) + (orientedAxis.Z.IsZero ? 1 : 0);
 156        // Only a face's two free coordinates certify its entire footprint.
 157        // Edge/vertex constraints require the paired finite-core relation.
 193158        if (axialSign == 0 && capsuleAxisLength > Fixed64.Zero && (needsCoreMatch || freeCount < 2))
 159        {
 160            // Compose only the winning support rectangle/edge/vertex; the shared
 161            // finite-core clip does not repeat SAT or materialize world points.
 55162            Span<Vector3d> support = stackalloc Vector3d[4];
 55163            Span<Signed576> projections = stackalloc Signed576[3]
 55164                { orientedAxis.X, orientedAxis.Y, orientedAxis.Z };
 55165            int count = 1 << freeCount;
 330166            for (int corner = 0; corner < count; corner++)
 167            {
 110168                Vector3d point = default;
 110169                int freeAxis = 0;
 880170                for (int axis = 0; axis < 3; axis++)
 171                {
 330172                    bool positive = projections[axis].IsZero
 330173                        ? (corner & (1 << freeAxis++)) != 0 : projections[axis].Sign > 0;
 330174                    point[axis] = positive ? halfExtents[axis] : -halfExtents[axis];
 175                }
 110176                support[corner] = point;
 177            }
 55178            ReadOnlySpan<int> triangles = stackalloc int[6] { 0, 1, 3, 0, 3, 2 };
 55179            ReadOnlySpan<int> edges = stackalloc int[8] { 0, 1, 1, 3, 3, 2, 2, 0 };
 55180            boxAnchor = GetMatchedHullCapsuleSupportAnchor(center, orientation, boxBasis,
 55181                support[..count], count == 4 ? triangles : ReadOnlySpan<int>.Empty,
 55182                count == 4 ? edges : count == 2 ? edges[..2] : ReadOnlySpan<int>.Empty,
 55183                new CapsuleAxis3(worldX, worldY, worldZ), capsuleAnchor,
 55184                capsuleCenter, capsuleRotation, localCapsuleAxisDirection,
 55185                capsuleAxisLength, capsuleRadius, normal, true, out capsuleAnchor);
 186        }
 193187        contact = new FixedContactAnchors(
 193188            boxAnchor,
 193189            capsuleAnchor,
 193190            normal,
 193191            depth,
 193192            depthIsClamped);
 193193        return true;
 194    }
 195
 196    /// <summary>
 197    /// Returns whether the exact SAT admits a possible box/capsule overlap.
 198    /// Unrepresentable edge-axis witnesses are conservatively treated as
 199    /// inconclusive rather than as separation.
 200    /// </summary>
 201    internal static bool CanOverlapCenteredCapsule(
 202        Vector3d center,
 203        FixedQuaternion orientation,
 204        Vector3d halfExtents,
 205        Vector3d capsuleCenter,
 206        Vector3d capsuleAxisDirection,
 207        Fixed64 capsuleAxisLength,
 208        Fixed64 capsuleRadius)
 209    {
 3210        WideRationalBasis3d boxBasis = new(orientation);
 3211        GetDirectionProjections(
 3212            capsuleAxisDirection,
 3213            boxBasis,
 3214            out Signed320 capsuleAxisX,
 3215            out Signed320 capsuleAxisY,
 3216            out Signed320 capsuleAxisZ);
 3217        var authoredCapsuleAxis = new WideAxis3(
 3218            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.X)),
 3219            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.Y)),
 3220            Signed320.ExtendValue(Signed192.Raw(capsuleAxisDirection.Z)));
 3221        return TryGetCenteredCapsulePenetration(
 3222            center,
 3223            halfExtents,
 3224            capsuleCenter,
 3225            boxBasis,
 3226            Signed192.Signed(1L),
 3227            new WideAxis3(
 3228                capsuleAxisX,
 3229                capsuleAxisY,
 3230                capsuleAxisZ),
 3231            boxBasis.Denominator,
 3232            authoredCapsuleAxis.SquaredLength,
 3233            WideArithmetic.MultiplySigned576(
 3234                WideRigidProjection.GetWorldOriginDifferenceProjection(
 3235                    capsuleCenter,
 3236                    center,
 3237                    authoredCapsuleAxis),
 3238                boxBasis.Denominator),
 3239            capsuleAxisLength,
 3240            capsuleRadius,
 3241            out _,
 3242            out _);
 243    }
 244
 245    internal static bool CanOverlapCenteredCapsule(
 246        Vector3d center,
 247        FixedQuaternion orientation,
 248        Vector3d halfExtents,
 249        Vector3d capsuleCenter,
 250        FixedQuaternion capsuleRotation,
 251        Vector3d localCapsuleAxisDirection,
 252        Fixed64 capsuleAxisLength,
 253        Fixed64 capsuleRadius)
 254    {
 1182255        WideRationalBasis3d boxBasis = new(orientation);
 1182256        WideRationalBasis3d capsuleBasis = new(capsuleRotation);
 1182257        WideRationalBasis3d relativeBasis =
 1182258            WideRationalBasis3d.CreateRelative(boxBasis, capsuleBasis);
 1182259        WideAxis3 capsuleAxis = WideRigidProjection.TransformLocalAxis(
 1182260            relativeBasis,
 1182261            Signed192.Raw(localCapsuleAxisDirection.X),
 1182262            Signed192.Raw(localCapsuleAxisDirection.Y),
 1182263            Signed192.Raw(localCapsuleAxisDirection.Z));
 1182264        return TryGetCenteredCapsulePenetration(
 1182265            center,
 1182266            halfExtents,
 1182267            capsuleCenter,
 1182268            boxBasis,
 1182269            capsuleBasis.Denominator,
 1182270            capsuleAxis,
 1182271            relativeBasis.Denominator,
 1182272            GetScaledCapsuleAxisSquared(
 1182273                localCapsuleAxisDirection,
 1182274                capsuleBasis.Denominator),
 1182275            GetCapsuleCenterAxisProjection(
 1182276                boxBasis.Denominator,
 1182277                center,
 1182278                capsuleCenter,
 1182279                capsuleBasis,
 1182280                localCapsuleAxisDirection),
 1182281            capsuleAxisLength,
 1182282            capsuleRadius,
 1182283            out _,
 1182284            out _);
 285    }
 286
 287    private static bool TryGetCenteredCapsulePenetration(
 288        Vector3d boxCenter,
 289        Vector3d halfExtents,
 290        Vector3d capsuleCenter,
 291        in WideRationalBasis3d boxBasis,
 292        Signed192 translationScale,
 293        in WideAxis3 capsuleAxis,
 294        Signed192 capsuleAxisDenominator,
 295        Signed576 capsuleAxisSquared,
 296        Signed576 capsuleCenterAxisProjection,
 297        Fixed64 capsuleAxisLength,
 298        Fixed64 capsuleRadius,
 299        out Signed192 commonDenominator,
 300        out CapsulePenetration best,
 301        bool strict = false)
 302    {
 1450303        Signed320 commonDenominatorWide = WideArithmetic.MultiplySigned192(
 1450304            capsuleAxisDenominator,
 1450305            Signed192.Raw(Fixed64.Two));
 1450306        commonDenominator = Signed192.NarrowProven(commonDenominatorWide);
 1450307        GetRelativeLocalPointNumerators(
 1450308            capsuleCenter,
 1450309            boxCenter,
 1450310            boxBasis,
 1450311            out Signed192 translationX,
 1450312            out Signed192 translationY,
 1450313            out Signed192 translationZ);
 1450314        var translation = new WideAxis3(
 1450315            Signed320.ExtendValue(translationX),
 1450316            Signed320.ExtendValue(translationY),
 1450317            Signed320.ExtendValue(translationZ));
 1450318        Signed320 centerScale = WideArithmetic.MultiplySigned192(
 1450319            translationScale,
 1450320            Signed192.Raw(Fixed64.Two));
 1450321        Signed320 axialScale = Signed320.ExtendValue(
 1450322            Signed192.Raw(capsuleAxisLength));
 1450323        var twiceTranslation = new WideAxis3(
 1450324            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 1450325                translation.X,
 1450326                centerScale)),
 1450327            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 1450328                translation.Y,
 1450329                centerScale)),
 1450330            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 1450331                translation.Z,
 1450332                centerScale)));
 1450333        var scaledExtents = new WideAxis3(
 1450334            WideArithmetic.MultiplySigned192(
 1450335                Signed192.Raw(halfExtents.X),
 1450336                commonDenominator),
 1450337            WideArithmetic.MultiplySigned192(
 1450338                Signed192.Raw(halfExtents.Y),
 1450339                commonDenominator),
 1450340            WideArithmetic.MultiplySigned192(
 1450341                Signed192.Raw(halfExtents.Z),
 1450342                commonDenominator));
 1450343        Signed704 vertexCapBound =
 1450344            WideArithmetic.MultiplySigned576ToSigned704(
 1450345                capsuleAxisSquared,
 1450346                WideArithmetic.MultiplySigned192(
 1450347                    boxBasis.Denominator,
 1450348                    Signed192.Raw(capsuleAxisLength)));
 1450349        Signed320 unit = Signed320.One;
 1450350        Span<WideAxis3> boxAxes = stackalloc WideAxis3[3]
 1450351        {
 1450352            new(default, default, unit),
 1450353            new(default, unit, default),
 1450354            new(unit, default, default),
 1450355        };
 1450356        best = default;
 11390357        for (int index = 0; index < boxAxes.Length; index++)
 358        {
 4287359            if (!TryKeepCapsuleAxis(
 4287360                    ToCapsuleAxis(boxAxes[index]),
 4287361                    scaledExtents,
 4287362                    twiceTranslation,
 4287363                    commonDenominator,
 4287364                    capsuleAxis,
 4287365                    axialScale,
 4287366                    capsuleRadius,
 4287367                    0,
 4287368                    ref best,
 4287369                    strict)
 4287370                || !TryKeepCapsuleAxis(
 4287371                    ToCapsuleAxis(WideAxis3.Cross(
 4287372                        boxAxes[index],
 4287373                        capsuleAxis)),
 4287374                    scaledExtents,
 4287375                    twiceTranslation,
 4287376                    commonDenominator,
 4287377                    capsuleAxis,
 4287378                    axialScale,
 4287379                    capsuleRadius,
 4287380                    1,
 4287381                    ref best,
 4287382                    strict))
 383            {
 42384                return false;
 385            }
 386        }
 387
 1408388        for (int vertexIndex = 0;
 12588389            vertexIndex < FixedOrientedBox.CornerCount;
 11180390            vertexIndex++)
 391        {
 11194392            Vector3d localVertex = new(
 11194393                (vertexIndex & 1) == 0
 11194394                    ? -halfExtents.X
 11194395                    : halfExtents.X,
 11194396                (vertexIndex & 2) == 0
 11194397                    ? -halfExtents.Y
 11194398                    : halfExtents.Y,
 11194399                (vertexIndex & 4) == 0
 11194400                    ? -halfExtents.Z
 11194401                    : halfExtents.Z);
 11194402            if (!TryKeepCapsuleAxis(
 11194403                    GetLocalVertexToCapsuleAxis(
 11194404                        translation,
 11194405                        boxBasis.Denominator,
 11194406                        localVertex,
 11194407                        capsuleAxis,
 11194408                        capsuleAxisSquared,
 11194409                        capsuleCenterAxisProjection,
 11194410                        centerScale,
 11194411                        axialScale,
 11194412                        vertexCapBound),
 11194413                    scaledExtents,
 11194414                    twiceTranslation,
 11194415                    commonDenominator,
 11194416                    capsuleAxis,
 11194417                    axialScale,
 11194418                    capsuleRadius,
 11194419                    1,
 11194420                    ref best,
 11194421                    strict))
 422            {
 14423                return false;
 424            }
 425        }
 426
 11146427        for (int edgeAxisIndex = 0; edgeAxisIndex < 3; edgeAxisIndex++)
 428        {
 25080429            for (int firstSign = -1; firstSign <= 1; firstSign += 2)
 430            {
 8361431                for (int secondSign = -1;
 25077432                    secondSign <= 1;
 16716433                    secondSign += 2)
 434                {
 16719435                    Vector3d localEdgeCenter = GetLocalEdgeCenter(
 16719436                        halfExtents,
 16719437                        edgeAxisIndex,
 16719438                        firstSign,
 16719439                        secondSign);
 16719440                    WideAxis3 edgeDifference =
 16719441                        GetLocalPointToCapsuleCenterAxis(
 16719442                            translation,
 16719443                            boxBasis.Denominator,
 16719444                            localEdgeCenter);
 16719445                    Signed320 edgeBound = edgeAxisIndex switch
 16719446                    {
 5576447                        0 => scaledExtents.X,
 5576448                        1 => scaledExtents.Y,
 5567449                        _ => scaledExtents.Z,
 16719450                    };
 16719451                    for (int endpointSign = -1;
 50151452                        endpointSign <= 1;
 33432453                        endpointSign += 2)
 454                    {
 33435455                        if (!TryKeepCapsuleAxis(
 33435456                                GetCapsuleEndpointToBoxEdgeAxis(
 33435457                                    edgeDifference,
 33435458                                    centerScale,
 33435459                                    axialScale,
 33435460                                    edgeAxisIndex,
 33435461                                    endpointSign,
 33435462                                    capsuleAxis,
 33435463                                    edgeBound),
 33435464                                scaledExtents,
 33435465                                twiceTranslation,
 33435466                                commonDenominator,
 33435467                                capsuleAxis,
 33435468                                axialScale,
 33435469                                capsuleRadius,
 33435470                                1,
 33435471                                ref best,
 33435472                                strict))
 473                        {
 3474                            return false;
 475                        }
 476                    }
 477                }
 478            }
 479        }
 480
 1391481        return true;
 482    }
 483
 484    private static Vector3d GetLocalEdgeCenter(
 485        Vector3d halfExtents,
 486        int edgeAxisIndex,
 487        int firstSign,
 488        int secondSign) =>
 16719489        edgeAxisIndex switch
 16719490        {
 5576491            0 => new Vector3d(
 5576492                Fixed64.Zero,
 5576493                firstSign * halfExtents.Y,
 5576494                secondSign * halfExtents.Z),
 5576495            1 => new Vector3d(
 5576496                firstSign * halfExtents.X,
 5576497                Fixed64.Zero,
 5576498                secondSign * halfExtents.Z),
 5567499            _ => new Vector3d(
 5567500                firstSign * halfExtents.X,
 5567501                secondSign * halfExtents.Y,
 5567502                Fixed64.Zero),
 16719503        };
 504
 505    private static Vector3d GetMatchedBoxSupportLocalPoint(
 506        WideRationalBasis3d basis,
 507        Vector3d halfExtents,
 508        Vector3d boxCenter,
 509        FixedQuaternion boxRotation,
 510        in FixedPointAnchor otherAnchor,
 511        WideAxis3 featureAxis)
 22512        => GetMatchedBoxSupportLocalPoint(
 22513            halfExtents,
 22514            boxCenter,
 22515            boxRotation,
 22516            otherAnchor,
 22517            WideRigidProjection.GetBasisAxisProjection(
 22518                featureAxis,
 22519                basis.Xx,
 22520                basis.Xy,
 22521                basis.Xz),
 22522            WideRigidProjection.GetBasisAxisProjection(
 22523                featureAxis,
 22524                basis.Yx,
 22525                basis.Yy,
 22526                basis.Yz),
 22527            WideRigidProjection.GetBasisAxisProjection(
 22528                featureAxis,
 22529                basis.Zx,
 22530                basis.Zy,
 22531                basis.Zz),
 22532            out _);
 533
 534    private static Vector3d GetMatchedBoxSupportLocalPoint(
 535        Vector3d halfExtents,
 536        Vector3d boxCenter,
 537        FixedQuaternion boxRotation,
 538        in FixedPointAnchor otherAnchor,
 539        Signed576 xProjection,
 540        Signed576 yProjection,
 541        Signed576 zProjection,
 542        out bool needsCoreMatch)
 543    {
 215544        if (!xProjection.IsZero && !yProjection.IsZero && !zProjection.IsZero)
 545        {
 8546            needsCoreMatch = false;
 8547            return new Vector3d(xProjection.Sign > 0 ? halfExtents.X : -halfExtents.X,
 8548                yProjection.Sign > 0 ? halfExtents.Y : -halfExtents.Y,
 8549                zProjection.Sign > 0 ? halfExtents.Z : -halfExtents.Z);
 550        }
 207551        WideTriangleRelations.GetPointLocalNumerators(otherAnchor, boxCenter, boxRotation,
 207552            out Signed576 x, out Signed576 y, out Signed576 z, out Signed320 denominator);
 207553        Fixed64 localX = GetMatchedSupportCoordinate(x, denominator, halfExtents.X,
 207554            xProjection, out bool clipX);
 207555        Fixed64 localY = GetMatchedSupportCoordinate(y, denominator, halfExtents.Y,
 207556            yProjection, out bool clipY);
 207557        Fixed64 localZ = GetMatchedSupportCoordinate(z, denominator, halfExtents.Z,
 207558            zProjection, out bool clipZ);
 207559        needsCoreMatch = clipX || clipY || clipZ;
 207560        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        int axialSign)
 572    {
 193573        if (axialSign != 0)
 574        {
 110575            return WideGeometry.GetCenteredCapsuleSupportAnchor(
 110576                capsuleCenter,
 110577                capsuleRotation,
 110578                localCapsuleAxisDirection,
 110579                capsuleAxisLength,
 110580                capsuleRadius,
 110581                -boxToCapsuleNormal,
 110582                axialSign);
 583        }
 584
 83585        Vector3d localNormal = WideNormalization.GetNormalized(
 83586            capsuleRotation.Inverse().Rotate(-boxToCapsuleNormal));
 83587        return FixedSegment.GetSurfaceAnchorOnCenteredCapsule(
 83588            boxCenter,
 83589            capsuleCenter,
 83590            capsuleRotation,
 83591            localCapsuleAxisDirection,
 83592            capsuleAxisLength,
 83593            capsuleRadius,
 83594            localNormal);
 595    }
 596
 597    private static Fixed64 GetMatchedSupportCoordinate(
 598        Signed576 numerator,
 599        Signed320 denominator,
 600        Fixed64 extent,
 601        Signed576 directionProjection,
 602        out bool needsCoreMatch)
 603    {
 621604        needsCoreMatch = false;
 621605        if (directionProjection.Sign != 0)
 285606            return directionProjection.Sign > 0 ? extent : -extent;
 607
 608        // Certify the exact free-coordinate interval before rounding; projecting
 609        // onto a rounded box basis could hide a clip near a rotated boundary.
 336610        Signed576 magnitude = numerator.Sign < 0
 336611            ? WideArithmetic.SubtractSigned576(default, numerator) : numerator;
 336612        Signed576 limit = WideArithmetic.MultiplySigned320(denominator,
 336613            Signed320.ExtendValue(Signed192.Raw(extent)));
 336614        needsCoreMatch = WideArithmetic.SubtractSigned576(limit, magnitude).Sign < 0;
 336615        if (needsCoreMatch)
 4616            return numerator.Sign > 0 ? extent : -extent;
 617
 618        // The bounded free coordinate is representable; round it once.
 332619        _ = Fixed64.TryGetSignedRawRatio(numerator, Signed576.ExtendValue(denominator), out Fixed64 target);
 332620        return target;
 621    }
 622
 623}

/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        {
 9651728            X = x;
 9651729            Y = y;
 9651730            Z = z;
 9651731        }
 32
 5854133        internal bool IsZero => X.IsZero && Y.IsZero && Z.IsZero;
 34
 35        public static CapsuleAxis3 operator -(CapsuleAxis3 value) =>
 11636            new(
 11637                WideArithmetic.SubtractSigned576(default, value.X),
 11638                WideArithmetic.SubtractSigned576(default, value.Y),
 11639                WideArithmetic.SubtractSigned576(default, value.Z));
 40    }
 41
 42    #endregion
 43
 44    private static WideAxis3 GetCornerToAxisEndpointAxis3D(
 45        Vector3d boxCenter,
 46        Vector3d axisCenter,
 47        WideRationalBasis3d basis,
 48        Vector3d localCorner,
 49        WideAxis3 axis,
 50        Signed192 axisDenominator,
 51        Fixed64 axisLength,
 52        int endpointSign) =>
 391353        new(
 391354            GetCornerToAxisEndpointComponent(
 391355                boxCenter.X,
 391356                axisCenter.X,
 391357                basis.Xx,
 391358                basis.Yx,
 391359                basis.Zx,
 391360                basis.Denominator,
 391361                localCorner,
 391362                axis.X,
 391363                axisDenominator,
 391364                axisLength,
 391365                endpointSign),
 391366            GetCornerToAxisEndpointComponent(
 391367                boxCenter.Y,
 391368                axisCenter.Y,
 391369                basis.Xy,
 391370                basis.Yy,
 391371                basis.Zy,
 391372                basis.Denominator,
 391373                localCorner,
 391374                axis.Y,
 391375                axisDenominator,
 391376                axisLength,
 391377                endpointSign),
 391378            GetCornerToAxisEndpointComponent(
 391379                boxCenter.Z,
 391380                axisCenter.Z,
 391381                basis.Xz,
 391382                basis.Yz,
 391383                basis.Zz,
 391384                basis.Denominator,
 391385                localCorner,
 391386                axis.Z,
 391387                axisDenominator,
 391388                axisLength,
 391389                endpointSign));
 90
 91    private static Signed320 GetCornerToAxisEndpointComponent(
 92        Fixed64 boxCenter,
 93        Fixed64 axisCenter,
 94        Signed192 basisX,
 95        Signed192 basisY,
 96        Signed192 basisZ,
 97        Signed192 basisDenominator,
 98        Vector3d localCorner,
 99        Signed320 axisComponent,
 100        Signed192 axisDenominator,
 101        Fixed64 axisLength,
 102        int endpointSign)
 103    {
 11739104        Signed192 twiceScale = Signed192.Raw(Fixed64.Two);
 11739105        Signed320 corner = GetLocalOffsetNumerator(
 11739106            basisX,
 11739107            basisY,
 11739108            basisZ,
 11739109            localCorner);
 11739110        Signed576 center = WideArithmetic.MultiplySigned576(
 11739111            WideArithmetic.MultiplySigned320(
 11739112                WideArithmetic.MultiplySigned192(
 11739113                    WideArithmetic.SubtractSigned192(
 11739114                        Signed192.Raw(axisCenter),
 11739115                        Signed192.Raw(boxCenter)),
 11739116                    basisDenominator),
 11739117                Signed320.ExtendValue(axisDenominator)),
 11739118            twiceScale);
 11739119        Signed576 endpoint = WideArithmetic.MultiplySigned576(
 11739120            WideArithmetic.MultiplySigned576(
 11739121                Signed576.ExtendValue(axisComponent),
 11739122                Signed192.Signed(
 11739123                    endpointSign * axisLength.m_rawValue)),
 11739124            basisDenominator);
 11739125        Signed576 cornerWide = WideArithmetic.MultiplySigned576(
 11739126            WideArithmetic.MultiplySigned320(
 11739127                corner,
 11739128                Signed320.ExtendValue(axisDenominator)),
 11739129            twiceScale);
 11739130        Signed576 component = WideArithmetic.SubtractSigned576(
 11739131            WideArithmetic.AddSigned576(center, endpoint),
 11739132            cornerWide);
 133        // The center term needs at most 235 signed bits (65-bit delta, two
 134        // 68-bit rigid denominators, and the 34-bit Q32.32 factor for two).
 135        // The endpoint and corner terms are no wider, so the final difference
 136        // fits exactly in Signed320.
 11739137        return new Signed320(
 11739138            component.Word4,
 11739139            component.Word3,
 11739140            component.Word2,
 11739141            component.Word1,
 11739142            component.Word0);
 143    }
 144
 145    private static CapsuleAxis3 GetVertexToCapsuleAxis(
 146        Vector3d boxCenter,
 147        Vector3d capsuleCenter,
 148        WideRationalBasis3d basis,
 149        Vector3d localVertex,
 150        WideAxis3 capsuleAxis,
 151        Signed192 capsuleAxisDenominator,
 152        Fixed64 capsuleAxisLength)
 153    {
 803154        WideAxis3 centerAxis = GetCornerToAxisCenterAxis3D(
 803155            boxCenter,
 803156            capsuleCenter,
 803157            basis,
 803158            localVertex,
 803159            capsuleAxisDenominator);
 803160        Signed576 projection = WideAxis3.Dot(
 803161            centerAxis,
 803162            capsuleAxis);
 803163        Signed576 capsuleSquared = capsuleAxis.SquaredLength;
 803164        Signed576 projectionAtHalfLength = WideArithmetic.MultiplySigned576(
 803165            GetMagnitude(projection),
 803166            Signed192.Raw(Fixed64.Two));
 803167        Signed576 capBound = WideArithmetic.MultiplySigned576(
 803168            WideArithmetic.MultiplySigned576(
 803169                capsuleSquared,
 803170                Signed192.Raw(capsuleAxisLength)),
 803171            basis.Denominator);
 803172        if (WideArithmetic.CompareNonNegative(
 803173                projectionAtHalfLength,
 803174                capBound) >= 0)
 175        {
 584176            int endpointSign = projection.Sign > 0 ? -1 : 1;
 584177            return ToCapsuleAxis(GetCornerToAxisEndpointAxis3D(
 584178                boxCenter,
 584179                capsuleCenter,
 584180                basis,
 584181                localVertex,
 584182                capsuleAxis,
 584183                capsuleAxisDenominator,
 584184                capsuleAxisLength,
 584185                endpointSign));
 186        }
 187
 219188        return GetPerpendicularAxis(
 219189            centerAxis,
 219190            capsuleAxis,
 219191            capsuleSquared,
 219192            projection);
 193    }
 194
 195    private static CapsuleAxis3 GetLocalVertexToCapsuleAxis(
 196        in WideAxis3 translation,
 197        Signed192 boxDenominator,
 198        Vector3d localVertex,
 199        in WideAxis3 capsuleAxis,
 200        in Signed576 capsuleAxisSquared,
 201        in Signed576 capsuleCenterAxisProjection,
 202        in Signed320 centerScale,
 203        in Signed320 axialScale,
 204        in Signed704 capBound)
 205    {
 11194206        WideAxis3 difference = GetLocalPointToCapsuleCenterAxis(
 11194207            translation,
 11194208            boxDenominator,
 11194209            localVertex);
 11194210        var localVertexAxis = new WideAxis3(
 11194211            Signed320.ExtendValue(Signed192.Raw(localVertex.X)),
 11194212            Signed320.ExtendValue(Signed192.Raw(localVertex.Y)),
 11194213            Signed320.ExtendValue(Signed192.Raw(localVertex.Z)));
 11194214        Signed576 projection = WideArithmetic.SubtractSigned576(
 11194215            capsuleCenterAxisProjection,
 11194216            WideAxis3.Dot(localVertexAxis, capsuleAxis));
 11194217        Signed704 projectionAtHalfLength =
 11194218            WideArithmetic.MultiplySigned576ToSigned704(
 11194219                GetMagnitude(projection),
 11194220                centerScale);
 11194221        if (WideArithmetic.CompareNonNegative(
 11194222                projectionAtHalfLength,
 11194223                capBound) >= 0)
 224        {
 6013225            return GetLocalPointToCapsuleEndpointAxis(
 6013226                difference,
 6013227                centerScale,
 6013228                axialScale,
 6013229                capsuleAxis,
 6013230                projection.Sign > 0 ? -1 : 1);
 231        }
 232
 5181233        var scaledDifference = new WideAxis3(
 5181234            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 5181235                difference.X,
 5181236                Signed320.ExtendValue(boxDenominator))),
 5181237            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 5181238                difference.Y,
 5181239                Signed320.ExtendValue(boxDenominator))),
 5181240            Signed320.NarrowValue(WideArithmetic.MultiplySigned320(
 5181241                difference.Z,
 5181242                Signed320.ExtendValue(boxDenominator))));
 5181243        return GetPerpendicularAxis(
 5181244            scaledDifference,
 5181245            capsuleAxis,
 5181246            capsuleAxisSquared,
 5181247            projection);
 248    }
 249
 250    private static CapsuleAxis3 GetCapsuleEndpointToBoxEdgeAxis(
 251        in WideAxis3 edgeDifference,
 252        in Signed320 centerScale,
 253        in Signed320 axialScale,
 254        int edgeAxisIndex,
 255        int endpointSign,
 256        in WideAxis3 capsuleAxis,
 257        in Signed320 edgeBound)
 258    {
 33435259        CapsuleAxis3 endpointAxis = GetLocalPointToCapsuleEndpointAxis(
 33435260            edgeDifference,
 33435261            centerScale,
 33435262            axialScale,
 33435263            capsuleAxis,
 33435264            endpointSign);
 33435265        Signed576 projection = edgeAxisIndex switch
 33435266        {
 11152267            0 => endpointAxis.X,
 11152268            1 => endpointAxis.Y,
 11131269            _ => endpointAxis.Z,
 33435270        };
 33435271        Signed576 wideEdgeBound = Signed576.ExtendValue(edgeBound);
 33435272        Signed576 edgeComponent = default;
 33435273        if (WideArithmetic.CompareNonNegative(
 33435274                GetMagnitude(projection),
 33435275                wideEdgeBound) >= 0)
 276        {
 7808277            edgeComponent = projection.Sign < 0
 7808278                ? WideArithmetic.AddSigned576(projection, wideEdgeBound)
 7808279                : WideArithmetic.SubtractSigned576(projection, wideEdgeBound);
 280        }
 281
 33435282        return edgeAxisIndex switch
 33435283        {
 11152284            0 => new CapsuleAxis3(
 11152285                edgeComponent,
 11152286                endpointAxis.Y,
 11152287                endpointAxis.Z),
 11152288            1 => new CapsuleAxis3(
 11152289                endpointAxis.X,
 11152290                edgeComponent,
 11152291                endpointAxis.Z),
 11131292            _ => new CapsuleAxis3(
 11131293                endpointAxis.X,
 11131294                endpointAxis.Y,
 11131295                edgeComponent),
 33435296        };
 297    }
 298
 299    private static WideAxis3 GetLocalPointToCapsuleCenterAxis(
 300        in WideAxis3 translation,
 301        Signed192 boxDenominator,
 302        Vector3d localPoint) =>
 27913303        new(
 27913304            WideArithmetic.SubtractSigned320(
 27913305                translation.X,
 27913306                WideArithmetic.MultiplySigned192(
 27913307                    Signed192.Raw(localPoint.X),
 27913308                    boxDenominator)),
 27913309            WideArithmetic.SubtractSigned320(
 27913310                translation.Y,
 27913311                WideArithmetic.MultiplySigned192(
 27913312                    Signed192.Raw(localPoint.Y),
 27913313                    boxDenominator)),
 27913314            WideArithmetic.SubtractSigned320(
 27913315                translation.Z,
 27913316                WideArithmetic.MultiplySigned192(
 27913317                    Signed192.Raw(localPoint.Z),
 27913318                    boxDenominator)));
 319
 320    private static CapsuleAxis3 GetLocalPointToCapsuleEndpointAxis(
 321        in WideAxis3 difference,
 322        in Signed320 centerScale,
 323        in Signed320 axialScale,
 324        in WideAxis3 capsuleAxis,
 325        int endpointSign)
 326    {
 39448327        return new CapsuleAxis3(
 39448328            GetLocalEndpointComponent(
 39448329                difference.X,
 39448330                capsuleAxis.X,
 39448331                centerScale,
 39448332                axialScale,
 39448333                endpointSign),
 39448334            GetLocalEndpointComponent(
 39448335                difference.Y,
 39448336                capsuleAxis.Y,
 39448337                centerScale,
 39448338                axialScale,
 39448339                endpointSign),
 39448340            GetLocalEndpointComponent(
 39448341                difference.Z,
 39448342                capsuleAxis.Z,
 39448343                centerScale,
 39448344                axialScale,
 39448345                endpointSign));
 346    }
 347
 348    private static Signed576 GetLocalEndpointComponent(
 349        in Signed320 difference,
 350        in Signed320 axis,
 351        in Signed320 centerScale,
 352        in Signed320 axialScale,
 353        int endpointSign)
 354    {
 118344355        Signed576 center = WideArithmetic.MultiplySigned320(
 118344356            difference,
 118344357            centerScale);
 118344358        Signed576 axial = WideArithmetic.MultiplySigned320(
 118344359            axis,
 118344360            axialScale);
 118344361        return endpointSign < 0
 118344362            ? WideArithmetic.SubtractSigned576(center, axial)
 118344363            : WideArithmetic.AddSigned576(center, axial);
 364    }
 365
 366    private static Signed576 GetScaledCapsuleAxisSquared(
 367        Vector3d localAxis,
 368        Signed192 basisDenominator)
 369    {
 1447370        var rawAxis = new WideAxis3(
 1447371            Signed320.ExtendValue(Signed192.Raw(localAxis.X)),
 1447372            Signed320.ExtendValue(Signed192.Raw(localAxis.Y)),
 1447373            Signed320.ExtendValue(Signed192.Raw(localAxis.Z)));
 1447374        Signed320 denominatorSquared = WideArithmetic.MultiplySigned192(
 1447375            basisDenominator,
 1447376            basisDenominator);
 377        // Rotation preserves length, so |C*u|^2 = Dc^2*|u|^2. A validated
 378        // Q32.32 unit axis and normalized-quaternion denominator keep this
 379        // exact product below 196 bits.
 1447380        return Signed576.NarrowValue(
 1447381            WideArithmetic.MultiplySigned576ToSigned704(
 1447382                rawAxis.SquaredLength,
 1447383                denominatorSquared));
 384    }
 385
 386    private static Signed576 GetCapsuleCenterAxisProjection(
 387        Signed192 boxDenominator,
 388        Vector3d boxCenter,
 389        Vector3d capsuleCenter,
 390        in WideRationalBasis3d capsuleBasis,
 391        Vector3d localCapsuleAxis)
 392    {
 1447393        GetRelativeLocalPointNumerators(
 1447394            capsuleCenter,
 1447395            boxCenter,
 1447396            capsuleBasis,
 1447397            out Signed192 translationX,
 1447398            out Signed192 translationY,
 1447399            out Signed192 translationZ);
 1447400        var capsuleTranslation = new WideAxis3(
 1447401            Signed320.ExtendValue(translationX),
 1447402            Signed320.ExtendValue(translationY),
 1447403            Signed320.ExtendValue(translationZ));
 1447404        var rawAxis = new WideAxis3(
 1447405            Signed320.ExtendValue(Signed192.Raw(localCapsuleAxis.X)),
 1447406            Signed320.ExtendValue(Signed192.Raw(localCapsuleAxis.Y)),
 1447407            Signed320.ExtendValue(Signed192.Raw(localCapsuleAxis.Z)));
 408        // (C^T*delta) dot u = delta dot (C*u). Multiplying by Db gives
 409        // the same reduced scalar as each old world vertex projection,
 410        // without constructing either world vector per vertex.
 1447411        return WideArithmetic.MultiplySigned576(
 1447412            WideAxis3.Dot(capsuleTranslation, rawAxis),
 1447413            boxDenominator);
 414    }
 415
 416    private static WideAxis3 GetCornerToAxisCenterAxis3D(
 417        Vector3d boxCenter,
 418        Vector3d axisCenter,
 419        WideRationalBasis3d basis,
 420        Vector3d localCorner,
 421        Signed192 axisDenominator) =>
 803422        new(
 803423            GetCornerToAxisCenterComponent(
 803424                boxCenter.X,
 803425                axisCenter.X,
 803426                basis.Xx,
 803427                basis.Yx,
 803428                basis.Zx,
 803429                basis.Denominator,
 803430                localCorner,
 803431                axisDenominator),
 803432            GetCornerToAxisCenterComponent(
 803433                boxCenter.Y,
 803434                axisCenter.Y,
 803435                basis.Xy,
 803436                basis.Yy,
 803437                basis.Zy,
 803438                basis.Denominator,
 803439                localCorner,
 803440                axisDenominator),
 803441            GetCornerToAxisCenterComponent(
 803442                boxCenter.Z,
 803443                axisCenter.Z,
 803444                basis.Xz,
 803445                basis.Yz,
 803446                basis.Zz,
 803447                basis.Denominator,
 803448                localCorner,
 803449                axisDenominator));
 450
 451    private static Signed320 GetCornerToAxisCenterComponent(
 452        Fixed64 boxCenter,
 453        Fixed64 axisCenter,
 454        Signed192 basisX,
 455        Signed192 basisY,
 456        Signed192 basisZ,
 457        Signed192 basisDenominator,
 458        Vector3d localCorner,
 459        Signed192 axisDenominator)
 460    {
 2409461        Signed320 corner = GetLocalOffsetNumerator(
 2409462            basisX,
 2409463            basisY,
 2409464            basisZ,
 2409465            localCorner);
 2409466        Signed576 center = WideArithmetic.MultiplySigned320(
 2409467            WideArithmetic.MultiplySigned192(
 2409468                WideArithmetic.SubtractSigned192(
 2409469                    Signed192.Raw(axisCenter),
 2409470                    Signed192.Raw(boxCenter)),
 2409471                basisDenominator),
 2409472            Signed320.ExtendValue(axisDenominator));
 2409473        Signed576 cornerWide = WideArithmetic.MultiplySigned320(
 2409474            corner,
 2409475            Signed320.ExtendValue(axisDenominator));
 476        // The 65-bit center delta and at-most-134-bit rotated corner each
 477        // retain both at-most-68-bit rigid denominators. Their difference
 478        // needs at most 203 signed bits and therefore fits Signed320 exactly.
 2409479        return Signed320.NarrowValue(WideArithmetic.SubtractSigned576(center, cornerWide));
 480    }
 481
 482    private static CapsuleAxis3 GetPerpendicularAxis(
 483        in WideAxis3 difference,
 484        in WideAxis3 lineAxis,
 485        in Signed576 lineSquared,
 486        in Signed576 projection) =>
 6526487        new(
 6526488            GetPerpendicularComponent(
 6526489                difference.X,
 6526490                lineAxis.X,
 6526491                lineSquared,
 6526492                projection),
 6526493            GetPerpendicularComponent(
 6526494                difference.Y,
 6526495                lineAxis.Y,
 6526496                lineSquared,
 6526497                projection),
 6526498            GetPerpendicularComponent(
 6526499                difference.Z,
 6526500                lineAxis.Z,
 6526501                lineSquared,
 6526502                projection));
 503
 504    private static Signed576 GetPerpendicularComponent(
 505        in Signed320 difference,
 506        in Signed320 line,
 507        in Signed576 lineSquared,
 508        in Signed576 projection)
 509    {
 19578510        Signed704 first = WideArithmetic.MultiplySigned576ToSigned704(
 19578511            lineSquared,
 19578512            difference);
 19578513        Signed704 second = WideArithmetic.MultiplySigned576ToSigned704(
 19578514            projection,
 19578515            line);
 516        // Vertex-to-axis terms need at most 411 signed bits; endpoint-to-edge
 517        // terms need at most 377. Their difference therefore fits Signed576
 518        // exactly before it becomes a candidate separating axis.
 19578519        return Signed576.NarrowValue(
 19578520            WideArithmetic.SubtractSigned704(first, second));
 521    }
 522
 523    private static bool TryKeepCapsuleAxis(
 524        in CapsuleAxis3 axis,
 525        in WideAxis3 scaledExtents,
 526        in WideAxis3 twiceTranslation,
 527        Signed192 commonDenominator,
 528        in WideAxis3 capsuleAxis,
 529        in Signed320 axialScale,
 530        Fixed64 capsuleRadius,
 531        int featureRank,
 532        ref CapsulePenetration best,
 533        bool strict)
 534    {
 53201535        if (axis.IsZero)
 1170536            return true;
 537
 52031538        Signed704 boxRadius = GetLocalCapsuleBoxRadius(
 52031539            axis,
 52031540            scaledExtents);
 52031541        Signed704 centerProjection = GetLocalCapsuleCenterProjection(
 52031542            axis,
 52031543            twiceTranslation);
 52031544        bool negate = centerProjection.Sign < 0;
 52031545        Signed704 rational = WideArithmetic.SubtractSigned704(
 52031546            boxRadius,
 52031547            negate
 52031548                ? WideArithmetic.SubtractSigned704(
 52031549                    default,
 52031550                    centerProjection)
 52031551                : centerProjection);
 552        // Every candidate norm is strictly below 2^411. Normalized quaternion
 553        // denominators are below 2^65, so the relative-axis norm
 554        // |A| = Db*Dc*|u| is below 2^163 for a validated Q32.32 unit axis.
 555        // Cauchy therefore bounds |candidate dot A| below 2^574, inside the
 556        // positive 575-bit magnitude of Signed576. This correlated norm bound
 557        // is tighter than summing independent component-width maxima.
 52031558        Signed576 alignment = Signed576.NarrowValue(
 52031559            GetCapsuleAxisProjection(axis, capsuleAxis));
 52031560        Signed704 axial = WideArithmetic.MultiplySigned576ToSigned704(
 52031561            GetMagnitude(alignment),
 52031562            axialScale);
 52031563        rational = WideArithmetic.AddSigned704(rational, axial);
 564
 565        // Strict admission only needs every candidate's exact depth sign.
 566        // Do not rank depths or retain a witness for a classification query.
 52031567        if (strict && rational.Sign >= 0)
 631568            return rational.Sign > 0 || capsuleRadius > Fixed64.Zero;
 569
 51400570        Signed832 squaredAxisLength = GetCapsuleSquaredLength(axis);
 51400571        if (strict)
 572        {
 111573            return CompareWideCapsuleRadicalToRational(
 111574                squaredAxisLength, commonDenominator, capsuleRadius, rational) > 0;
 575        }
 51289576        if (rational.Sign < 0
 51289577            && CompareWideCapsuleRadicalToRational(
 51289578                squaredAxisLength,
 51289579                commonDenominator,
 51289580                capsuleRadius,
 51289581                rational) < 0)
 582        {
 51583            return false;
 584        }
 585
 51238586        bool shouldReplace = !best.HasValue;
 51238587        if (best.HasValue)
 588        {
 49818589            int comparison = CompareWideCapsuleDepth(
 49818590                rational,
 49818591                squaredAxisLength,
 49818592                best.WideRational,
 49818593                best.WideSquaredAxisLength);
 49818594            shouldReplace = comparison < 0
 49818595                || (comparison == 0 && featureRank < best.FeatureRank);
 596        }
 51238597        if (shouldReplace)
 598        {
 3092599            best = new CapsulePenetration(
 3092600                axis,
 3092601                negate,
 3092602                rational,
 3092603                squaredAxisLength,
 3092604                featureRank);
 605        }
 51238606        return true;
 607    }
 608
 609    private static Signed704 GetLocalCapsuleBoxRadius(
 610        in CapsuleAxis3 axis,
 611        in WideAxis3 scaledExtents) =>
 52031612        WideArithmetic.AddSigned704(
 52031613            WideArithmetic.AddSigned704(
 52031614                WideArithmetic.MultiplySigned576ToSigned704(
 52031615                    GetMagnitude(axis.X),
 52031616                    scaledExtents.X),
 52031617                WideArithmetic.MultiplySigned576ToSigned704(
 52031618                    GetMagnitude(axis.Y),
 52031619                    scaledExtents.Y)),
 52031620            WideArithmetic.MultiplySigned576ToSigned704(
 52031621                GetMagnitude(axis.Z),
 52031622                scaledExtents.Z));
 623
 624    private static Signed704 GetLocalCapsuleCenterProjection(
 625        in CapsuleAxis3 axis,
 626        in WideAxis3 twiceTranslation) =>
 52031627        WideArithmetic.AddSigned704(
 52031628            WideArithmetic.AddSigned704(
 52031629                WideArithmetic.MultiplySigned576ToSigned704(
 52031630                    axis.X,
 52031631                    twiceTranslation.X),
 52031632                WideArithmetic.MultiplySigned576ToSigned704(
 52031633                    axis.Y,
 52031634                    twiceTranslation.Y)),
 52031635            WideArithmetic.MultiplySigned576ToSigned704(
 52031636                axis.Z,
 52031637                twiceTranslation.Z));
 638
 639    private static Signed704 GetCapsuleBasisProjection(
 640        in CapsuleAxis3 axis,
 641        Signed192 x,
 642        Signed192 y,
 643        Signed192 z) =>
 14835644        WideArithmetic.AddSigned704(
 14835645            WideArithmetic.AddSigned704(
 14835646                WideArithmetic.MultiplySigned576ToSigned704(
 14835647                    axis.X,
 14835648                    Signed320.ExtendValue(x)),
 14835649                WideArithmetic.MultiplySigned576ToSigned704(
 14835650                    axis.Y,
 14835651                    Signed320.ExtendValue(y))),
 14835652            WideArithmetic.MultiplySigned576ToSigned704(
 14835653                axis.Z,
 14835654                Signed320.ExtendValue(z)));
 655
 656    private static Signed704 GetCapsuleAxisProjection(
 657        in CapsuleAxis3 axis,
 658        in WideAxis3 direction) =>
 56867659        WideArithmetic.AddSigned704(
 56867660            WideArithmetic.AddSigned704(
 56867661                WideArithmetic.MultiplySigned576ToSigned704(
 56867662                    axis.X,
 56867663                    direction.X),
 56867664                WideArithmetic.MultiplySigned576ToSigned704(
 56867665                    axis.Y,
 56867666                    direction.Y)),
 56867667            WideArithmetic.MultiplySigned576ToSigned704(
 56867668                axis.Z,
 56867669                direction.Z));
 670
 671    private static Signed832 GetCapsuleSquaredLength(
 672        in CapsuleAxis3 axis) =>
 51400673        WideArithmetic.AddSigned832(
 51400674            WideArithmetic.AddSigned832(
 51400675                WideArithmetic.MultiplySigned576ToSigned832(
 51400676                    axis.X,
 51400677                    axis.X),
 51400678                WideArithmetic.MultiplySigned576ToSigned832(
 51400679                    axis.Y,
 51400680                    axis.Y)),
 51400681            WideArithmetic.MultiplySigned576ToSigned832(
 51400682                axis.Z,
 51400683                axis.Z));
 684
 685    private static int CompareWideCapsuleRadicalToRational(
 686        Signed832 squaredAxisLength,
 687        Signed192 commonDenominator,
 688        Fixed64 radius,
 689        Signed704 rational)
 690    {
 3768691        Span<ulong> axis = stackalloc ulong[13];
 3768692        Span<ulong> coefficient = stackalloc ulong[5];
 3768693        Span<ulong> coefficientSquared = stackalloc ulong[10];
 3768694        Span<ulong> rationalMagnitude = stackalloc ulong[11];
 3768695        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 3768696        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 3768697        WideArithmetic.GetMagnitude(squaredAxisLength, axis);
 3768698        Signed320 coefficientValue = WideArithmetic.MultiplySigned192(
 3768699            commonDenominator,
 3768700            Signed192.Raw(radius));
 3768701        WideArithmetic.GetMagnitude(
 3768702            coefficientValue,
 3768703            out coefficient[4],
 3768704            out coefficient[3],
 3768705            out coefficient[2],
 3768706            out coefficient[1],
 3768707            out coefficient[0]);
 3768708        WideArithmetic.MultiplyMagnitudes(
 3768709            coefficient,
 3768710            coefficient,
 3768711            coefficientSquared);
 3768712        WideArithmetic.MultiplyMagnitudes(coefficientSquared, axis, left);
 3768713        WideArithmetic.GetMagnitude(rational, rationalMagnitude);
 3768714        WideArithmetic.MultiplyMagnitudes(
 3768715            rationalMagnitude,
 3768716            rationalMagnitude,
 3768717            right);
 3768718        return WideArithmetic.CompareMagnitudeEqualLength(left, right);
 719    }
 720
 721    private static void GetWideCapsuleDepth(
 722        Signed704 rational,
 723        Signed832 squaredAxisLength,
 724        Signed192 commonDenominator,
 725        Fixed64 radius,
 726        out Fixed64 depth,
 727        out bool depthIsClamped)
 728    {
 193729        Signed576 axisLength = WideArithmetic.GetFloorSquareRootOfProduct(
 193730            squaredAxisLength,
 193731            Signed192.Signed(1L));
 193732        Signed704 denominator = WideArithmetic.MultiplySigned576ToSigned704(
 193733            axisLength,
 193734            Signed320.ExtendValue(commonDenominator));
 193735        Signed320 radialScale = WideArithmetic.MultiplySigned192(
 193736            commonDenominator,
 193737            Signed192.Raw(radius));
 738        // Rigid basis axes have an exact integer length. Every other capsule
 739        // candidate retains both rigid Q32.32 denominators, so flooring its
 740        // radical is still finer than one Q32.32 quotient rounding interval.
 193741        Signed704 numerator = WideArithmetic.AddSigned704(
 193742            rational,
 193743            WideArithmetic.MultiplySigned576ToSigned704(
 193744                axisLength,
 193745                radialScale));
 193746        if (!Fixed64.TryGetSignedRawRatio(numerator, denominator, out depth))
 747        {
 3748            depth = Fixed64.MaxValue;
 3749            depthIsClamped = true;
 3750            return;
 751        }
 752
 190753        depthIsClamped = false;
 190754    }
 755
 756    private static int CompareWideCapsuleDepth(
 757        Signed704 candidateRational,
 758        Signed832 candidateSquaredAxisLength,
 759        Signed704 currentRational,
 760        Signed832 currentSquaredAxisLength)
 761    {
 49818762        int candidateSign = candidateRational.Sign;
 49818763        int currentSign = currentRational.Sign;
 49818764        Span<ulong> candidate = stackalloc ulong[11];
 49818765        Span<ulong> current = stackalloc ulong[11];
 49818766        Span<ulong> candidateAxis = stackalloc ulong[13];
 49818767        Span<ulong> currentAxis = stackalloc ulong[13];
 49818768        WideArithmetic.GetMagnitude(candidateRational, candidate);
 49818769        WideArithmetic.GetMagnitude(currentRational, current);
 49818770        WideArithmetic.GetMagnitude(
 49818771            candidateSquaredAxisLength,
 49818772            candidateAxis);
 49818773        WideArithmetic.GetMagnitude(
 49818774            currentSquaredAxisLength,
 49818775            currentAxis);
 49818776        return WideArithmetic.CompareSignedNormalizedMagnitudes(
 49818777            candidate,
 49818778            candidateSign,
 49818779            candidateAxis,
 49818780            current,
 49818781            currentSign,
 49818782            currentAxis);
 783    }
 784
 785    private static CapsuleAxis3 ToCapsuleAxis(in WideAxis3 axis) =>
 16937786        new(
 16937787            Signed576.ExtendValue(axis.X),
 16937788            Signed576.ExtendValue(axis.Y),
 16937789            Signed576.ExtendValue(axis.Z));
 790}

/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) =>
 164331        WideArithmetic.AddSigned576(
 164332            WideArithmetic.MultiplySigned576(
 164333                Signed576.ExtendValue(axis.X),
 164334                Signed192.Raw(planarDirection.X)),
 164335            WideArithmetic.MultiplySigned576(
 164336                Signed576.ExtendValue(axis.Z),
 164337                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    {
 5418        Vector2d localTowardBox = GetLocalPlanarSupportDirection(
 5419            boxToSlabAxis,
 5420            capsuleFrameRotation);
 5421        FixedPointAnchor2d planar =
 5422            FixedSegment2d.GetCenteredCapsuleSupportAnchor(
 5423                Vector2d.Zero,
 5424                capsuleFrameRotation,
 5425                localCapsuleAxisDirection,
 5426                capsuleAxisLength,
 5427                capsuleRadius,
 5428                localTowardBox);
 5429        return new FixedPointAnchor(
 5430            slabCenter,
 5431            FixedQuaternion.FromAxisAngle(
 5432                Vector3d.Up,
 5433                -capsuleFrameRotation),
 5434            new Vector3d(
 5435                planar.LocalPoint.X,
 5436                boxToSlabAxis.Y.Sign >= 0
 5437                    ? -slabHalfThickness
 5438                    : slabHalfThickness,
 5439                planar.LocalPoint.Y),
 5440            new Vector3d(
 5441                planar.LocalDisplacement.X,
 5442                Fixed64.Zero,
 5443                planar.LocalDisplacement.Y),
 5444            FixedPointAnchorTerm3d.LiftPlanarXZ(
 5445                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    {
 30728        WideRationalBasis3d basis = new(orientation);
 30729        var best = default(RadialPenetration);
 30730        WideAxis3 up = new(default, Signed320.One, default);
 30731        if (!TryKeepCircleSlabAxis(
 30732                up,
 30733                center,
 30734                halfExtents,
 30735                basis,
 30736                slabCenter,
 30737                slabHalfThickness,
 30738                radius,
 30739                ref best))
 40        {
 241            contact = default;
 242            return false;
 43        }
 44
 30545        Span<WideAxis3> boxAxes = stackalloc WideAxis3[3]
 30546        {
 30547            new(
 30548                Signed320.ExtendValue(basis.Xx),
 30549                Signed320.ExtendValue(basis.Xy),
 30550                Signed320.ExtendValue(basis.Xz)),
 30551            new(
 30552                Signed320.ExtendValue(basis.Yx),
 30553                Signed320.ExtendValue(basis.Yy),
 30554                Signed320.ExtendValue(basis.Yz)),
 30555            new(
 30556                Signed320.ExtendValue(basis.Zx),
 30557                Signed320.ExtendValue(basis.Zy),
 30558                Signed320.ExtendValue(basis.Zz)),
 30559        };
 73060        for (int index = 0; index < boxAxes.Length; index++)
 61        {
 34562            if (!TryKeepCircleSlabAxis(
 34563                    boxAxes[index],
 34564                    center,
 34565                    halfExtents,
 34566                    basis,
 34567                    slabCenter,
 34568                    slabHalfThickness,
 34569                    radius,
 34570                    ref best)
 34571                || !TryKeepCircleSlabAxis(
 34572                    CrossWithUp(boxAxes[index]),
 34573                    center,
 34574                    halfExtents,
 34575                    basis,
 34576                    slabCenter,
 34577                    slabHalfThickness,
 34578                    radius,
 34579                    ref best))
 80            {
 28581                contact = default;
 28582                return false;
 83            }
 84        }
 85
 32886        for (int cornerIndex = 0; cornerIndex < FixedOrientedBox.CornerCount; cornerIndex++)
 87        {
 14688            Vector3d localCorner = new(
 14689                (cornerIndex & 1) == 0 ? -halfExtents.X : halfExtents.X,
 14690                (cornerIndex & 2) == 0 ? -halfExtents.Y : halfExtents.Y,
 14691                (cornerIndex & 4) == 0 ? -halfExtents.Z : halfExtents.Z);
 14692            WideAxis3 cornerAxis = GetCornerToOriginAxis(
 14693                center,
 14694                slabCenter,
 14695                basis,
 14696                localCorner);
 14697            if (!TryKeepCircleSlabAxis(
 14698                    cornerAxis,
 14699                    center,
 146100                    halfExtents,
 146101                    basis,
 146102                    slabCenter,
 146103                    slabHalfThickness,
 146104                    radius,
 146105                    ref best))
 106            {
 2107                contact = default;
 2108                return false;
 109            }
 110        }
 111
 18112        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 18113        Vector3d normal = WideNormalization.GetNormalized(
 18114            Signed576.ExtendValue(orientedAxis.X),
 18115            Signed576.ExtendValue(orientedAxis.Y),
 18116            Signed576.ExtendValue(orientedAxis.Z));
 18117        Vector3d boxLocalPoint = GetCircleSlabBoxContactPoint(
 18118            center,
 18119            orientation,
 18120            halfExtents,
 18121            slabCenter,
 18122            basis,
 18123            orientedAxis);
 18124        FixedPointAnchor slabAnchor = GetCircleSlabSupportAnchor(
 18125            slabCenter,
 18126            orientedAxis,
 18127            circleFrameRotation,
 18128            slabHalfThickness,
 18129            radius);
 18130        contact = new FixedContactAnchors(
 18131            new FixedPointAnchor(center, orientation, boxLocalPoint),
 18132            slabAnchor,
 18133            normal,
 18134            best.Depth,
 18135            best.DepthIsClamped);
 18136        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    {
 18147        var slabCenterAnchor = new FixedPointAnchor(
 18148            slabCenter,
 18149            FixedQuaternion.Identity,
 18150            Vector3d.Zero);
 18151        if (!slabCenterAnchor.TryGetLocalPointIn(
 18152                boxCenter,
 18153                boxOrientation,
 18154                out Vector3d localCenter))
 155        {
 1156            return GetLocalAxisSupportPoint(
 1157                basis,
 1158                halfExtents,
 1159                boxToSlabAxis);
 160        }
 161
 17162        bool outsideX = localCenter.X < -halfExtents.X
 17163            || localCenter.X > halfExtents.X;
 17164        bool outsideY = localCenter.Y < -halfExtents.Y
 17165            || localCenter.Y > halfExtents.Y;
 17166        bool outsideZ = localCenter.Z < -halfExtents.Z
 17167            || localCenter.Z > halfExtents.Z;
 17168        Vector3d closest = new(
 17169            FixedMath.Clamp(
 17170                localCenter.X,
 17171                -halfExtents.X,
 17172                halfExtents.X),
 17173            FixedMath.Clamp(
 17174                localCenter.Y,
 17175                -halfExtents.Y,
 17176                halfExtents.Y),
 17177            FixedMath.Clamp(
 17178                localCenter.Z,
 17179                -halfExtents.Z,
 17180                halfExtents.Z));
 17181        if (outsideX || outsideY || outsideZ)
 9182            return closest;
 183
 8184        Signed576 localNormalX = WideRigidProjection.GetBasisAxisProjection(
 8185            boxToSlabAxis,
 8186            basis.Xx,
 8187            basis.Xy,
 8188            basis.Xz);
 8189        Signed576 localNormalY = WideRigidProjection.GetBasisAxisProjection(
 8190            boxToSlabAxis,
 8191            basis.Yx,
 8192            basis.Yy,
 8193            basis.Yz);
 8194        Signed576 localNormalZ = WideRigidProjection.GetBasisAxisProjection(
 8195            boxToSlabAxis,
 8196            basis.Zx,
 8197            basis.Zy,
 8198            basis.Zz);
 8199        Signed576 magnitudeX = GetMagnitude(localNormalX);
 8200        Signed576 magnitudeY = GetMagnitude(localNormalY);
 8201        Signed576 magnitudeZ = GetMagnitude(localNormalZ);
 8202        if (CompareSigned(magnitudeX, magnitudeY) >= 0
 8203            && CompareSigned(magnitudeX, magnitudeZ) >= 0)
 204        {
 3205            closest.X = localNormalX.Sign < 0
 3206                ? -halfExtents.X
 3207                : 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
 8222        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    {
 862235        if (axis.IsZero)
 21236            return true;
 237
 841238        Signed576 boxRadius = GetBoxProjectionRadiusNumerator(
 841239            axis,
 841240            halfExtents,
 841241            basis);
 841242        Signed576 centerProjection = WideRigidProjection.GetWorldOriginDifferenceProjection(
 841243            slabCenter,
 841244            boxCenter,
 841245            axis);
 841246        bool negate = centerProjection.Sign < 0;
 841247        Signed576 centerMagnitude = GetMagnitude(centerProjection);
 841248        Signed576 verticalRadius = WideArithmetic.MultiplySigned576(
 841249            Signed576.ExtendValue(GetMagnitude(axis.Y)),
 841250            Signed192.Raw(slabHalfThickness));
 841251        Signed576 rational = WideArithmetic.AddSigned576(
 841252            boxRadius,
 841253            WideArithmetic.MultiplySigned576(
 841254                WideArithmetic.SubtractSigned576(
 841255                    verticalRadius,
 841256                    centerMagnitude),
 841257                basis.Denominator));
 841258        Signed576 planarSquared = WideArithmetic.AddSigned576(
 841259            WideArithmetic.MultiplySigned320(axis.X, axis.X),
 841260            WideArithmetic.MultiplySigned320(axis.Z, axis.Z));
 841261        Signed320 radiusSquared = WideArithmetic.MultiplySigned192(
 841262            Signed192.Raw(radius),
 841263            Signed192.Raw(radius));
 841264        Signed832 radialSquared = WideArithmetic.MultiplySigned576ToSigned832(
 841265            Signed576.ExtendValue(radiusSquared),
 841266            planarSquared);
 841267        if (rational.Sign < 0
 841268            && !IsRadicalAtLeastRatio(
 841269                radialSquared,
 841270                WideArithmetic.SubtractSigned576(default, rational),
 841271                basis.Denominator))
 272        {
 289273            return false;
 274        }
 275
 552276        Signed576 squaredAxisLength = axis.SquaredLength;
 552277        GetRadialDepth(
 552278            rational,
 552279            radialSquared,
 552280            squaredAxisLength,
 552281            basis.Denominator,
 552282            out Fixed64 depth,
 552283            out bool depthIsClamped);
 552284        if (!best.HasValue
 552285            || depth < best.Depth
 552286            || (depth == best.Depth
 552287                && WideArithmetic.CompareRadialProjectionDepths(
 552288                    rational,
 552289                    radialSquared,
 552290                    ToSigned576(Signed192.Signed(1L)),
 552291                    squaredAxisLength,
 552292                    best.Rational,
 552293                    best.RadialNumerator,
 552294                    best.RadialDenominator,
 552295                    best.AxisSquared,
 552296                    basis.Denominator) < 0))
 297        {
 327298            best = new RadialPenetration(
 327299                axis,
 327300                negate,
 327301                depth,
 327302                depthIsClamped,
 327303                rational,
 327304                radialSquared,
 327305                ToSigned576(Signed192.Signed(1L)),
 327306                squaredAxisLength);
 307        }
 552308        return true;
 309    }
 310
 311    private static bool IsRadicalAtLeastRatio(
 312        Signed832 radicalSquared,
 313        Signed576 ratioNumerator,
 314        Signed192 ratioDenominator)
 315    {
 399316        Span<ulong> radicalMagnitude = stackalloc ulong[13];
 399317        Span<ulong> denominatorMagnitude = stackalloc ulong[3];
 399318        Span<ulong> denominatorSquared = stackalloc ulong[6];
 399319        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 399320        Span<ulong> numeratorMagnitude = stackalloc ulong[9];
 399321        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 399322        WideArithmetic.GetMagnitude(radicalSquared, radicalMagnitude);
 399323        WideArithmetic.GetMagnitude(
 399324            ratioDenominator,
 399325            out denominatorMagnitude[2],
 399326            out denominatorMagnitude[1],
 399327            out denominatorMagnitude[0]);
 399328        WideArithmetic.MultiplyMagnitudes(
 399329            denominatorMagnitude,
 399330            denominatorMagnitude,
 399331            denominatorSquared);
 399332        WideArithmetic.MultiplyMagnitudes(
 399333            radicalMagnitude,
 399334            denominatorSquared,
 399335            left);
 399336        WideArithmetic.GetMagnitude(
 399337            ratioNumerator,
 399338            numeratorMagnitude);
 399339        WideArithmetic.MultiplyMagnitudes(
 399340            numeratorMagnitude,
 399341            numeratorMagnitude,
 399342            right);
 399343        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    {
 709354        Signed576 radial = WideArithmetic.GetFloorSquareRootOfProduct(
 709355            radialSquared,
 709356            Signed192.Signed(1L));
 709357        Signed576 numerator = WideArithmetic.AddSigned576(
 709358            rational,
 709359            WideArithmetic.MultiplySigned576(radial, basisDenominator));
 709360        numerator = WideArithmetic.ClampToNonNegative(numerator);
 709361        Signed576 axisLength = WideArithmetic.GetFloorSquareRoot(
 709362            Signed704.ExtendValue(squaredAxisLength));
 709363        Signed576 denominator = WideArithmetic.MultiplySigned576(
 709364            axisLength,
 709365            basisDenominator);
 709366        if (!Fixed64.TryGetSignedRawRatio(numerator, denominator, out depth))
 367        {
 42368            depth = Fixed64.MaxValue;
 42369            depthIsClamped = true;
 42370            return;
 371        }
 372
 667373        depthIsClamped = false;
 667374    }
 375
 376    private static WideAxis3 GetCornerToOriginAxis(
 377        Vector3d boxCenter,
 378        Vector3d otherOrigin,
 379        WideRationalBasis3d basis,
 380        Vector3d localCorner)
 381    {
 146382        Signed320 cornerX = GetLocalOffsetNumerator(
 146383            basis.Xx,
 146384            basis.Yx,
 146385            basis.Zx,
 146386            localCorner);
 146387        Signed320 cornerZ = GetLocalOffsetNumerator(
 146388            basis.Xz,
 146389            basis.Yz,
 146390            basis.Zz,
 146391            localCorner);
 146392        return new WideAxis3(
 146393            WideArithmetic.SubtractSigned320(
 146394                WideArithmetic.MultiplySigned192(
 146395                    WideArithmetic.SubtractSigned192(
 146396                        Signed192.Raw(otherOrigin.X),
 146397                        Signed192.Raw(boxCenter.X)),
 146398                    basis.Denominator),
 146399                cornerX),
 146400            default,
 146401            WideArithmetic.SubtractSigned320(
 146402                WideArithmetic.MultiplySigned192(
 146403                    WideArithmetic.SubtractSigned192(
 146404                        Signed192.Raw(otherOrigin.Z),
 146405                        Signed192.Raw(boxCenter.Z)),
 146406                    basis.Denominator),
 146407                cornerZ));
 408    }
 409
 410    private static Signed320 GetLocalOffsetNumerator(
 411        Signed192 axisX,
 412        Signed192 axisY,
 413        Signed192 axisZ,
 414        Vector3d localOffset) =>
 23452415        WideArithmetic.AddSigned320(
 23452416            WideArithmetic.AddSigned320(
 23452417                WideArithmetic.MultiplySigned192(
 23452418                    Signed192.Raw(localOffset.X),
 23452419                    axisX),
 23452420                WideArithmetic.MultiplySigned192(
 23452421                    Signed192.Raw(localOffset.Y),
 23452422                    axisY)),
 23452423            WideArithmetic.MultiplySigned192(
 23452424                Signed192.Raw(localOffset.Z),
 23452425                axisZ));
 426
 427    private static FixedPointAnchor GetCircleSlabSupportAnchor(
 428        Vector3d slabCenter,
 429        WideAxis3 boxToSlabAxis,
 430        Fixed64 circleFrameRotation,
 431        Fixed64 halfThickness,
 432        Fixed64 radius)
 433    {
 18434        Vector2d localTowardBox = GetLocalPlanarSupportDirection(
 18435            boxToSlabAxis,
 18436            circleFrameRotation);
 18437        Vector3d localRadialDirection = new(
 18438            localTowardBox.X,
 18439            Fixed64.Zero,
 18440            localTowardBox.Y);
 18441        Vector3d roundedRadialOffset =
 18442            localRadialDirection * radius;
 18443        Vector3d localPoint = new(
 18444            Fixed64.Zero,
 18445            boxToSlabAxis.Y.Sign >= 0 ? -halfThickness : halfThickness,
 18446            Fixed64.Zero);
 18447        return new FixedPointAnchor(
 18448            slabCenter,
 18449            FixedQuaternion.FromAxisAngle(
 18450                Vector3d.Up,
 18451                -circleFrameRotation),
 18452            localPoint,
 18453            roundedRadialOffset,
 18454            FixedPointAnchorTerm3d.CreateRadialSupport(
 18455                localRadialDirection,
 18456                radius,
 18457                roundedRadialOffset));
 458    }
 459
 460    private static Vector2d GetLocalPlanarSupportDirection(
 461        WideAxis3 boxToSlabAxis,
 462        Fixed64 frameRotation)
 463    {
 23464        Signed576 worldX = WideArithmetic.SubtractSigned576(
 23465            default,
 23466            Signed576.ExtendValue(boxToSlabAxis.X));
 23467        Signed576 worldY = WideArithmetic.SubtractSigned576(
 23468            default,
 23469            Signed576.ExtendValue(boxToSlabAxis.Z));
 23470        Signed192 cosine = Signed192.Raw(FixedMath.Cos(frameRotation));
 23471        Signed192 sine = Signed192.Raw(FixedMath.Sin(frameRotation));
 23472        Signed576 localX = WideArithmetic.AddSigned576(
 23473            WideArithmetic.MultiplySigned576(worldX, cosine),
 23474            WideArithmetic.MultiplySigned576(worldY, sine));
 23475        Signed576 localY = WideArithmetic.SubtractSigned576(
 23476            WideArithmetic.MultiplySigned576(worldY, cosine),
 23477            WideArithmetic.MultiplySigned576(worldX, sine));
 23478        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        {
 234434            A = a;
 234435            B = b;
 234436            C = c;
 234437            K = k;
 234438        }
 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        {
 439552            A = a;
 439553            C = c;
 439554            K = k;
 439555        }
 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        {
 229669            X = x;
 229670            Y = y;
 229671            Z = z;
 229672        }
 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        {
 1168786            X = x;
 1168787            Z = z;
 1168788            Denominator = denominator;
 1168789        }
 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    {
 293103        Span<SweepSpatialConstraint> spatial =
 293104            stackalloc SweepSpatialConstraint[8];
 293105        int spatialCount = 0;
 293106        AddBoxAxisConstraints(
 293107            center,
 293108            halfExtents.X,
 293109            basis.Denominator,
 293110            basis.Xx,
 293111            basis.Xy,
 293112            basis.Xz,
 293113            spatial,
 293114            ref spatialCount);
 293115        AddBoxAxisConstraints(
 293116            center,
 293117            halfExtents.Y,
 293118            basis.Denominator,
 293119            basis.Yx,
 293120            basis.Yy,
 293121            basis.Yz,
 293122            spatial,
 293123            ref spatialCount);
 293124        AddBoxAxisConstraints(
 293125            center,
 293126            halfExtents.Z,
 293127            basis.Denominator,
 293128            basis.Zx,
 293129            basis.Zy,
 293130            basis.Zz,
 293131            spatial,
 293132            ref spatialCount);
 293133        spatial[spatialCount++] = new SweepSpatialConstraint(
 293134            default,
 293135            SweepOneCoefficient,
 293136            default,
 293137            Signed320.ExtendValue(upperY));
 293138        spatial[spatialCount++] = new SweepSpatialConstraint(
 293139            default,
 293140            WideArithmetic.SubtractSigned192(
 293141                default,
 293142                SweepOneCoefficient),
 293143            default,
 293144            Signed320.ExtendValue(
 293145                WideArithmetic.SubtractSigned192(default, lowerY)));
 146
 293147        count = 0;
 5274148        for (int index = 0; index < spatialCount; index++)
 149        {
 2344150            if (!spatial[index].B.IsZero)
 151                continue;
 152
 144153            constraints[count++] = new SweepPlanarConstraint(
 144154                Signed320.ExtendValue(spatial[index].A),
 144155                Signed320.ExtendValue(spatial[index].C),
 144156                Signed576.ExtendValue(spatial[index].K));
 157        }
 158
 5246159        for (int positive = 0; positive < spatialCount; positive++)
 160        {
 2333161            if (spatial[positive].B.Sign <= 0)
 162                continue;
 163
 19750164            for (int negative = 0; negative < spatialCount; negative++)
 165            {
 8780166                if (spatial[negative].B.Sign >= 0)
 167                    continue;
 168
 4251169                Signed320 a = WideArithmetic.SubtractSigned320(
 4251170                    WideArithmetic.MultiplySigned192(
 4251171                        spatial[positive].B,
 4251172                        spatial[negative].A),
 4251173                    WideArithmetic.MultiplySigned192(
 4251174                        spatial[negative].B,
 4251175                        spatial[positive].A));
 4251176                Signed320 c = WideArithmetic.SubtractSigned320(
 4251177                    WideArithmetic.MultiplySigned192(
 4251178                        spatial[positive].B,
 4251179                        spatial[negative].C),
 4251180                    WideArithmetic.MultiplySigned192(
 4251181                        spatial[negative].B,
 4251182                        spatial[positive].C));
 4251183                Signed576 k = WideArithmetic.SubtractSigned576(
 4251184                    WideArithmetic.MultiplySigned320(
 4251185                        Signed320.ExtendValue(
 4251186                            spatial[positive].B),
 4251187                        spatial[negative].K),
 4251188                    WideArithmetic.MultiplySigned320(
 4251189                        Signed320.ExtendValue(
 4251190                            spatial[negative].B),
 4251191                        spatial[positive].K));
 4251192                if (!TryAddProjectionConstraint(
 4251193                        new SweepPlanarConstraint(a, c, k),
 4251194                        constraints,
 4251195                        ref count))
 196                {
 3197                    return false;
 198                }
 199            }
 200        }
 201
 290202        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    {
 879215        Signed320 centerProjection = WideArithmetic.AddSigned320(
 879216            WideArithmetic.AddSigned320(
 879217                WideArithmetic.MultiplySigned192(Signed192.Raw(center.X), axisX),
 879218                WideArithmetic.MultiplySigned192(Signed192.Raw(center.Y), axisY)),
 879219            WideArithmetic.MultiplySigned192(Signed192.Raw(center.Z), axisZ));
 879220        Signed320 extentNumerator =
 879221            WideArithmetic.MultiplySigned192(Signed192.Raw(extent), denominator);
 879222        constraints[count++] = new SweepSpatialConstraint(
 879223            axisX,
 879224            axisY,
 879225            axisZ,
 879226            WideArithmetic.AddSigned320(
 879227                extentNumerator,
 879228                centerProjection));
 879229        constraints[count++] = new SweepSpatialConstraint(
 879230            WideArithmetic.SubtractSigned192(default, axisX),
 879231            WideArithmetic.SubtractSigned192(default, axisY),
 879232            WideArithmetic.SubtractSigned192(default, axisZ),
 879233            WideArithmetic.SubtractSigned320(
 879234                extentNumerator,
 879235                centerProjection));
 879236    }
 237
 238    private static bool TryAddProjectionConstraint(
 239        SweepPlanarConstraint constraint,
 240        Span<SweepPlanarConstraint> constraints,
 241        ref int count)
 242    {
 4251243        if (constraint.A.IsZero && constraint.C.IsZero)
 1167244            return constraint.K.Sign >= 0;
 245
 3084246        constraints[count++] = constraint;
 3084247        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    {
 287259        Span<SweepBoxCorner> corners = stackalloc SweepBoxCorner[8];
 287260        Signed320 lowerNumerator =
 287261            WideArithmetic.MultiplySigned192(lowerY, basis.Denominator);
 287262        Signed320 upperNumerator =
 287263            WideArithmetic.MultiplySigned192(upperY, basis.Denominator);
 287264        count = 0;
 5166265        for (int index = 0; index < corners.Length; index++)
 266        {
 2296267            Vector3d local = new(
 2296268                (index & 1) == 0 ? -halfExtents.X : halfExtents.X,
 2296269                (index & 2) == 0 ? -halfExtents.Y : halfExtents.Y,
 2296270                (index & 4) == 0 ? -halfExtents.Z : halfExtents.Z);
 2296271            corners[index] = GetSweepBoxCorner(center, basis, local);
 2296272            if (CompareSigned(corners[index].Y, lowerNumerator) >= 0
 2296273                && 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
 5166287        for (int index = 0; index < corners.Length; index++)
 288        {
 18368289            for (int bit = 1; bit <= 4; bit <<= 1)
 290            {
 6888291                if ((index & bit) != 0)
 292                    continue;
 293
 3444294                TryAddPlaneIntersection(
 3444295                    corners[index],
 3444296                    corners[index | bit],
 3444297                    lowerNumerator,
 3444298                    basis.Denominator,
 3444299                    vertices,
 3444300                    ref count);
 3444301                TryAddPlaneIntersection(
 3444302                    corners[index],
 3444303                    corners[index | bit],
 3444304                    upperNumerator,
 3444305                    basis.Denominator,
 3444306                    vertices,
 3444307                    ref count);
 308            }
 309        }
 287310    }
 311
 312    private static SweepBoxCorner GetSweepBoxCorner(
 313        Vector3d center,
 314        WideRationalBasis3d basis,
 315        Vector3d local) =>
 2296316        new(
 2296317            WideArithmetic.AddSigned320(
 2296318                WideArithmetic.MultiplySigned192(
 2296319                    Signed192.Raw(center.X),
 2296320                    basis.Denominator),
 2296321                GetLocalOffsetNumerator(
 2296322                    basis.Xx,
 2296323                    basis.Yx,
 2296324                    basis.Zx,
 2296325                    local)),
 2296326            WideArithmetic.AddSigned320(
 2296327                WideArithmetic.MultiplySigned192(
 2296328                    Signed192.Raw(center.Y),
 2296329                    basis.Denominator),
 2296330                GetLocalOffsetNumerator(
 2296331                    basis.Xy,
 2296332                    basis.Yy,
 2296333                    basis.Zy,
 2296334                    local)),
 2296335            WideArithmetic.AddSigned320(
 2296336                WideArithmetic.MultiplySigned192(
 2296337                    Signed192.Raw(center.Z),
 2296338                    basis.Denominator),
 2296339                GetLocalOffsetNumerator(
 2296340                    basis.Xz,
 2296341                    basis.Yz,
 2296342                    basis.Zz,
 2296343                    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    {
 6888353        Signed320 minimum = CompareSigned(first.Y, second.Y) <= 0
 6888354            ? first.Y
 6888355            : second.Y;
 6888356        Signed320 maximum = CompareSigned(first.Y, second.Y) <= 0
 6888357            ? second.Y
 6888358            : first.Y;
 6888359        if (CompareSigned(planeNumerator, minimum) < 0
 6888360            || CompareSigned(planeNumerator, maximum) > 0)
 361        {
 4496362            return;
 363        }
 364
 2392365        Signed320 deltaY =
 2392366            WideArithmetic.SubtractSigned320(second.Y, first.Y);
 2392367        if (deltaY.IsZero)
 104368            return;
 369
 2288370        Signed320 firstWeight =
 2288371            WideArithmetic.SubtractSigned320(second.Y, planeNumerator);
 2288372        Signed320 secondWeight =
 2288373            WideArithmetic.SubtractSigned320(planeNumerator, first.Y);
 2288374        Signed576 x = WideArithmetic.AddSigned576(
 2288375            WideArithmetic.MultiplySigned320(first.X, firstWeight),
 2288376            WideArithmetic.MultiplySigned320(second.X, secondWeight));
 2288377        Signed576 z = WideArithmetic.AddSigned576(
 2288378            WideArithmetic.MultiplySigned320(first.Z, firstWeight),
 2288379            WideArithmetic.MultiplySigned320(second.Z, secondWeight));
 2288380        Signed576 denominator = WideArithmetic.MultiplySigned320(
 2288381            Signed320.ExtendValue(basisDenominator),
 2288382            deltaY);
 2288383        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
 2288391        AddUniqueSweepPoint(
 2288392            new SweepRationalPoint(x, z, denominator),
 2288393            vertices,
 2288394            ref count);
 2288395    }
 396
 397    private static void AddUniqueSweepPoint(
 398        SweepRationalPoint point,
 399        Span<SweepRationalPoint> vertices,
 400        ref int count)
 401    {
 27974402        for (int index = 0; index < count; index++)
 403        {
 9338404            if (AreSameSweepPoint(vertices[index], point))
 370405                return;
 406        }
 407
 4649408        vertices[count++] = point;
 4649409    }
 410
 411    private static bool AreSameSweepPoint(
 412        SweepRationalPoint first,
 413        SweepRationalPoint second) =>
 11516414        WideArithmetic.SubtractSigned832(
 11516415            WideArithmetic.MultiplySigned576ToSigned832(
 11516416                first.X,
 11516417                second.Denominator),
 11516418            WideArithmetic.MultiplySigned576ToSigned832(
 11516419                second.X,
 11516420                first.Denominator)).IsZero
 11516421        && WideArithmetic.SubtractSigned832(
 11516422            WideArithmetic.MultiplySigned576ToSigned832(
 11516423                first.Z,
 11516424                second.Denominator),
 11516425            WideArithmetic.MultiplySigned576ToSigned832(
 11516426                second.Z,
 11516427                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 SweepOneCoefficient = Signed192.Signed(1L);
 20
 21    #region Nested Types
 22
 23    private readonly struct SweepTrajectory
 24    {
 25        internal readonly Signed192 DirectionX;
 26        internal readonly Signed192 DirectionZ;
 27        internal readonly Signed192 TimeScale;
 28        internal readonly bool IsSegment;
 29
 30        internal SweepTrajectory(Vector2d direction)
 31        {
 25432            DirectionX = Signed192.Raw(direction.X);
 25433            DirectionZ = Signed192.Raw(direction.Y);
 25434            TimeScale = SweepRawScale;
 25435            IsSegment = false;
 25436        }
 37
 38        internal SweepTrajectory(FixedSegment2d segment, Fixed64 totalDistance)
 39        {
 25240            DirectionX = WideArithmetic.SubtractSigned192(Signed192.Raw(segment.End.X), Signed192.Raw(segment.Start.X));
 25241            DirectionZ = WideArithmetic.SubtractSigned192(Signed192.Raw(segment.End.Y), Signed192.Raw(segment.Start.Y));
 25242            TimeScale = totalDistance == Fixed64.Zero ? SweepRawScale : Signed192.Raw(totalDistance);
 25243            IsSegment = true;
 25244        }
 45
 4946746        internal Signed192 DoubleTimeScale => WideArithmetic.AddSigned192(TimeScale, TimeScale);
 47    }
 48
 49    private readonly struct RationalPointDistance
 50    {
 51        internal readonly Signed576 Denominator;
 52        internal readonly Signed832 SquaredDistance;
 53
 54        internal RationalPointDistance(
 55            Signed576 denominator,
 56            Signed832 squaredDistance)
 57        {
 1658            Denominator = denominator;
 1659            SquaredDistance = squaredDistance;
 1660        }
 61    }
 62
 63    #endregion
 64
 65    internal static bool TryGetCircleSlabSweepDistance(
 66        Vector3d center,
 67        FixedQuaternion orientation,
 68        Vector3d halfExtents,
 69        Vector3d slabStartCenter,
 70        Vector2d normalizedDirection,
 71        Fixed64 maxDistance,
 72        Fixed64 slabHalfThickness,
 73        Fixed64 radius,
 74        out Fixed64 distance)
 14275        => TryGetCircleSlabSweepDistanceCore(
 14276            center, orientation, halfExtents, slabStartCenter,
 14277            new SweepTrajectory(normalizedDirection), maxDistance, slabHalfThickness, radius, out distance);
 78
 79    internal static bool TryGetCircleSlabSweepDistance(
 80        Vector3d center,
 81        FixedQuaternion orientation,
 82        Vector3d halfExtents,
 83        FixedSegment2d segment,
 84        Fixed64 totalDistance,
 85        Fixed64 slabCenterY,
 86        Fixed64 slabHalfThickness,
 87        Fixed64 radius,
 88        out Fixed64 distance)
 14689        => TryGetCircleSlabSweepDistanceCore(
 14690            center, orientation, halfExtents,
 14691            new Vector3d(segment.Start.X, slabCenterY, segment.Start.Y),
 14692            new SweepTrajectory(segment, totalDistance), totalDistance, slabHalfThickness, radius, out distance);
 93
 94    private static bool TryGetCircleSlabSweepDistanceCore(
 95        Vector3d center,
 96        FixedQuaternion orientation,
 97        Vector3d halfExtents,
 98        Vector3d slabStartCenter,
 99        in SweepTrajectory trajectory,
 100        Fixed64 maxDistance,
 101        Fixed64 slabHalfThickness,
 102        Fixed64 radius,
 103        out Fixed64 distance)
 104    {
 288105        if (TryGetCircleSlabContact(
 288106                center,
 288107                orientation,
 288108                halfExtents,
 288109                slabStartCenter,
 288110                Fixed64.Zero,
 288111                slabHalfThickness,
 288112                radius,
 288113                out _))
 114        {
 2115            distance = Fixed64.Zero;
 2116            return true;
 117        }
 118
 286119        if (maxDistance == Fixed64.Zero)
 120        {
 2121            distance = default;
 2122            return false;
 123        }
 124
 284125        WideRationalBasis3d basis = new(orientation);
 284126        Signed192 lowerY = WideArithmetic.SubtractSigned192(
 284127            Signed192.Raw(slabStartCenter.Y),
 284128            Signed192.Raw(slabHalfThickness));
 284129        Signed192 upperY = WideArithmetic.AddSigned192(
 284130            Signed192.Raw(slabStartCenter.Y),
 284131            Signed192.Raw(slabHalfThickness));
 284132        Span<SweepPlanarConstraint> constraints =
 284133            stackalloc SweepPlanarConstraint[16];
 284134        if (!TryBuildCircleSlabProjectionConstraints(
 284135                center,
 284136                halfExtents,
 284137                basis,
 284138                lowerY,
 284139                upperY,
 284140                constraints,
 284141                out int constraintCount))
 142        {
 1143            distance = default;
 1144            return false;
 145        }
 146
 283147        Span<SweepRationalPoint> vertices =
 283148            stackalloc SweepRationalPoint[32];
 283149        BuildCircleSlabProjectionVertices(
 283150            center,
 283151            halfExtents,
 283152            basis,
 283153            lowerY,
 283154            upperY,
 283155            vertices,
 283156            out int vertexCount);
 283157        Vector2d planarStart = new(slabStartCenter.X, slabStartCenter.Z);
 283158        bool found = false;
 283159        Fixed64 best = Fixed64.MaxValue;
 6942160        for (int index = 0; index < constraintCount; index++)
 161        {
 3188162            if (!TryGetExpandedEdgeSweepDistance(
 3188163                    constraints,
 3188164                    constraintCount,
 3188165                    index,
 3188166                    planarStart,
 3188167                    trajectory,
 3188168                    maxDistance,
 3188169                    radius,
 3188170                    out Fixed64 candidate))
 171            {
 172                continue;
 173            }
 269174            best = FixedMath.Min(best, candidate);
 269175            found = true;
 176        }
 177
 4886178        for (int index = 0; index < vertexCount; index++)
 179        {
 2160180            if (!TryGetRationalPointSweepDistance(
 2160181                    vertices[index],
 2160182                    planarStart,
 2160183                    trajectory,
 2160184                    maxDistance,
 2160185                    radius,
 2160186                    out Fixed64 candidate))
 187            {
 188                continue;
 189            }
 190
 11191            best = FixedMath.Min(best, candidate);
 11192            found = true;
 193        }
 194
 283195        distance = found ? best : default;
 283196        return found;
 197    }
 198
 199    internal static Fixed64 GetCircleSlabSeparationLowerBound(
 200        Vector3d center,
 201        FixedQuaternion orientation,
 202        Vector3d halfExtents,
 203        Vector3d slabCenter,
 204        Fixed64 slabHalfThickness,
 205        Fixed64 radius)
 206    {
 9207        WideRationalBasis3d basis = new(orientation);
 9208        Signed192 lowerY = WideArithmetic.SubtractSigned192(
 9209            Signed192.Raw(slabCenter.Y),
 9210            Signed192.Raw(slabHalfThickness));
 9211        Signed192 upperY = WideArithmetic.AddSigned192(
 9212            Signed192.Raw(slabCenter.Y),
 9213            Signed192.Raw(slabHalfThickness));
 9214        Span<SweepPlanarConstraint> constraints =
 9215            stackalloc SweepPlanarConstraint[16];
 9216        if (!TryBuildCircleSlabProjectionConstraints(
 9217                center,
 9218                halfExtents,
 9219                basis,
 9220                lowerY,
 9221                upperY,
 9222                constraints,
 9223                out int count))
 224        {
 2225            return GetCircleSlabVerticalSeparationLowerBound(
 2226                center,
 2227                halfExtents,
 2228                basis,
 2229                lowerY,
 2230                upperY);
 231        }
 232
 7233        Vector2d planarCenter = new(slabCenter.X, slabCenter.Z);
 7234        Fixed64 lowerBound = Fixed64.Zero;
 7235        bool hasPlanarViolation = false;
 7236        bool hasClosestEdgeFeature = false;
 54237        for (int index = 0; index < count; index++)
 238        {
 22239            SweepPlanarConstraint constraint = constraints[index];
 22240            Signed576 violation = WideArithmetic.SubtractSigned576(
 22241                GetSweepProjection(constraint, planarCenter),
 22242                constraint.K);
 22243            if (violation.Sign <= 0)
 244                continue;
 245
 10246            hasPlanarViolation = true;
 10247            Signed576 normalSquared = WideArithmetic.AddSigned576(
 10248                WideArithmetic.MultiplySigned320(
 10249                    constraint.A,
 10250                    constraint.A),
 10251                WideArithmetic.MultiplySigned320(
 10252                    constraint.C,
 10253                    constraint.C));
 10254            Signed576 normalFloor = WideArithmetic.GetFloorSquareRoot(
 10255                Signed704.ExtendValue(normalSquared));
 10256            Signed832 floorSquared =
 10257                WideArithmetic.MultiplySigned576ToSigned832(
 10258                    normalFloor,
 10259                    normalFloor);
 10260            Signed832 remainderSign = WideArithmetic.SubtractSigned832(
 10261                floorSquared,
 10262                Signed832.ExtendValue(normalSquared));
 10263            long ceilingIncrementRaw =
 10264                (long)(remainderSign.Word12 >> 63);
 10265            normalFloor = WideArithmetic.AddSigned576(
 10266                normalFloor,
 10267                Signed576.ExtendValue(
 10268                    Signed320.ExtendValue(
 10269                        Signed192.Signed(
 10270                            ceilingIncrementRaw))));
 271
 10272            Fixed64 axisDistance = Fixed64.GetNonNegativeRawRatioFloor(
 10273                Signed704.ExtendValue(violation),
 10274                Signed704.ExtendValue(normalFloor));
 10275            Fixed64 candidate = axisDistance > radius
 10276                ? axisDistance - radius
 10277                : Fixed64.Zero;
 10278            if (candidate > lowerBound)
 6279                lowerBound = candidate;
 280
 10281            if (IsClosestProjectionOnConstraint(
 10282                    constraints,
 10283                    count,
 10284                    index,
 10285                    planarCenter,
 10286                    violation,
 10287                    Signed320.NarrowValue(normalSquared)))
 288            {
 2289                hasClosestEdgeFeature = true;
 290                // This valid orthogonal projection is the closest point of
 291                // the convex projection. Every remaining half-space distance
 292                // is therefore bounded by the candidate already retained.
 2293                break;
 294            }
 295        }
 296
 7297        if (hasPlanarViolation && !hasClosestEdgeFeature)
 298        {
 4299            Fixed64 vertexDistance =
 4300                GetClosestProjectionVertexDistanceLowerBound(
 4301                    center,
 4302                    halfExtents,
 4303                    basis,
 4304                    lowerY,
 4305                    upperY,
 4306                    planarCenter);
 4307            Fixed64 vertexGap = vertexDistance > radius
 4308                ? vertexDistance - radius
 4309                : Fixed64.Zero;
 4310            if (vertexGap > lowerBound)
 3311                lowerBound = vertexGap;
 312        }
 313
 7314        return lowerBound;
 315    }
 316
 317    private static bool IsClosestProjectionOnConstraint(
 318        ReadOnlySpan<SweepPlanarConstraint> constraints,
 319        int constraintCount,
 320        int constraintIndex,
 321        Vector2d point,
 322        Signed576 violation,
 323        Signed320 normalSquared)
 324    {
 10325        SweepPlanarConstraint constraint = constraints[constraintIndex];
 52326        for (int index = 0; index < constraintCount; index++)
 327        {
 24328            SweepPlanarConstraint candidate = constraints[index];
 24329            Signed576 candidateViolation =
 24330                WideArithmetic.SubtractSigned576(
 24331                    GetSweepProjection(candidate, point),
 24332                    candidate.K);
 24333            Signed320 normalDot = Signed320.NarrowValue(
 24334                WideArithmetic.AddSigned576(
 24335                    WideArithmetic.MultiplySigned320(
 24336                        candidate.A,
 24337                        constraint.A),
 24338                    WideArithmetic.MultiplySigned320(
 24339                        candidate.C,
 24340                        constraint.C)));
 24341            Signed704 projectedViolation =
 24342                WideArithmetic.SubtractSigned704(
 24343                    WideArithmetic.MultiplySigned576ToSigned704(
 24344                        candidateViolation,
 24345                        normalSquared),
 24346                    WideArithmetic.MultiplySigned576ToSigned704(
 24347                        violation,
 24348                        normalDot));
 24349            if (projectedViolation.Sign > 0)
 8350                return false;
 351        }
 352
 2353        return true;
 354    }
 355
 356    private static Fixed64 GetClosestProjectionVertexDistanceLowerBound(
 357        Vector3d center,
 358        Vector3d halfExtents,
 359        WideRationalBasis3d basis,
 360        Signed192 lowerY,
 361        Signed192 upperY,
 362        Vector2d point)
 363    {
 4364        Span<SweepRationalPoint> vertices =
 4365            stackalloc SweepRationalPoint[32];
 4366        BuildCircleSlabProjectionVertices(
 4367            center,
 4368            halfExtents,
 4369            basis,
 4370            lowerY,
 4371            upperY,
 4372            vertices,
 4373            out int vertexCount);
 374        // The caller already proved that the finite box/slab intersection is
 375        // nonempty, so its compact planar projection has at least one vertex.
 4376        RationalPointDistance closest =
 4377            GetRationalPointDistance(vertices[0], point);
 32378        for (int index = 1; index < vertexCount; index++)
 379        {
 12380            RationalPointDistance candidate =
 12381                GetRationalPointDistance(vertices[index], point);
 12382            if (CompareRationalPointDistances(candidate, closest) < 0)
 8383                closest = candidate;
 384        }
 385
 4386        return GetRationalPointDistanceLowerBound(closest);
 387    }
 388
 389    private static RationalPointDistance GetRationalPointDistance(
 390        SweepRationalPoint point,
 391        Vector2d reference)
 392    {
 16393        Signed576 deltaX = WideArithmetic.SubtractSigned576(
 16394            WideArithmetic.MultiplySigned576(
 16395                point.Denominator,
 16396                Signed192.Raw(reference.X)),
 16397            point.X);
 16398        Signed576 deltaZ = WideArithmetic.SubtractSigned576(
 16399            WideArithmetic.MultiplySigned576(
 16400                point.Denominator,
 16401                Signed192.Raw(reference.Y)),
 16402            point.Z);
 16403        Signed832 squaredDistance = WideArithmetic.AddSigned832(
 16404            WideArithmetic.MultiplySigned576ToSigned832(deltaX, deltaX),
 16405            WideArithmetic.MultiplySigned576ToSigned832(deltaZ, deltaZ));
 16406        return new RationalPointDistance(
 16407            point.Denominator,
 16408            squaredDistance);
 409    }
 410
 411    private static int CompareRationalPointDistances(
 412        RationalPointDistance first,
 413        RationalPointDistance second)
 414    {
 12415        Signed832 firstDenominatorSquared =
 12416            WideArithmetic.MultiplySigned576ToSigned832(
 12417                first.Denominator,
 12418                first.Denominator);
 12419        Signed832 secondDenominatorSquared =
 12420            WideArithmetic.MultiplySigned576ToSigned832(
 12421                second.Denominator,
 12422                second.Denominator);
 12423        Span<ulong> firstSquaredMagnitude = stackalloc ulong[13];
 12424        Span<ulong> secondSquaredMagnitude = stackalloc ulong[13];
 12425        Span<ulong> firstDenominatorMagnitude = stackalloc ulong[13];
 12426        Span<ulong> secondDenominatorMagnitude = stackalloc ulong[13];
 12427        WideArithmetic.GetMagnitude(
 12428            first.SquaredDistance,
 12429            firstSquaredMagnitude);
 12430        WideArithmetic.GetMagnitude(
 12431            second.SquaredDistance,
 12432            secondSquaredMagnitude);
 12433        WideArithmetic.GetMagnitude(
 12434            firstDenominatorSquared,
 12435            firstDenominatorMagnitude);
 12436        WideArithmetic.GetMagnitude(
 12437            secondDenominatorSquared,
 12438            secondDenominatorMagnitude);
 12439        Span<ulong> left =
 12440            stackalloc ulong[TriangleSweepMagnitudeWords];
 12441        Span<ulong> right =
 12442            stackalloc ulong[TriangleSweepMagnitudeWords];
 12443        WideArithmetic.MultiplyMagnitudes(
 12444            firstSquaredMagnitude,
 12445            secondDenominatorMagnitude,
 12446            left);
 12447        WideArithmetic.MultiplyMagnitudes(
 12448            secondSquaredMagnitude,
 12449            firstDenominatorMagnitude,
 12450            right);
 12451        return WideArithmetic.CompareMagnitudeEqualLength(left, right);
 452    }
 453
 454    private static Fixed64 GetRationalPointDistanceLowerBound(
 455        RationalPointDistance distance)
 456    {
 4457        long low = 0L;
 4458        long high = Fixed64.MaxValue.m_rawValue;
 256459        while (low < high)
 460        {
 252461            long difference = high - low;
 252462            long middle =
 252463                low + (difference >> 1) + (difference & 1L);
 252464            Signed576 scaledDistance = WideArithmetic.MultiplySigned576(
 252465                distance.Denominator,
 252466                Signed192.Signed(middle));
 252467            Signed832 squaredCandidate =
 252468                WideArithmetic.MultiplySigned576ToSigned832(
 252469                    scaledDistance,
 252470                    scaledDistance);
 252471            if (WideArithmetic.SubtractSigned832(
 252472                    squaredCandidate,
 252473                    distance.SquaredDistance).Sign <= 0)
 474            {
 58475                low = middle;
 476            }
 477            else
 478            {
 194479                high = middle - 1L;
 480            }
 481        }
 482
 4483        return Fixed64.FromRaw(low);
 484    }
 485
 486    private static Fixed64 GetCircleSlabVerticalSeparationLowerBound(
 487        Vector3d center,
 488        Vector3d halfExtents,
 489        WideRationalBasis3d basis,
 490        Signed192 lowerY,
 491        Signed192 upperY)
 492    {
 2493        Signed320 boxRadius = GetExtentNumerator(
 2494            basis.Xy,
 2495            basis.Yy,
 2496            basis.Zy,
 2497            halfExtents);
 2498        Signed320 boxCenter = WideArithmetic.MultiplySigned192(
 2499            Signed192.Raw(center.Y),
 2500            basis.Denominator);
 2501        Signed320 boxMinimum =
 2502            WideArithmetic.SubtractSigned320(boxCenter, boxRadius);
 2503        Signed320 boxMaximum =
 2504            WideArithmetic.AddSigned320(boxCenter, boxRadius);
 2505        Signed320 slabMinimum =
 2506            WideArithmetic.MultiplySigned192(lowerY, basis.Denominator);
 2507        Signed320 slabMaximum =
 2508            WideArithmetic.MultiplySigned192(upperY, basis.Denominator);
 2509        Signed320 gap = CompareSigned(boxMaximum, slabMinimum) < 0
 2510            ? WideArithmetic.SubtractSigned320(slabMinimum, boxMaximum)
 2511            : WideArithmetic.SubtractSigned320(boxMinimum, slabMaximum);
 2512        return Fixed64.GetNonNegativeRawRatioFloor(
 2513            Signed704.ExtendValue(
 2514                Signed576.ExtendValue(gap)),
 2515            Signed704.ExtendValue(
 2516                Signed576.ExtendValue(
 2517                    Signed320.ExtendValue(
 2518                        basis.Denominator))));
 519    }
 520
 521    private static bool TryGetExpandedEdgeSweepDistance(
 522        ReadOnlySpan<SweepPlanarConstraint> constraints,
 523        int constraintCount,
 524        int constraintIndex,
 525        Vector2d start,
 526        in SweepTrajectory trajectory,
 527        Fixed64 maxDistance,
 528        Fixed64 radius,
 529        out Fixed64 distance)
 530    {
 3188531        SweepPlanarConstraint edge = constraints[constraintIndex];
 3188532        Signed576 startViolation = WideArithmetic.SubtractSigned576(
 3188533            GetSweepProjection(edge, start),
 3188534            edge.K);
 3188535        if (startViolation.Sign <= 0)
 536        {
 1867537            distance = default;
 1867538            return false;
 539        }
 540
 1321541        Signed576 normalSquared = WideArithmetic.AddSigned576(
 1321542            WideArithmetic.MultiplySigned320(edge.A, edge.A),
 1321543            WideArithmetic.MultiplySigned320(edge.C, edge.C));
 1321544        Signed320 radiusSquared =
 1321545            WideArithmetic.MultiplySigned192(Signed192.Raw(radius), Signed192.Raw(radius));
 1321546        Signed832 expandedSquared =
 1321547            WideArithmetic.MultiplyNonNegativeToSigned832(
 1321548                Signed832.ExtendValue(
 1321549                    Signed576.ExtendValue(radiusSquared)),
 1321550                Signed320.NarrowValue(normalSquared));
 1321551        Signed832 startSquared =
 1321552            WideArithmetic.MultiplySigned576ToSigned832(
 1321553                startViolation,
 1321554                startViolation);
 1321555        if (WideArithmetic.SubtractSigned832(
 1321556                startSquared,
 1321557                expandedSquared).Sign <= 0)
 558        {
 9559            distance = default;
 9560            return false;
 561        }
 562
 1312563        Signed576 velocity = GetSweepProjection(edge, trajectory);
 1312564        if (velocity.Sign >= 0
 1312565            || CompareExpandedEdgeAt(
 1312566                startViolation,
 1312567                velocity,
 1312568                normalSquared,
 1312569                radius,
 1312570                Signed192.Signed(maxDistance.m_rawValue),
 1312571                trajectory.TimeScale) > 0)
 572        {
 4573            distance = default;
 4574            return false;
 575        }
 576
 1308577        long maxRaw = maxDistance.m_rawValue;
 578        // The public contract has already rejected a zero maximum distance.
 1308579        long high = maxRaw - 1L;
 1308580        if (CompareExpandedEdgeAtHalf(
 1308581                startViolation,
 1308582                velocity,
 1308583                normalSquared,
 1308584                radius,
 1308585                high, trajectory) > 0)
 586        {
 1587            distance = maxDistance;
 588        }
 589        else
 590        {
 1307591            long low = 0L;
 48159592            while (low < high)
 593            {
 46852594                long middle = low + ((high - low) >> 1);
 46852595                if (CompareExpandedEdgeAtHalf(
 46852596                        startViolation,
 46852597                        velocity,
 46852598                        normalSquared,
 46852599                        radius,
 46852600                        middle, trajectory) <= 0)
 601                {
 24768602                    high = middle;
 603                }
 604                else
 605                {
 22084606                    low = middle + 1L;
 607                }
 608            }
 609
 1307610            int midpointComparison = CompareExpandedEdgeAtHalf(
 1307611                startViolation,
 1307612                velocity,
 1307613                normalSquared,
 1307614                radius,
 1307615                low, trajectory);
 1307616            distance = Fixed64.FromRaw(
 1307617                low + GetHalfToEvenIncrement(midpointComparison, low));
 618        }
 619
 1308620        return IsExactEdgeFeatureValid(
 1308621            constraints, constraintCount, constraintIndex, start,
 1308622            trajectory, startViolation, velocity, normalSquared, radius);
 623    }
 624
 625    private static int CompareExpandedEdgeAtHalf(
 626        Signed576 startViolation,
 627        Signed576 velocity,
 628        Signed576 normalSquared,
 629        Fixed64 radius,
 630        long lowerRaw,
 631        in SweepTrajectory trajectory)
 632    {
 49467633        Signed192 lower = Signed192.Signed(lowerRaw);
 49467634        Signed192 midpoint = WideArithmetic.AddSigned192(
 49467635            WideArithmetic.AddSigned192(lower, lower),
 49467636            SweepOneCoefficient);
 49467637        return CompareExpandedEdgeAt(
 49467638            startViolation,
 49467639            velocity,
 49467640            normalSquared,
 49467641            radius,
 49467642            midpoint,
 49467643            trajectory.DoubleTimeScale);
 644    }
 645
 646    private static int CompareExpandedEdgeAt(
 647        Signed576 startViolation,
 648        Signed576 velocity,
 649        Signed576 normalSquared,
 650        Fixed64 radius,
 651        Signed192 timeNumerator,
 652        Signed192 timeDenominator)
 653    {
 50775654        Signed576 left = WideArithmetic.AddSigned576(
 50775655            WideArithmetic.MultiplySigned576(
 50775656                startViolation,
 50775657                timeDenominator),
 50775658            WideArithmetic.MultiplySigned576(
 50775659                velocity,
 50775660                timeNumerator));
 50775661        if (left.Sign <= 0)
 6035662            return left.IsZero && radius == Fixed64.Zero ? 0 : -1;
 663
 44740664        Signed832 leftSquared =
 44740665            WideArithmetic.MultiplySigned576ToSigned832(left, left);
 44740666        Signed320 scaledRadius = WideArithmetic.MultiplySigned192(
 44740667            Signed192.Raw(radius),
 44740668            timeDenominator);
 44740669        Signed832 rightSquared =
 44740670            WideArithmetic.MultiplyNonNegativeToSigned832(
 44740671                Signed832.ExtendValue(
 44740672                    WideArithmetic.MultiplySigned320(
 44740673                        scaledRadius,
 44740674                        scaledRadius)),
 44740675                Signed320.NarrowValue(normalSquared));
 44740676        return WideArithmetic.SubtractSigned832(
 44740677            leftSquared,
 44740678            rightSquared).Sign;
 679    }
 680
 681    private static bool IsExactEdgeFeatureValid(
 682        ReadOnlySpan<SweepPlanarConstraint> constraints,
 683        int constraintCount,
 684        int constraintIndex,
 685        Vector2d start,
 686        in SweepTrajectory trajectory,
 687        Signed576 edgeStartViolation,
 688        Signed576 edgeVelocity,
 689        Signed576 edgeNormalSquared,
 690        Fixed64 radius)
 691    {
 1308692        SweepPlanarConstraint edge = constraints[constraintIndex];
 18158693        for (int index = 0; index < constraintCount; index++)
 694        {
 8810695            SweepPlanarConstraint candidate = constraints[index];
 8810696            Signed576 startViolation = WideArithmetic.SubtractSigned576(GetSweepProjection(candidate, start), candidate.
 8810697            Signed576 velocity = GetSweepProjection(candidate, trajectory);
 8810698            Signed576 normalDot = WideArithmetic.AddSigned576(
 8810699                WideArithmetic.MultiplySigned320(candidate.A, edge.A),
 8810700                WideArithmetic.MultiplySigned320(candidate.C, edge.C));
 8810701            Signed704 radicalCoefficient = WideArithmetic.SubtractSigned704(
 8810702                WideArithmetic.MultiplySigned576ToSigned704(edgeStartViolation, Signed320.NarrowValue(velocity)),
 8810703                WideArithmetic.MultiplySigned576ToSigned704(startViolation, Signed320.NarrowValue(edgeVelocity)));
 8810704            Signed832 rational = WideArithmetic.MultiplySigned832(
 8810705                WideArithmetic.SubtractSigned832(
 8810706                    WideArithmetic.MultiplySigned576ToSigned832(edgeVelocity, normalDot),
 8810707                    WideArithmetic.MultiplySigned576ToSigned832(velocity, edgeNormalSquared)),
 8810708                Signed192.Raw(radius));
 709            // At the exact edge root, the boundary-foot violation has sign
 710            // (F*V-E*W)*sqrt(L) + R*(E*H-F*L); the time denominator cancels.
 711            // Normalized frames bound planar normals to 134 bits, velocities
 712            // to 200, the radical coefficient to 402 and the R-term to 535.
 8810713            if (WideArithmetic.CompareSignedLinearRadicalToZero(
 8810714                    rational, radicalCoefficient, edgeNormalSquared,
 8810715                    Signed320.ExtendValue(SweepOneCoefficient)) > 0)
 1039716                return false;
 717        }
 718
 269719        return true;
 720    }
 721
 722    private static bool TryGetRationalPointSweepDistance(
 723        SweepRationalPoint point,
 724        Vector2d start,
 725        in SweepTrajectory trajectory,
 726        Fixed64 maxDistance,
 727        Fixed64 radius,
 728        out Fixed64 distance)
 729    {
 3725730        Signed576 deltaX = WideArithmetic.SubtractSigned576(
 3725731            WideArithmetic.MultiplySigned576(
 3725732                point.Denominator,
 3725733                Signed192.Raw(start.X)),
 3725734            point.X);
 3725735        Signed576 deltaZ = WideArithmetic.SubtractSigned576(
 3725736            WideArithmetic.MultiplySigned576(
 3725737                point.Denominator,
 3725738                Signed192.Raw(start.Y)),
 3725739            point.Z);
 3725740        Signed576 directionX = WideArithmetic.MultiplySigned576(
 3725741            point.Denominator,
 3725742            trajectory.DirectionX);
 3725743        Signed576 directionZ = WideArithmetic.MultiplySigned576(
 3725744            point.Denominator,
 3725745            trajectory.DirectionZ);
 3725746        Signed576 radiusNumerator = WideArithmetic.MultiplySigned576(
 3725747            point.Denominator,
 3725748            Signed192.Raw(radius));
 3725749        Signed832 constant = WideArithmetic.SubtractSigned832(
 3725750            WideArithmetic.AddSigned832(
 3725751                WideArithmetic.MultiplySigned576ToSigned832(deltaX, deltaX),
 3725752                WideArithmetic.MultiplySigned576ToSigned832(deltaZ, deltaZ)),
 3725753            WideArithmetic.MultiplySigned576ToSigned832(
 3725754                radiusNumerator,
 3725755                radiusNumerator));
 3725756        Signed832 projection = WideArithmetic.AddSigned832(
 3725757            WideArithmetic.MultiplySigned576ToSigned832(
 3725758                deltaX,
 3725759                directionX),
 3725760            WideArithmetic.MultiplySigned576ToSigned832(
 3725761                deltaZ,
 3725762                directionZ));
 763        // Triangle-sweep callers share this vertex solver and can reach it
 764        // without a whole-shape start-overlap precheck.
 3725765        if (constant.Sign <= 0)
 766        {
 9767            distance = Fixed64.Zero;
 9768            return true;
 769        }
 3716770        if (projection.Sign >= 0)
 771        {
 59772            distance = default;
 59773            return false;
 774        }
 775
 3657776        Signed832 directionSquared = WideArithmetic.AddSigned832(
 3657777            WideArithmetic.MultiplySigned576ToSigned832(
 3657778                directionX,
 3657779                directionX),
 3657780            WideArithmetic.MultiplySigned576ToSigned832(
 3657781                directionZ,
 3657782                directionZ));
 3657783        Signed832 negativeProjection =
 3657784            WideArithmetic.SubtractSigned832(default, projection);
 3657785        bool closestBeyondMaximum =
 3657786            WideArithmetic.CompareNonNegativeProducts(
 3657787                negativeProjection,
 3657788                Signed832.ExtendValue(trajectory.TimeScale),
 3657789                directionSquared,
 3657790                Signed832.ExtendValue(Signed192.Signed(maxDistance.m_rawValue))) > 0;
 3657791        if (closestBeyondMaximum)
 792        {
 198793            if (CompareRationalPointAt(
 198794                    deltaX,
 198795                    deltaZ,
 198796                    directionX,
 198797                    directionZ,
 198798                    radiusNumerator,
 198799                    Signed192.Signed(maxDistance.m_rawValue),
 198800                    trajectory.TimeScale, trajectory.IsSegment) > 0)
 801            {
 180802                distance = default;
 180803                return false;
 804            }
 805        }
 3459806        else if (WideArithmetic.CompareNonNegativeProducts(
 3459807                negativeProjection,
 3459808                negativeProjection,
 3459809                directionSquared,
 3459810                constant) < 0)
 811        {
 3089812            distance = default;
 3089813            return false;
 814        }
 815
 816        // Entry is (-B-sqrt(B*B-A*C))*TimeScale/A. Two 832-bit products
 817        // fit 27 limbs; shared quadratic rounding retains exact nearest-even ties.
 818        const int words = 27;
 388819        Span<ulong> values = stackalloc ulong[6 * words];
 388820        Span<int> signs = stackalloc int[6];
 388821        ContactQuadratic entry = ContactQuadratic.At(values, signs, 0, words);
 388822        ContactQuadratic divisor = ContactQuadratic.At(values, signs, 1, words);
 388823        ContactQuadratic work = ContactQuadratic.At(values, signs, 2, words);
 1164824        entry.Clear(); divisor.Clear(); work.Clear();
 776825        WideArithmetic.GetMagnitude(negativeProjection, entry.Rational[..13]); entry.Signs[0] = 1;
 776826        WideArithmetic.GetMagnitude(directionSquared, divisor.Rational[..13]); divisor.Signs[0] = 1;
 388827        WideArithmetic.GetMagnitude(constant, work.Rational[..13]);
 388828        Span<ulong> discriminant = stackalloc ulong[words];
 388829        WideArithmetic.MultiplyMagnitudes(entry.Rational, entry.Rational, discriminant);
 388830        WideArithmetic.MultiplyMagnitudes(divisor.Rational, work.Rational, work.Radical);
 388831        WideArithmetic.SubtractEqualMagnitudes(discriminant, work.Radical, discriminant);
 776832        entry.Radical[0] = 1; entry.Signs[1] = -1;
 388833        ContactQuadratic.Scale(entry, Signed576.ExtendValue(Signed320.ExtendValue(trajectory.TimeScale)), work);
 388834        work.CopyTo(entry);
 835        // Earlier admission bounds this positive entering root by the maximum distance.
 388836        distance = ContactQuadratic.RoundRatio(entry, divisor, discriminant, 0L, maxDistance.m_rawValue);
 388837        return true;
 838    }
 839
 840    private static long GetHalfToEvenIncrement(
 841        int midpointComparison,
 842        long lowerRaw)
 843    {
 1307844        int nonzero =
 1307845            (int)((uint)(midpointComparison | -midpointComparison) >> 31);
 1307846        int zero = nonzero ^ 1;
 1307847        return zero & (lowerRaw & 1L);
 848    }
 849
 850    private static int CompareRationalPointAt(
 851        Signed576 deltaX,
 852        Signed576 deltaZ,
 853        Signed576 directionX,
 854        Signed576 directionZ,
 855        Signed576 radiusNumerator,
 856        Signed192 timeNumerator,
 857        Signed192 timeDenominator,
 858        bool isSegment)
 859    {
 198860        Signed576 x = WideArithmetic.AddSigned576(
 198861            WideArithmetic.MultiplySigned576(deltaX, timeDenominator),
 198862            WideArithmetic.MultiplySigned576(directionX, timeNumerator));
 198863        Signed576 z = WideArithmetic.AddSigned576(
 198864            WideArithmetic.MultiplySigned576(deltaZ, timeDenominator),
 198865            WideArithmetic.MultiplySigned576(directionZ, timeNumerator));
 198866        Signed576 scaledRadius =
 198867            WideArithmetic.MultiplySigned576(
 198868                radiusNumerator,
 198869                timeDenominator);
 198870        if (!isSegment)
 871        {
 110872            return WideArithmetic.SubtractSigned832(
 110873                WideArithmetic.AddSigned832(
 110874                    WideArithmetic.MultiplySigned576ToSigned832(x, x),
 110875                    WideArithmetic.MultiplySigned576ToSigned832(z, z)),
 110876                WideArithmetic.MultiplySigned576ToSigned832(scaledRadius, scaledRadius)).Sign;
 877        }
 878
 879        // A segment-distance denominator can add 30 bits beyond the direction
 880        // scale; retain the full 1152-bit squares before comparing them.
 88881        Span<ulong> xMagnitude = stackalloc ulong[9];
 88882        Span<ulong> zMagnitude = stackalloc ulong[9];
 88883        Span<ulong> radiusMagnitude = stackalloc ulong[9];
 88884        Span<ulong> xSquared = stackalloc ulong[18];
 88885        Span<ulong> zSquared = stackalloc ulong[18];
 88886        Span<ulong> radiusSquared = stackalloc ulong[18];
 88887        WideArithmetic.GetMagnitude(x, xMagnitude);
 88888        WideArithmetic.GetMagnitude(z, zMagnitude);
 88889        WideArithmetic.GetMagnitude(scaledRadius, radiusMagnitude);
 88890        WideArithmetic.MultiplyMagnitudes(xMagnitude, xMagnitude, xSquared);
 88891        WideArithmetic.MultiplyMagnitudes(zMagnitude, zMagnitude, zSquared);
 88892        WideArithmetic.MultiplyMagnitudes(radiusMagnitude, radiusMagnitude, radiusSquared);
 88893        WideArithmetic.AddEqualMagnitudes(xSquared, zSquared, xSquared);
 88894        return WideArithmetic.CompareMagnitudeEqualLength(xSquared, radiusSquared);
 895    }
 896
 897    private static Signed576 GetSweepProjection(SweepPlanarConstraint constraint, in SweepTrajectory trajectory) =>
 10122898        WideArithmetic.AddSigned576(
 10122899            WideArithmetic.MultiplySigned320(constraint.A, Signed320.ExtendValue(trajectory.DirectionX)),
 10122900            WideArithmetic.MultiplySigned320(constraint.C, Signed320.ExtendValue(trajectory.DirectionZ)));
 901
 902    private static Signed576 GetSweepProjection(
 903        SweepPlanarConstraint constraint,
 904        Vector2d point) =>
 12044905        WideArithmetic.AddSigned576(
 12044906            WideArithmetic.MultiplySigned320(
 12044907                constraint.A,
 12044908                Signed320.ExtendValue(Signed192.Raw(point.X))),
 12044909            WideArithmetic.MultiplySigned320(
 12044910                constraint.C,
 12044911                Signed320.ExtendValue(Signed192.Raw(point.Y))));
 912}

/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    {
 7729        WideRationalBasis3d boxBasis = new(boxOrientation);
 7730        WideRationalBasis3d hullBasis = new(hullOrientation);
 7731        WideRationalBasis3d relativeBasis =
 7732            WideRationalBasis3d.CreateRelative(boxBasis, hullBasis);
 7733        Signed320 unit = Signed320.One;
 7734        Span<WideAxis3> boxAxes = stackalloc WideAxis3[3]
 7735        {
 7736            new(unit, default, default),
 7737            new(default, unit, default),
 7738            new(default, default, unit),
 7739        };
 7740        GetRelativeLocalPointNumerators(
 7741            hullOrigin,
 7742            boxCenter,
 7743            boxBasis,
 7744            out Signed192 translationX,
 7745            out Signed192 translationY,
 7746            out Signed192 translationZ);
 7747        var hullTranslation = new WideAxis3(
 7748            WideArithmetic.MultiplySigned192(
 7749                translationX,
 7750                hullBasis.Denominator),
 7751            WideArithmetic.MultiplySigned192(
 7752                translationY,
 7753                hullBasis.Denominator),
 7754            WideArithmetic.MultiplySigned192(
 7755                translationZ,
 7756                hullBasis.Denominator));
 7757        var best = default(WidePointSpanPenetration);
 61058        for (int index = 0; index < boxAxes.Length; index++)
 59        {
 22960            if (!TryKeepPointSpanAxis(
 22961                    boxAxes[index],
 22962                    boxHalfExtents,
 22963                    relativeBasis,
 22964                    hullTranslation,
 22965                    hullLocalOffsets,
 22966                    ref best))
 67            {
 168                contact = default;
 169                return false;
 70            }
 71        }
 72
 7673        for (int index = 0;
 98074            index < triangleVertexIndices.Length;
 90475            index += 3)
 76        {
 90577            Vector3d first = hullLocalOffsets[
 90578                triangleVertexIndices[index]];
 90579            Vector3d second = hullLocalOffsets[
 90580                triangleVertexIndices[index + 1]];
 90581            Vector3d third = hullLocalOffsets[
 90582                triangleVertexIndices[index + 2]];
 90583            WideGeometry.GetDifferenceCrossProduct3D(
 90584                second.X,
 90585                first.X,
 90586                second.Y,
 90587                first.Y,
 90588                second.Z,
 90589                first.Z,
 90590                third.X,
 90591                first.X,
 90592                third.Y,
 90593                first.Y,
 90594                third.Z,
 90595                first.Z,
 90596                out Signed192 normalX,
 90597                out Signed192 normalY,
 90598                out Signed192 normalZ);
 90599            WideAxis3 axis = WideRigidProjection.TransformLocalAxis(
 905100                relativeBasis,
 905101                normalX,
 905102                normalY,
 905103                normalZ);
 905104            if (!TryKeepPointSpanAxis(
 905105                    axis,
 905106                    boxHalfExtents,
 905107                    relativeBasis,
 905108                    hullTranslation,
 905109                    hullLocalOffsets,
 905110                    ref best))
 111            {
 1112                contact = default;
 1113                return false;
 114            }
 115        }
 116
 1926117        for (int index = 0; index < edgeVertexPairs.Length; index += 2)
 118        {
 889119            Vector3d start = hullLocalOffsets[edgeVertexPairs[index]];
 889120            Vector3d end = hullLocalOffsets[edgeVertexPairs[index + 1]];
 889121            WideAxis3 edge = WideRigidProjection.TransformLocalAxis(
 889122                relativeBasis,
 889123                WideArithmetic.SubtractSigned192(
 889124                    Signed192.Raw(end.X),
 889125                    Signed192.Raw(start.X)),
 889126                WideArithmetic.SubtractSigned192(
 889127                    Signed192.Raw(end.Y),
 889128                    Signed192.Raw(start.Y)),
 889129                WideArithmetic.SubtractSigned192(
 889130                    Signed192.Raw(end.Z),
 889131                    Signed192.Raw(start.Z)));
 889132            for (int axisIndex = 0;
 3554133                axisIndex < boxAxes.Length;
 2665134                axisIndex++)
 135            {
 2666136                if (!TryKeepPointSpanAxis(
 2666137                        WideAxis3.Cross(boxAxes[axisIndex], edge),
 2666138                        boxHalfExtents,
 2666139                        relativeBasis,
 2666140                        hullTranslation,
 2666141                        hullLocalOffsets,
 2666142                        ref best))
 143                {
 1144                    contact = default;
 1145                    return false;
 146                }
 147            }
 148        }
 149
 74150        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 74151        WideRigidProjection.TransformLocalAxis(
 74152            boxBasis,
 74153            orientedAxis,
 74154            out Signed576 worldX,
 74155            out Signed576 worldY,
 74156            out Signed576 worldZ);
 74157        Vector3d normal = WideNormalization.GetNormalized(
 74158            worldX,
 74159            worldY,
 74160            worldZ);
 74161        Vector3d hullLocalPoint = GetHullSupportLocalPoint(
 74162            relativeBasis,
 74163            hullLocalOffsets,
 74164            orientedAxis,
 74165            maximize: false);
 166
 74167        Vector3d boxLocalPoint = GetLocalSupportPoint(
 74168            normal,
 74169            boxOrientation,
 74170            boxHalfExtents);
 74171        Fixed64 depth = best.GetRoundedDepth(out bool depthIsClamped);
 74172        contact = new FixedContactAnchors(
 74173            new FixedPointAnchor(
 74174                boxCenter,
 74175                boxOrientation,
 74176                boxLocalPoint),
 74177            new FixedPointAnchor(
 74178                hullOrigin,
 74179                hullOrientation,
 74180                hullLocalPoint),
 74181            normal,
 74182            depth,
 74183            depthIsClamped);
 74184        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    {
 3800195        if (axis.IsZero)
 52196            return true;
 197
 3748198        WideRigidProjection.GetLocalAxisProjections(
 3748199            axis,
 3748200            relativeBasis,
 3748201            out Signed576 localAxisX,
 3748202            out Signed576 localAxisY,
 3748203            out Signed576 localAxisZ);
 3748204        Signed576 minimum = WideRigidProjection.GetLocalOffsetProjection(
 3748205            hullLocalOffsets[0],
 3748206            localAxisX,
 3748207            localAxisY,
 3748208            localAxisZ);
 3748209        Signed576 maximum = minimum;
 59968210        for (int index = 1; index < hullLocalOffsets.Length; index++)
 211        {
 26236212            WideRigidProjection.IncludeProjection(
 26236213                WideRigidProjection.GetLocalOffsetProjection(
 26236214                    hullLocalOffsets[index],
 26236215                    localAxisX,
 26236216                    localAxisY,
 26236217                    localAxisZ),
 26236218                ref minimum,
 26236219                ref maximum);
 220        }
 221
 3748222        Signed576 originProjection = WideAxis3.Dot(
 3748223            axis,
 3748224            hullTranslation);
 3748225        minimum = WideArithmetic.AddSigned576(originProjection, minimum);
 3748226        maximum = WideArithmetic.AddSigned576(originProjection, maximum);
 3748227        Signed576 boxRadius = WideArithmetic.MultiplySigned576(
 3748228            GetLocalBoxProjectionRadiusNumerator(axis, boxHalfExtents),
 3748229            relativeBasis.Denominator);
 3748230        Signed576 pushBoxNegative = WideArithmetic.SubtractSigned576(
 3748231            boxRadius,
 3748232            minimum);
 3748233        Signed576 pushBoxPositive = WideArithmetic.AddSigned576(
 3748234            maximum,
 3748235            boxRadius);
 3748236        if (pushBoxNegative.Sign < 0 || pushBoxPositive.Sign < 0)
 3237            return false;
 238
 3745239        bool negate =
 3745240            CompareSigned(pushBoxPositive, pushBoxNegative) < 0;
 3745241        Signed576 overlap = negate
 3745242            ? pushBoxPositive
 3745243            : pushBoxNegative;
 3745244        Signed320 commonDenominator =
 3745245            Signed320.ExtendValue(relativeBasis.Denominator);
 3745246        Signed576 squaredAxisLength = axis.SquaredLength;
 3745247        if (best.ShouldReplace(
 3745248            overlap,
 3745249            squaredAxisLength,
 3745250            commonDenominator))
 251        {
 146252            best = new WidePointSpanPenetration(
 146253                axis,
 146254                negate,
 146255                overlap,
 146256                squaredAxisLength,
 146257                commonDenominator);
 258        }
 3745259        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    {
 12734        WideRationalBasis3d hullBasis = new(hullRotation);
 12735        GetRotatedLocalAxisNumerators(
 12736            capsuleRotation,
 12737            capsuleLocalAxisDirection,
 12738            out Signed192 capsuleAxisX,
 12739            out Signed192 capsuleAxisY,
 12740            out Signed192 capsuleAxisZ,
 12741            out Signed192 capsuleAxisDenominator);
 12742        var capsuleAxis = new WideAxis3(
 12743            Signed320.ExtendValue(capsuleAxisX),
 12744            Signed320.ExtendValue(capsuleAxisY),
 12745            Signed320.ExtendValue(capsuleAxisZ));
 46
 12747        if (!TryFindHullCapsuleCandidate(
 12748                hullOrigin,
 12749                hullRotation,
 12750                hullBasis,
 12751                hullLocalPoints,
 12752                triangleVertexIndices,
 12753                edgeVertexPairs,
 12754                capsuleCenter,
 12755                capsuleAxis,
 12756                capsuleAxisDenominator,
 12757                capsuleAxisLength,
 12758                capsuleRadius,
 12759                strict: false,
 12760                out HullCapsuleCandidate best))
 61        {
 2962            contact = default;
 2963            return false;
 64        }
 65
 9866        Span<ulong> rational =
 9867            stackalloc ulong[HullCapsuleMagnitudeWords];
 9868        Span<ulong> squaredAxisLength =
 9869            stackalloc ulong[HullCapsuleMagnitudeWords];
 9870        _ = EvaluateHullCapsuleCandidate(
 9871            best,
 9872            hullOrigin,
 9873            hullBasis,
 9874            hullLocalPoints,
 9875            triangleVertexIndices,
 9876            edgeVertexPairs,
 9877            capsuleCenter,
 9878            capsuleAxis,
 9879            capsuleAxisDenominator,
 9880            capsuleAxisLength,
 9881            capsuleRadius,
 9882            rational,
 9883            out int rationalSign,
 9884            squaredAxisLength,
 9885            out CapsuleAxis3 axis,
 9886            out bool negate,
 9887            out Signed192 commonDenominator);
 9888        CapsuleAxis3 orientedAxis = negate ? -axis : axis;
 9889        Vector3d normal = WideNormalization.GetNormalized(
 9890            orientedAxis.X,
 9891            orientedAxis.Y,
 9892            orientedAxis.Z);
 9893        int capsuleAxialSign = -GetCapsuleAxisProjection(
 9894            orientedAxis,
 9895            capsuleAxis).Sign;
 9896        FixedPointAnchor capsuleAnchor =
 9897            WideGeometry.GetCenteredCapsuleSupportAnchor(
 9898                capsuleCenter,
 9899                capsuleRotation,
 98100                capsuleLocalAxisDirection,
 98101                capsuleAxisLength,
 98102                capsuleRadius,
 98103                -normal,
 98104                capsuleAxialSign);
 98105        FixedPointAnchor hullAnchor =
 98106            GetMatchedHullCapsuleSupportAnchor(
 98107                hullOrigin,
 98108                hullRotation,
 98109                hullBasis,
 98110                hullLocalPoints,
 98111                triangleVertexIndices,
 98112                edgeVertexPairs,
 98113                orientedAxis,
 98114                capsuleAnchor,
 98115                capsuleCenter, capsuleRotation, capsuleLocalAxisDirection,
 98116                capsuleAxisLength, capsuleRadius, normal,
 98117                capsuleAxialSign == 0 && capsuleAxisLength > Fixed64.Zero,
 98118                out capsuleAnchor);
 98119        GetHullCapsuleDepth(
 98120            rational,
 98121            rationalSign,
 98122            squaredAxisLength,
 98123            commonDenominator,
 98124            capsuleRadius,
 98125            out Fixed64 depth,
 98126            out bool depthIsClamped);
 98127        contact = new FixedContactAnchors(
 98128            hullAnchor,
 98129            capsuleAnchor,
 98130            normal,
 98131            depth,
 98132            depthIsClamped);
 98133        return true;
 134    }
 135
 136    /// <summary>
 137    /// Tests positive overlap against every exact hull-capsule separating-axis
 138    /// candidate without rounding depth or constructing contact witnesses.
 139    /// Inputs have the same admitted geometry contract as the contact kernel.
 140    /// A zero-length capsule is a sphere; tangency is not positive overlap.
 141    /// </summary>
 142    internal static bool DoesConvexHullCenteredCapsuleStrictlyOverlap(
 143        Vector3d hullOrigin,
 144        FixedQuaternion hullRotation,
 145        ReadOnlySpan<Vector3d> hullLocalPoints,
 146        ReadOnlySpan<int> triangleVertexIndices,
 147        ReadOnlySpan<int> edgeVertexPairs,
 148        Vector3d capsuleCenter,
 149        FixedQuaternion capsuleRotation,
 150        Vector3d capsuleLocalAxisDirection,
 151        Fixed64 capsuleAxisLength,
 152        Fixed64 capsuleRadius)
 153    {
 66154        WideRationalBasis3d hullBasis = new(hullRotation);
 66155        GetRotatedLocalAxisNumerators(
 66156            capsuleRotation,
 66157            capsuleLocalAxisDirection,
 66158            out Signed192 capsuleAxisX,
 66159            out Signed192 capsuleAxisY,
 66160            out Signed192 capsuleAxisZ,
 66161            out Signed192 capsuleAxisDenominator);
 66162        var capsuleAxis = new WideAxis3(
 66163            Signed320.ExtendValue(capsuleAxisX),
 66164            Signed320.ExtendValue(capsuleAxisY),
 66165            Signed320.ExtendValue(capsuleAxisZ));
 66166        return TryFindHullCapsuleCandidate(
 66167            hullOrigin,
 66168            hullRotation,
 66169            hullBasis,
 66170            hullLocalPoints,
 66171            triangleVertexIndices,
 66172            edgeVertexPairs,
 66173            capsuleCenter,
 66174            capsuleAxis,
 66175            capsuleAxisDenominator,
 66176            capsuleAxisLength,
 66177            capsuleRadius,
 66178            strict: true,
 66179            out _);
 180    }
 181
 182    private static bool TryFindHullCapsuleCandidate(
 183        Vector3d hullOrigin,
 184        FixedQuaternion hullRotation,
 185        WideRationalBasis3d hullBasis,
 186        ReadOnlySpan<Vector3d> hullLocalPoints,
 187        ReadOnlySpan<int> triangleVertexIndices,
 188        ReadOnlySpan<int> edgeVertexPairs,
 189        Vector3d capsuleCenter,
 190        WideAxis3 capsuleAxis,
 191        Signed192 capsuleAxisDenominator,
 192        Fixed64 capsuleAxisLength,
 193        Fixed64 capsuleRadius,
 194        bool strict,
 195        out HullCapsuleCandidate best)
 196    {
 193197        best = default;
 193198        bool hasBest = false;
 193199        Span<ulong> bestRational = stackalloc ulong[HullCapsuleMagnitudeWords];
 193200        Span<ulong> bestSquaredAxisLength = stackalloc ulong[HullCapsuleMagnitudeWords];
 193201        int bestRationalSign = 0;
 193202        WideAxis3 previousFaceNormal = default;
 193203        for (int index = 0;
 1973204            index < triangleVertexIndices.Length;
 1780205            index += 3)
 206        {
 1806207            WideAxis3 faceNormal = GetHullTriangleNormal(
 1806208                hullLocalPoints, triangleVertexIndices, index);
 209            // Parallel local normals define the same whole-hull slab, even
 210            // with opposite winding. Preserve the first authored face on ties.
 211            // Raw-coordinate triangle normals need at most 130 signed bits;
 212            // their cross products therefore fit Signed320 exactly.
 1806213            if (!faceNormal.IsZero && !previousFaceNormal.IsZero
 1806214                && WideAxis3.Cross(previousFaceNormal, faceNormal).IsZero)
 215            {
 216                continue;
 217            }
 508218            previousFaceNormal = faceNormal;
 508219            if (!TryKeepHullCapsuleCandidate(
 508220                    new HullCapsuleCandidate(
 508221                        HullCapsuleCandidateKind.Face,
 508222                        index,
 508223                        0),
 508224                    hullOrigin,
 508225                    hullBasis,
 508226                    hullLocalPoints,
 508227                    triangleVertexIndices,
 508228                    edgeVertexPairs,
 508229                    capsuleCenter,
 508230                    capsuleAxis,
 508231                    capsuleAxisDenominator,
 508232                    capsuleAxisLength,
 508233                    capsuleRadius,
 508234                    ref best,
 508235                    ref hasBest,
 508236                    bestRational,
 508237                    ref bestRationalSign,
 508238                    bestSquaredAxisLength,
 508239                    strict))
 240            {
 26241                return false;
 242            }
 243        }
 244
 167245        if (capsuleAxisLength == Fixed64.Zero && hasBest)
 246        {
 247            // A positive minimum face margin puts the center inside the hull.
 248            // Its nearest facet is the sphere's minimum exit; strict queries
 249            // retain only the last face and therefore cannot use this proof.
 46250            if (!strict && bestRationalSign > 0)
 6251                return true;
 252
 40253            if (!strict)
 254            {
 27255                _ = EvaluateHullCapsuleCandidate(best, hullOrigin, hullBasis,
 27256                    hullLocalPoints, triangleVertexIndices, edgeVertexPairs,
 27257                    capsuleCenter, capsuleAxis, capsuleAxisDenominator,
 27258                    capsuleAxisLength, capsuleRadius, bestRational,
 27259                    out bestRationalSign, bestSquaredAxisLength,
 27260                    out CapsuleAxis3 faceAxis, out bool negate, out _);
 27261                if (ContainsHullSphereSupportProjection(hullOrigin, hullRotation,
 27262                        hullBasis, hullLocalPoints, triangleVertexIndices,
 27263                        negate ? -faceAxis : faceAxis, capsuleCenter))
 12264                    return true;
 265            }
 266
 267            // For a sphere, a closest face-interior point is represented by
 268            // the face axes. Otherwise the closest finite edge or vertex
 269            // supplies the remaining radial axis. Keep the old degenerate-
 270            // hull path when no nondegenerate face supplies a plane normal.
 28271            if (!TryGetClosestHullSphereFeature(
 28272                    hullOrigin, hullBasis, hullLocalPoints, edgeVertexPairs,
 28273                    capsuleCenter, capsuleAxis, capsuleAxisDenominator,
 28274                    out HullCapsuleCandidate closest))
 275            {
 2276                return hasBest;
 277            }
 26278            return TryKeepHullCapsuleCandidate(
 26279                closest,
 26280                hullOrigin,
 26281                hullBasis,
 26282                hullLocalPoints,
 26283                triangleVertexIndices,
 26284                edgeVertexPairs,
 26285                capsuleCenter,
 26286                capsuleAxis,
 26287                capsuleAxisDenominator,
 26288                capsuleAxisLength,
 26289                capsuleRadius,
 26290                ref best,
 26291                ref hasBest,
 26292                bestRational,
 26293                ref bestRationalSign,
 26294                bestSquaredAxisLength,
 26295                strict);
 296        }
 297
 2796298        for (int index = 0; index < edgeVertexPairs.Length; index += 2)
 299        {
 1282300            if (!TryKeepHullCapsuleCandidate(
 1282301                    new HullCapsuleCandidate(
 1282302                        HullCapsuleCandidateKind.EdgeCross,
 1282303                        index,
 1282304                        0),
 1282305                    hullOrigin,
 1282306                    hullBasis,
 1282307                    hullLocalPoints,
 1282308                    triangleVertexIndices,
 1282309                    edgeVertexPairs,
 1282310                    capsuleCenter,
 1282311                    capsuleAxis,
 1282312                    capsuleAxisDenominator,
 1282313                    capsuleAxisLength,
 1282314                    capsuleRadius,
 1282315                    ref best,
 1282316                    ref hasBest,
 1282317                    bestRational,
 1282318                    ref bestRationalSign,
 1282319                    bestSquaredAxisLength,
 1282320                    strict))
 321            {
 5322                return false;
 323            }
 324        }
 325
 1762326        for (int index = 0; index < hullLocalPoints.Length; index++)
 327        {
 780328            if (!TryKeepHullCapsuleCandidate(
 780329                    new HullCapsuleCandidate(
 780330                        HullCapsuleCandidateKind.VertexCore,
 780331                        index,
 780332                        0),
 780333                    hullOrigin,
 780334                    hullBasis,
 780335                    hullLocalPoints,
 780336                    triangleVertexIndices,
 780337                    edgeVertexPairs,
 780338                    capsuleCenter,
 780339                    capsuleAxis,
 780340                    capsuleAxisDenominator,
 780341                    capsuleAxisLength,
 780342                    capsuleRadius,
 780343                    ref best,
 780344                    ref hasBest,
 780345                    bestRational,
 780346                    ref bestRationalSign,
 780347                    bestSquaredAxisLength,
 780348                    strict))
 349            {
 15350                return false;
 351            }
 352        }
 353
 2376354        for (int index = 0; index < edgeVertexPairs.Length; index += 2)
 355        {
 1088356            for (int endpointSign = -1;
 3262357                endpointSign <= 1;
 2174358                endpointSign += 2)
 359            {
 2175360                if (!TryKeepHullCapsuleCandidate(
 2175361                        new HullCapsuleCandidate(
 2175362                            HullCapsuleCandidateKind.EndpointEdge,
 2175363                            index,
 2175364                            endpointSign),
 2175365                        hullOrigin,
 2175366                        hullBasis,
 2175367                        hullLocalPoints,
 2175368                        triangleVertexIndices,
 2175369                        edgeVertexPairs,
 2175370                        capsuleCenter,
 2175371                        capsuleAxis,
 2175372                        capsuleAxisDenominator,
 2175373                        capsuleAxisLength,
 2175374                        capsuleRadius,
 2175375                        ref best,
 2175376                        ref hasBest,
 2175377                        bestRational,
 2175378                        ref bestRationalSign,
 2175379                        bestSquaredAxisLength,
 2175380                        strict))
 381                {
 1382                    return false;
 383                }
 384            }
 385        }
 386
 100387        return hasBest;
 388    }
 389
 390    private static bool TryGetClosestHullSphereFeature(
 391        Vector3d hullOrigin,
 392        WideRationalBasis3d hullBasis,
 393        ReadOnlySpan<Vector3d> points,
 394        ReadOnlySpan<int> edgeVertexPairs,
 395        Vector3d sphereCenter,
 396        WideAxis3 capsuleAxis,
 397        Signed192 capsuleAxisDenominator,
 398        out HullCapsuleCandidate closest)
 399    {
 28400        closest = default;
 28401        bool hasClosest = false;
 28402        Span<ulong> denominator = stackalloc ulong[HullCapsuleMagnitudeWords];
 28403        Span<ulong> squaredRay = stackalloc ulong[HullCapsuleMagnitudeWords];
 28404        Span<ulong> bestDenominator = stackalloc ulong[HullCapsuleMagnitudeWords];
 28405        Span<ulong> bestSquaredRay = stackalloc ulong[HullCapsuleMagnitudeWords];
 406        // All zero-core rays share the same positive rigid-frame scale.
 407        // An interior-edge ray also retains |edge|^2: maximizing this
 408        // denominator / |ray| selects the nearest exact feature without
 409        // rounding witnesses. Existing span comparisons retain the full
 410        // endpoint/edge product widths even at unrepresentable world points.
 162411        for (int featureKind = 0; featureKind < 2; featureKind++)
 412        {
 55413            bool isVertex = featureKind == 0;
 55414            int featureCount = isVertex ? points.Length : edgeVertexPairs.Length / 2;
 994415            for (int index = 0; index < featureCount; index++)
 416            {
 444417                int featureIndex = isVertex ? index : index * 2;
 444418                var candidate = new HullCapsuleCandidate(
 444419                    isVertex ? HullCapsuleCandidateKind.VertexCore
 444420                        : HullCapsuleCandidateKind.EndpointEdge,
 444421                    featureIndex,
 444422                    isVertex ? 0 : -1);
 444423                Signed576 distanceDenominator =
 444424                    Signed576.ExtendValue(Signed320.ExtendValue(Signed192.Signed(1L)));
 444425                CapsuleAxis3 ray = isVertex
 444426                    ? ToCapsuleAxis(GetCornerToAxisEndpointAxis3D(
 444427                        hullOrigin, sphereCenter, hullBasis, points[index],
 444428                        capsuleAxis, capsuleAxisDenominator, Fixed64.Zero, 0))
 444429                    : GetCapsuleEndpointToHullEdgeAxis(
 444430                        hullOrigin, sphereCenter, hullBasis,
 444431                        points[edgeVertexPairs[featureIndex]],
 444432                        points[edgeVertexPairs[featureIndex + 1]],
 444433                        capsuleAxis, capsuleAxisDenominator, Fixed64.Zero, -1,
 444434                        out distanceDenominator);
 435                // At distance zero no radial direction is defined; retain
 436                // the admitted face constraints instead of dividing by zero.
 444437                if (ray.IsZero)
 2438                    return false;
 442439                GetHullCapsuleMagnitude(distanceDenominator, denominator);
 442440                BuildHullCapsuleAxisSquared(ray, squaredRay);
 442441                if (!hasClosest || WideArithmetic.CompareSignedNormalizedMagnitudes(
 442442                        denominator, 1, squaredRay,
 442443                        bestDenominator, 1, bestSquaredRay) > 0)
 444                {
 87445                    closest = candidate;
 87446                    hasClosest = true;
 87447                    denominator.CopyTo(bestDenominator);
 87448                    squaredRay.CopyTo(bestSquaredRay);
 449                }
 450            }
 451        }
 26452        return hasClosest;
 453    }
 454
 455    private static bool TryKeepHullCapsuleCandidate(
 456        HullCapsuleCandidate candidate,
 457        Vector3d hullOrigin,
 458        WideRationalBasis3d hullBasis,
 459        ReadOnlySpan<Vector3d> hullLocalPoints,
 460        ReadOnlySpan<int> triangleVertexIndices,
 461        ReadOnlySpan<int> edgeVertexPairs,
 462        Vector3d capsuleCenter,
 463        WideAxis3 capsuleAxis,
 464        Signed192 capsuleAxisDenominator,
 465        Fixed64 capsuleAxisLength,
 466        Fixed64 capsuleRadius,
 467        ref HullCapsuleCandidate best,
 468        ref bool hasBest,
 469        Span<ulong> bestRational,
 470        ref int bestRationalSign,
 471        Span<ulong> bestSquaredAxisLength,
 472        bool strict)
 473    {
 4771474        Span<ulong> rational =
 4771475            stackalloc ulong[HullCapsuleMagnitudeWords];
 4771476        Span<ulong> squaredAxisLength =
 4771477            stackalloc ulong[HullCapsuleMagnitudeWords];
 4771478        int status = EvaluateHullCapsuleCandidate(
 4771479            candidate,
 4771480            hullOrigin,
 4771481            hullBasis,
 4771482            hullLocalPoints,
 4771483            triangleVertexIndices,
 4771484            edgeVertexPairs,
 4771485            capsuleCenter,
 4771486            capsuleAxis,
 4771487            capsuleAxisDenominator,
 4771488            capsuleAxisLength,
 4771489            capsuleRadius,
 4771490            rational,
 4771491            out int rationalSign,
 4771492            squaredAxisLength,
 4771493            out _,
 4771494            out _,
 4771495            out _,
 4771496            strict);
 4771497        if (status < 0)
 54498            return false;
 4717499        if (status == 0)
 351500            return true;
 501        // The winning exact metric does not change until another axis wins.
 502        // Retain it rather than projecting the whole hull again on each comparison.
 4366503        if (strict || !hasBest || WideArithmetic.CompareSignedNormalizedMagnitudes(
 4366504                rational,
 4366505                rationalSign,
 4366506                squaredAxisLength,
 4366507                bestRational,
 4366508                bestRationalSign,
 4366509                bestSquaredAxisLength) < 0)
 510        {
 1626511            best = candidate;
 1626512            hasBest = true;
 1626513            rational.CopyTo(bestRational);
 1626514            bestRationalSign = rationalSign;
 1626515            squaredAxisLength.CopyTo(bestSquaredAxisLength);
 516        }
 4366517        return true;
 518    }
 519
 520    // Returns -1 for separation, 0 for a degenerate axis, and 1 for overlap.
 521    private static int EvaluateHullCapsuleCandidate(
 522        HullCapsuleCandidate candidate,
 523        Vector3d hullOrigin,
 524        WideRationalBasis3d hullBasis,
 525        ReadOnlySpan<Vector3d> hullLocalPoints,
 526        ReadOnlySpan<int> triangleVertexIndices,
 527        ReadOnlySpan<int> edgeVertexPairs,
 528        Vector3d capsuleCenter,
 529        WideAxis3 capsuleAxis,
 530        Signed192 capsuleAxisDenominator,
 531        Fixed64 capsuleAxisLength,
 532        Fixed64 capsuleRadius,
 533        Span<ulong> rational,
 534        out int rationalSign,
 535        Span<ulong> squaredAxisLength,
 536        out CapsuleAxis3 axis,
 537        out bool negate,
 538        out Signed192 commonDenominator,
 539        bool strict = false)
 540    {
 4896541        axis = BuildHullCapsuleCandidateAxis(
 4896542            candidate,
 4896543            hullOrigin,
 4896544            hullBasis,
 4896545            hullLocalPoints,
 4896546            triangleVertexIndices,
 4896547            edgeVertexPairs,
 4896548            capsuleCenter,
 4896549            capsuleAxis,
 4896550            capsuleAxisDenominator,
 4896551            capsuleAxisLength);
 4896552        rational.Clear();
 4896553        squaredAxisLength.Clear();
 4896554        rationalSign = 0;
 4896555        negate = false;
 4896556        commonDenominator = default;
 4896557        if (axis.IsZero)
 351558            return 0;
 559
 560        // Axis magnitude has no geometric meaning. Remove common rational
 561        // frame scale before projection; retain the original full-width axis
 562        // when its components exceed the existing common-scale reducer.
 4545563        if (Signed320.TryNarrowSigned(axis.X, out Signed320 axisX)
 4545564            && Signed320.TryNarrowSigned(axis.Y, out Signed320 axisY)
 4545565            && Signed320.TryNarrowSigned(axis.Z, out Signed320 axisZ))
 566        {
 4370567            Span<Signed320> components = stackalloc Signed320[3] { axisX, axisY, axisZ };
 4370568            WideArithmetic.ReduceCommonScale(components);
 4370569            axis = ToCapsuleAxis(new WideAxis3(components[0], components[1], components[2]));
 570        }
 571
 4545572        BuildHullCapsuleAxisSquared(axis, squaredAxisLength);
 4545573        Span<ulong> minimum =
 4545574            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545575        Span<ulong> maximum =
 4545576            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545577        GetHullCapsuleProjectionInterval(
 4545578            hullLocalPoints,
 4545579            hullBasis,
 4545580            axis,
 4545581            minimum,
 4545582            out int minimumSign,
 4545583            maximum,
 4545584            out int maximumSign);
 585
 4545586        Signed704 centerProjection = GetHullCapsuleCenterProjection(
 4545587            capsuleCenter,
 4545588            hullOrigin,
 4545589            axis);
 4545590        Span<ulong> centerMagnitude =
 4545591            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545592        centerMagnitude.Clear();
 4545593        GetHullCapsuleMagnitude(
 4545594            centerProjection,
 4545595            centerMagnitude);
 4545596        Span<ulong> hullDenominatorMagnitude =
 4545597            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545598        GetHullCapsuleMagnitude(
 4545599            hullBasis.Denominator,
 4545600            hullDenominatorMagnitude);
 4545601        Span<ulong> scaledCenter =
 4545602            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545603        WideArithmetic.MultiplyMagnitudes(
 4545604            centerMagnitude,
 4545605            hullDenominatorMagnitude,
 4545606            scaledCenter);
 607
 4545608        Span<ulong> positive =
 4545609            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545610        CombineHullCapsuleSignedMagnitudes(
 4545611            maximum,
 4545612            maximumSign,
 4545613            scaledCenter,
 4545614            -centerProjection.Sign,
 4545615            positive,
 4545616            out int positiveSign);
 4545617        Span<ulong> negative =
 4545618            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545619        CombineHullCapsuleSignedMagnitudes(
 4545620            scaledCenter,
 4545621            centerProjection.Sign,
 4545622            minimum,
 4545623            -minimumSign,
 4545624            negative,
 4545625            out int negativeSign);
 626
 4545627        Signed320 baseScale = WideArithmetic.MultiplySigned192(
 4545628            capsuleAxisDenominator,
 4545629            Signed192.Raw(Fixed64.Two));
 4545630        MultiplyHullCapsuleMagnitude(
 4545631            positive,
 4545632            baseScale,
 4545633            positive);
 4545634        MultiplyHullCapsuleMagnitude(
 4545635            negative,
 4545636            baseScale,
 4545637            negative);
 638
 4545639        Signed704 alignment =
 4545640            GetCapsuleAxisProjection(axis, capsuleAxis);
 4545641        Span<ulong> axial =
 4545642            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545643        axial.Clear();
 4545644        GetHullCapsuleMagnitude(alignment, axial);
 4545645        MultiplyHullCapsuleMagnitude(
 4545646            axial,
 4545647            Signed192.Raw(capsuleAxisLength),
 4545648            axial);
 4545649        MultiplyHullCapsuleMagnitude(
 4545650            axial,
 4545651            hullBasis.Denominator,
 4545652            axial);
 4545653        CombineHullCapsuleSignedMagnitudes(
 4545654            positive,
 4545655            positiveSign,
 4545656            axial,
 4545657            1,
 4545658            positive,
 4545659            out positiveSign);
 4545660        CombineHullCapsuleSignedMagnitudes(
 4545661            negative,
 4545662            negativeSign,
 4545663            axial,
 4545664            1,
 4545665            negative,
 4545666            out negativeSign);
 667
 4545668        int directionComparison =
 4545669            CompareHullCapsuleSignedMagnitudes(
 4545670                negative,
 4545671                negativeSign,
 4545672                positive,
 4545673                positiveSign);
 4545674        negate = directionComparison < 0;
 4545675        ReadOnlySpan<ulong> selected =
 4545676            negate ? negative : positive;
 4545677        rationalSign = negate ? negativeSign : positiveSign;
 4545678        selected.CopyTo(rational);
 679
 4545680        Signed576 commonWide = WideArithmetic.MultiplySigned576(
 4545681            Signed576.ExtendValue(
 4545682                WideArithmetic.MultiplySigned192(
 4545683                    hullBasis.Denominator,
 4545684                    capsuleAxisDenominator)),
 4545685            Signed192.Raw(Fixed64.Two));
 4545686        _ = Signed192.TryNarrowSigned(
 4545687            commonWide,
 4545688            out commonDenominator);
 4545689        Signed320 radialCoefficient =
 4545690            WideArithmetic.MultiplySigned192(
 4545691                commonDenominator,
 4545692                Signed192.Raw(capsuleRadius));
 4545693        Span<ulong> coefficient =
 4545694            stackalloc ulong[HullCapsuleMagnitudeWords];
 4545695        GetHullCapsuleMagnitude(
 4545696            radialCoefficient,
 4545697            coefficient);
 4545698        int overlapSign = WideArithmetic.GetSignedMagnitudeAndSquareRootSign(
 4545699                rational,
 4545700                rationalSign,
 4545701                coefficient,
 4545702                radialCoefficient.Sign,
 4545703                squaredAxisLength);
 4545704        return overlapSign < 0 || (overlapSign == 0 && strict)
 4545705            ? -1
 4545706            : 1;
 707    }
 708
 709    private static WideAxis3 GetHullTriangleNormal(
 710        ReadOnlySpan<Vector3d> points,
 711        ReadOnlySpan<int> triangleVertexIndices,
 712        int index)
 713    {
 2833714        Vector3d first = points[
 2833715            triangleVertexIndices[index]];
 2833716        Vector3d second = points[
 2833717            triangleVertexIndices[index + 1]];
 2833718        Vector3d third = points[
 2833719            triangleVertexIndices[index + 2]];
 2833720        WideGeometry.GetDifferenceCrossProduct3D(
 2833721            second.X,
 2833722            first.X,
 2833723            second.Y,
 2833724            first.Y,
 2833725            second.Z,
 2833726            first.Z,
 2833727            third.X,
 2833728            first.X,
 2833729            third.Y,
 2833730            first.Y,
 2833731            third.Z,
 2833732            first.Z,
 2833733            out Signed192 normalX,
 2833734            out Signed192 normalY,
 2833735            out Signed192 normalZ);
 2833736        return new WideAxis3(
 2833737            Signed320.ExtendValue(normalX),
 2833738            Signed320.ExtendValue(normalY),
 2833739            Signed320.ExtendValue(normalZ));
 740    }
 741
 742    private static CapsuleAxis3 BuildHullCapsuleCandidateAxis(
 743        HullCapsuleCandidate candidate,
 744        Vector3d hullOrigin,
 745        WideRationalBasis3d hullBasis,
 746        ReadOnlySpan<Vector3d> hullLocalPoints,
 747        ReadOnlySpan<int> triangleVertexIndices,
 748        ReadOnlySpan<int> edgeVertexPairs,
 749        Vector3d capsuleCenter,
 750        WideAxis3 capsuleAxis,
 751        Signed192 capsuleAxisDenominator,
 752        Fixed64 capsuleAxisLength)
 753    {
 4896754        if (candidate.Kind == HullCapsuleCandidateKind.Face)
 755        {
 610756            WideAxis3 normal = GetHullTriangleNormal(
 610757                hullLocalPoints, triangleVertexIndices, candidate.Index);
 610758            return ToCapsuleAxis(WideRigidProjection.TransformLocalAxis(
 610759                hullBasis,
 610760                Signed192.NarrowValue(normal.X),
 610761                Signed192.NarrowValue(normal.Y),
 610762                Signed192.NarrowValue(normal.Z)));
 763        }
 4286764        if (candidate.Kind == HullCapsuleCandidateKind.EdgeCross)
 765        {
 1286766            WideAxis3 edge = GetHullEdge(
 1286767                hullBasis,
 1286768                hullLocalPoints[edgeVertexPairs[candidate.Index]],
 1286769                hullLocalPoints[edgeVertexPairs[candidate.Index + 1]]);
 1286770            return ToCapsuleAxis(WideAxis3.Cross(edge, capsuleAxis));
 771        }
 3000772        if (candidate.Kind == HullCapsuleCandidateKind.VertexCore)
 773        {
 803774            return GetVertexToCapsuleAxis(
 803775                hullOrigin,
 803776                capsuleCenter,
 803777                hullBasis,
 803778                hullLocalPoints[candidate.Index],
 803779                capsuleAxis,
 803780                capsuleAxisDenominator,
 803781                capsuleAxisLength);
 782        }
 783
 2197784        return GetCapsuleEndpointToHullEdgeAxis(
 2197785            hullOrigin,
 2197786            capsuleCenter,
 2197787            hullBasis,
 2197788            hullLocalPoints[edgeVertexPairs[candidate.Index]],
 2197789            hullLocalPoints[edgeVertexPairs[candidate.Index + 1]],
 2197790            capsuleAxis,
 2197791            capsuleAxisDenominator,
 2197792            capsuleAxisLength,
 2197793            candidate.EndpointSign,
 2197794            out _);
 795    }
 796
 797    private static CapsuleAxis3 GetCapsuleEndpointToHullEdgeAxis(
 798        Vector3d hullOrigin,
 799        Vector3d capsuleCenter,
 800        WideRationalBasis3d hullBasis,
 801        Vector3d localStart,
 802        Vector3d localEnd,
 803        WideAxis3 capsuleAxis,
 804        Signed192 capsuleAxisDenominator,
 805        Fixed64 capsuleAxisLength,
 806        int endpointSign,
 807        out Signed576 distanceDenominator)
 808    {
 2456809        distanceDenominator = Signed576.ExtendValue(Signed320.ExtendValue(Signed192.Signed(1L)));
 2456810        WideAxis3 startToEndpoint = GetCornerToAxisEndpointAxis3D(
 2456811            hullOrigin,
 2456812            capsuleCenter,
 2456813            hullBasis,
 2456814            localStart,
 2456815            capsuleAxis,
 2456816            capsuleAxisDenominator,
 2456817            capsuleAxisLength,
 2456818            endpointSign);
 2456819        WideAxis3 edge = GetHullEdge(
 2456820            hullBasis,
 2456821            localStart,
 2456822            localEnd);
 2456823        Signed576 edgeSquared = edge.SquaredLength;
 2456824        if (edgeSquared.IsZero)
 9825            return ToCapsuleAxis(startToEndpoint);
 826
 2447827        Signed576 projection =
 2447828            WideAxis3.Dot(startToEndpoint, edge);
 2447829        if (projection.Sign <= 0)
 633830            return ToCapsuleAxis(startToEndpoint);
 1814831        Signed576 upperBound = WideArithmetic.MultiplySigned576(
 1814832            WideArithmetic.MultiplySigned576(
 1814833                edgeSquared,
 1814834                capsuleAxisDenominator),
 1814835            Signed192.Raw(Fixed64.Two));
 1814836        if (WideArithmetic.CompareNonNegative(
 1814837                projection,
 1814838                upperBound) >= 0)
 839        {
 688840            return ToCapsuleAxis(GetCornerToAxisEndpointAxis3D(
 688841                hullOrigin,
 688842                capsuleCenter,
 688843                hullBasis,
 688844                localEnd,
 688845                capsuleAxis,
 688846                capsuleAxisDenominator,
 688847                capsuleAxisLength,
 688848                endpointSign));
 849        }
 850
 1126851        distanceDenominator = edgeSquared;
 1126852        return GetPerpendicularAxis(
 1126853            startToEndpoint,
 1126854            edge,
 1126855            edgeSquared,
 1126856            projection);
 857    }
 858
 859}

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

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.ConvexHullCapsule.ScaledFrame.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>Retains authored affine hull points through the existing finite capsule SAT candidates.</content>
 13internal static partial class WideOrientedBox
 14{
 15    // Bounded physical reach is at most 4096. A common source/core point needs
 16    // <360 bits, degree-three radial axes <1080, and their squares <2160.
 17    // All candidate products stay in borrowed banks; no scalar vertex is made.
 18    private const int ScaledHullCapsuleWords = 64;
 19
 20    private readonly ref struct ScaledHullCapsuleFrame
 21    {
 22        internal readonly ScaledRigidFrame3d Frame;
 23        internal readonly ReadOnlySpan<Vector3d> Points;
 24        internal readonly ReadOnlySpan<int> Triangles, Edges;
 25        internal readonly Vector3d Center;
 26        internal readonly RationalPoint3d First, Second;
 27        internal readonly Signed576 Denominator;
 28        private readonly Signed192 coreFactor;
 29        internal ScaledHullCapsuleFrame(in ScaledRigidFrame3d frame, ReadOnlySpan<Vector3d> points,
 30            ReadOnlySpan<int> triangles, ReadOnlySpan<int> edges, Vector3d center,
 31            in RationalPoint3d first, in RationalPoint3d second)
 32        {
 12533            Frame = frame; Points = points; Triangles = triangles; Edges = edges; Center = center;
 5034            First = first; Second = second;
 2535            coreFactor = WideArithmetic.TruncateSigned320By64(first.Denominator);
 2536            Denominator = WideArithmetic.MultiplySigned320(frame.Denominator, coreFactor);
 2537        }
 38        internal WideDirection3d Point(int index)
 39        {
 1138040            RationalPoint3d point = Frame.GetPoint(Points[index]);
 1138041            return Relative(point, coreFactor);
 42        }
 496643        internal WideDirection3d Endpoint(bool second) => Relative(second ? Second : First, Frame.RotationDenominator);
 1634644        private WideDirection3d Relative(in RationalPoint3d point, Signed192 factor) => new(
 1634645            Coordinate(point.X, point.Denominator, Center.X, factor),
 1634646            Coordinate(point.Y, point.Denominator, Center.Y, factor),
 1634647            Coordinate(point.Z, point.Denominator, Center.Z, factor));
 48        private static Signed576 Coordinate(Signed320 numerator, Signed320 denominator, Fixed64 center, Signed192 factor
 4903849            WideArithmetic.MultiplySigned576(WideArithmetic.SubtractSigned576(Signed576.ExtendValue(numerator),
 4903850                WideArithmetic.MultiplySigned320(denominator, Signed192.Raw(center))), factor);
 51    }
 52
 53    internal static bool TryGetConvexHullCenteredCapsuleContact(in ScaledRigidFrame3d frame, Vector3d hullAnchorOrigin,
 54        ReadOnlySpan<Vector3d> points, ReadOnlySpan<int> triangles, ReadOnlySpan<int> edges,
 55        Vector3d center, FixedQuaternion rotation, Vector3d localAxis, Fixed64 length, Fixed64 radius,
 56        out FixedContactAnchors contact)
 57    {
 2258        if (frame.IsRigid) return TryGetConvexHullCenteredCapsuleContact(frame.RigidOrigin, frame.Rotation,
 359            points, triangles, edges, center, rotation, localAxis, length, radius, out contact);
 1660        contact = default;
 1661        FixedPointAnchor first = WideGeometry.GetCenteredCapsuleSupportAnchor(center, rotation, localAxis,
 1662            length, Fixed64.Zero, Vector3d.Zero, -1);
 1663        FixedPointAnchor second = WideGeometry.GetCenteredCapsuleSupportAnchor(center, rotation, localAxis,
 1664            length, Fixed64.Zero, Vector3d.Zero, 1);
 1665        var geometry = new ScaledHullCapsuleFrame(frame, points, triangles, edges, center,
 1666            RationalPoint3d.FromAnchor(first), RationalPoint3d.FromAnchor(second));
 67        const int words = ScaledHullCapsuleWords;
 3268        Span<ulong> values = stackalloc ulong[14 * words]; Span<int> signs = stackalloc int[14];
 1669        var x = ContactQuadratic.At(values, signs, 0, words);
 1670        var y = ContactQuadratic.At(values, signs, 1, words);
 1671        var z = ContactQuadratic.At(values, signs, 2, words);
 1672        var rational = ContactQuadratic.At(values, signs, 3, words);
 1673        var square = ContactQuadratic.At(values, signs, 4, words);
 1674        var bestRational = ContactQuadratic.At(values, signs, 5, words);
 1675        var bestSquare = ContactQuadratic.At(values, signs, 6, words);
 1676        if (!FindScaledHullCapsuleCandidate(geometry, radius, false, x, y, z, rational, square,
 1877                bestRational, bestSquare, out HullCapsuleCandidate best)) return false;
 1478        _ = EvaluateScaledHullCapsuleCandidate(geometry, best, radius, x, y, z, rational, square, out bool negate);
 4479        if (negate) { x.MultiplySign(-1); y.MultiplySign(-1); z.MultiplySign(-1); }
 1480        Vector3d normal = NormalizeScaledHullAxis(x, y, z);
 1481        SetScaledHullAxisDot(x, y, z, Subtract(geometry.Endpoint(true), geometry.Endpoint(false)), bestRational, bestSqu
 1482        int axialSign = -bestRational.Signs[0];
 1483        FixedPointAnchor capsule = WideGeometry.GetCenteredCapsuleSupportAnchor(center, rotation, localAxis,
 1484            length, radius, -normal, axialSign);
 1485        FixedPointAnchor hull = GetScaledHullCapsuleSupportAnchor(geometry, x, y, z, hullAnchorOrigin,
 1486            center, rotation, localAxis, length, radius, normal, capsule, out capsule);
 1487        GetHullCapsuleDepth(rational.Rational, rational.Signs[0], square.Rational,
 1488            geometry.Denominator, radius, out Fixed64 depth, out bool clamped);
 1489        contact = new FixedContactAnchors(hull, capsule, normal, depth, clamped);
 1490        return true;
 91    }
 92
 93    internal static bool DoesConvexHullCenteredCapsuleStrictlyOverlap(in ScaledRigidFrame3d frame,
 94        ReadOnlySpan<Vector3d> points, ReadOnlySpan<int> triangles, ReadOnlySpan<int> edges,
 95        Vector3d center, FixedQuaternion rotation, Vector3d localAxis, Fixed64 length, Fixed64 radius)
 96    {
 1597        if (frame.IsRigid) return DoesConvexHullCenteredCapsuleStrictlyOverlap(frame.RigidOrigin, frame.Rotation,
 398            points, triangles, edges, center, rotation, localAxis, length, radius);
 999        var first = RationalPoint3d.FromAnchor(WideGeometry.GetCenteredCapsuleSupportAnchor(center, rotation,
 9100            localAxis, length, Fixed64.Zero, Vector3d.Zero, -1));
 9101        var second = RationalPoint3d.FromAnchor(WideGeometry.GetCenteredCapsuleSupportAnchor(center, rotation,
 9102            localAxis, length, Fixed64.Zero, Vector3d.Zero, 1));
 9103        var geometry = new ScaledHullCapsuleFrame(frame, points, triangles, edges, center, first, second);
 104        const int words = ScaledHullCapsuleWords;
 18105        Span<ulong> values = stackalloc ulong[14 * words]; Span<int> signs = stackalloc int[14];
 9106        return FindScaledHullCapsuleCandidate(geometry, radius, true,
 9107            ContactQuadratic.At(values, signs, 0, words), ContactQuadratic.At(values, signs, 1, words),
 9108            ContactQuadratic.At(values, signs, 2, words), ContactQuadratic.At(values, signs, 3, words),
 9109            ContactQuadratic.At(values, signs, 4, words), ContactQuadratic.At(values, signs, 5, words),
 9110            ContactQuadratic.At(values, signs, 6, words), out _);
 111    }
 112
 113    private static FixedPointAnchor GetScaledHullCapsuleSupportAnchor(scoped in ScaledHullCapsuleFrame geometry,
 114        scoped ContactQuadratic x, scoped ContactQuadratic y, scoped ContactQuadratic z, Vector3d hullOrigin,
 115        Vector3d center, FixedQuaternion rotation, Vector3d localAxis, Fixed64 length, Fixed64 radius,
 116        Vector3d normal, in FixedPointAnchor target, out FixedPointAnchor matchedCapsule)
 117    {
 14118        matchedCapsule = target;
 119        const int words = ScaledHullCapsuleWords;
 28120        Span<ulong> values = stackalloc ulong[8 * words]; Span<int> signs = stackalloc int[8];
 14121        var support = ContactQuadratic.At(values, signs, 0, words);
 14122        var projection = ContactQuadratic.At(values, signs, 1, words);
 14123        var term = ContactQuadratic.At(values, signs, 2, words);
 14124        var coreProjection = ContactQuadratic.At(values, signs, 3, words);
 14125        SetScaledHullAxisDot(x, y, z, geometry.Point(0), support, term);
 224126        for (int index = 1; index < geometry.Points.Length; index++)
 127        {
 98128            SetScaledHullAxisDot(x, y, z, geometry.Point(index), projection, term);
 116129            if (CompareScaledHullValues(projection, support) > 0) projection.CopyTo(support);
 130        }
 14131        SetScaledHullAxisDot(x, y, z, Subtract(geometry.Endpoint(true), geometry.Endpoint(false)), coreProjection, term)
 14132        bool matchCore = coreProjection.Signs[0] == 0 && length > Fixed64.Zero;
 14133        RationalPoint3d targetPoint = RationalPoint3d.FromAnchor(target);
 134        // A finite support-face projection certifies the entire support set.
 296135        for (int index = 0; index < geometry.Triangles.Length; index += 3)
 136        {
 423137            int ia = geometry.Triangles[index], ib = geometry.Triangles[index + 1], ic = geometry.Triangles[index + 2];
 141138            if (!IsScaledHullCapsuleSupport(geometry, ia, x,y,z,support,projection,term)
 141139                || !IsScaledHullCapsuleSupport(geometry, ib, x,y,z,support,projection,term)
 141140                || !IsScaledHullCapsuleSupport(geometry, ic, x,y,z,support,projection,term)) continue;
 13141            var triangle = new FixedTriangle(geometry.Points[ia],geometry.Points[ib],geometry.Points[ic]);
 13142            if (WideTriangleRelations.TryGetProjectedPointAnchor(triangle, geometry.Frame, targetPoint, hullOrigin,
 20143                    out FixedPointAnchor face)) return face;
 144        }
 7145        Span<ulong> bestValues = stackalloc ulong[WideFiniteAxisIntersection.ScaledAxisTriangleCandidate.StorageWords];
 7146        Span<int> bestSigns = stackalloc int[WideFiniteAxisIntersection.ScaledAxisTriangleCandidate.SignCount];
 7147        var best = new WideFiniteAxisIntersection.ScaledAxisTriangleCandidate(bestValues,bestSigns);
 14148        RationalPoint3d first = matchCore ? geometry.First : targetPoint, second = matchCore ? geometry.Second : targetP
 149        // Faces, edges and vertices form the same finite support set as the
 150        // rigid owner. The shared closest-feature kernel retains both witnesses.
 56151        for (int kind = 0; kind < 3; kind++)
 152        {
 21153            int count = kind == 0 ? geometry.Triangles.Length/3 : kind == 1 ? geometry.Edges.Length/2 : geometry.Points.
 490154            for(int index = 0; index < count; index++)
 155            {
 224156                int ia = kind == 0 ? geometry.Triangles[3*index] : kind == 1 ? geometry.Edges[2*index] : index;
 224157                int ib = kind == 0 ? geometry.Triangles[3*index+1] : kind == 1 ? geometry.Edges[2*index+1] : ia;
 224158                int ic = kind == 0 ? geometry.Triangles[3*index+2] : ib;
 224159                if(!IsScaledHullCapsuleSupport(geometry,ia,x,y,z,support,projection,term)
 224160                    ||!IsScaledHullCapsuleSupport(geometry,ib,x,y,z,support,projection,term)
 224161                    ||!IsScaledHullCapsuleSupport(geometry,ic,x,y,z,support,projection,term)) continue;
 38162                var triangle = new FixedTriangle(geometry.Points[ia],geometry.Points[ib],geometry.Points[ic]);
 38163                WideFiniteAxisIntersection.GetClosestScaledAxisTriangleCandidate(triangle,geometry.Frame,
 38164                    first,second,center,ref best);
 165            }
 166        }
 167        System.Diagnostics.Debug.Assert(best.HasValue);
 7168        bool represented = QuadraticPointMaterialization.TryGetPointInFrame(center,FixedQuaternion.Identity,
 7169            best.TriangleCoordinate(0),best.TriangleCoordinate(1),best.TriangleCoordinate(2),best.Denominator,
 7170            ReadOnlySpan<ulong>.Empty,hullOrigin,out Vector3d hullPoint);
 171        System.Diagnostics.Debug.Assert(represented);
 7172        if(matchCore)
 173        {
 174            // Add radial support before the only scalar rounding, preserving an
 175            // odd endpoint or fractional projected core coordinate.
 3176            int witnessWords=best.Denominator.FieldWords+2;
 6177            Span<ulong> material=stackalloc ulong[10*witnessWords];Span<int> materialSigns=stackalloc int[10];
 3178            var a=ContactQuadratic.At(material,materialSigns,0,witnessWords);
 3179            var b=ContactQuadratic.At(material,materialSigns,1,witnessWords);
 3180            var c=ContactQuadratic.At(material,materialSigns,2,witnessWords);
 3181            var d=ContactQuadratic.At(material,materialSigns,3,witnessWords);
 3182            var radial=ContactQuadratic.At(material,materialSigns,4,witnessWords);
 3183            ContactQuadratic.Scale(best.Denominator,Signed576.ExtendValue(Signed192.Raw(Fixed64.One)),d);
 24184            for(int axis=0;axis<3;axis++)
 185            {
 9186                var output=axis==0?a:axis==1?b:c;
 9187                ContactQuadratic.Scale(best.AxisCoordinate(axis),Signed576.ExtendValue(Signed192.Raw(Fixed64.One)),outpu
 9188                ContactQuadratic.Scale(best.Denominator,Signed576.ExtendValue(Fixed64.GetExactRawProduct(normal[axis],ra
 9189                output.Add(radial,-1);
 190            }
 3191            represented=QuadraticPointMaterialization.TryGetPointInFrame(center,FixedQuaternion.Identity,a,b,c,d,
 3192                ReadOnlySpan<ulong>.Empty,center,out Vector3d capsulePoint);
 193            System.Diagnostics.Debug.Assert(represented);
 3194            matchedCapsule=new FixedPointAnchor(center,FixedQuaternion.Identity,capsulePoint);
 195        }
 7196        return new FixedPointAnchor(hullOrigin,FixedQuaternion.Identity,hullPoint);
 197    }
 198
 199    private static bool IsScaledHullCapsuleSupport(scoped in ScaledHullCapsuleFrame geometry,int index,
 200        scoped ContactQuadratic x,scoped ContactQuadratic y,scoped ContactQuadratic z,
 201        scoped ContactQuadratic support,scoped ContactQuadratic projection,scoped ContactQuadratic term)
 994202    { SetScaledHullAxisDot(x,y,z,geometry.Point(index),projection,term);return CompareScaledHullValues(projection,suppor
 203
 204    private static bool FindScaledHullCapsuleCandidate(scoped in ScaledHullCapsuleFrame geometry, Fixed64 radius,
 205        bool strict, scoped ContactQuadratic x, scoped ContactQuadratic y, scoped ContactQuadratic z,
 206        scoped ContactQuadratic rational, scoped ContactQuadratic square,
 207        scoped ContactQuadratic bestRational, scoped ContactQuadratic bestSquare, out HullCapsuleCandidate best)
 208    {
 50209        bool found = false; best = default;
 210210        for (int kind = 0; kind < 4; kind++)
 211        {
 85212            int count = kind == 0 ? geometry.Triangles.Length / 3
 85213                : kind == 2 ? geometry.Points.Length : geometry.Edges.Length / 2;
 2010214            for (int feature = 0; feature < count; feature++)
 4170215            for (int endpoint = kind == 3 ? -1 : 0; endpoint <= (kind == 3 ? 1 : 0); endpoint += 2)
 216            {
 1165217                var candidate = new HullCapsuleCandidate((HullCapsuleCandidateKind)kind,
 1165218                    kind == 0 ? feature * 3 : kind == 2 ? feature : feature * 2, endpoint);
 1165219                int status = EvaluateScaledHullCapsuleCandidate(geometry, candidate, radius,
 1165220                    x, y, z, rational, square, out _);
 1165221                if (status < 0 || strict && status > 0 && GetScaledHullCapsuleOverlapSign(
 1170222                        rational, square, geometry.Denominator, radius) == 0) return false;
 1160223                if (status == 0) continue;
 1016224                if (!found || !strict && WideArithmetic.CompareSignedNormalizedMagnitudes(rational.Rational,
 1016225                    rational.Signs[0], square.Rational, bestRational.Rational, bestRational.Signs[0], bestSquare.Rationa
 226                {
 156227                    found = true; best = candidate; rational.CopyTo(bestRational); square.CopyTo(bestSquare);
 228                }
 229            }
 230        }
 20231        return found;
 232    }
 233
 234    private static int EvaluateScaledHullCapsuleCandidate(scoped in ScaledHullCapsuleFrame geometry,
 235        HullCapsuleCandidate candidate, Fixed64 radius, scoped ContactQuadratic x, scoped ContactQuadratic y,
 236        scoped ContactQuadratic z, scoped ContactQuadratic rational, scoped ContactQuadratic square, out bool negate)
 237    {
 1179238        BuildScaledHullCapsuleAxis(geometry, candidate, x, y, z);
 3537239        negate = false; rational.Clear(); square.Clear();
 1323240        if (x.Signs[0] == 0 && y.Signs[0] == 0 && z.Signs[0] == 0) return 0;
 241        const int words = ScaledHullCapsuleWords;
 2070242        Span<ulong> values = stackalloc ulong[12 * words]; Span<int> signs = stackalloc int[12];
 1035243        var minimum = ContactQuadratic.At(values, signs, 0, words);
 1035244        var maximum = ContactQuadratic.At(values, signs, 1, words);
 1035245        var projection = ContactQuadratic.At(values, signs, 2, words);
 1035246        var term = ContactQuadratic.At(values, signs, 3, words);
 1035247        var positive = ContactQuadratic.At(values, signs, 4, words);
 1035248        var negative = ContactQuadratic.At(values, signs, 5, words);
 2070249        SetScaledHullAxisDot(x, y, z, geometry.Point(0), minimum, term); minimum.CopyTo(maximum);
 16560250        for (int index = 1; index < geometry.Points.Length; index++)
 251        {
 7245252            SetScaledHullAxisDot(x, y, z, geometry.Point(index), projection, term);
 8210253            if (CompareScaledHullValues(projection, minimum) < 0) projection.CopyTo(minimum);
 8481254            if (CompareScaledHullValues(projection, maximum) > 0) projection.CopyTo(maximum);
 255        }
 1035256        SetScaledHullAxisDot(x, y, z, geometry.Endpoint(false), positive, term);
 1035257        SetScaledHullAxisDot(x, y, z, geometry.Endpoint(true), negative, term);
 1035258        if (CompareScaledHullValues(positive, negative) > 0)
 492259        { positive.CopyTo(projection); negative.CopyTo(positive); projection.CopyTo(negative); }
 2070260        maximum.CopyTo(rational); rational.Add(positive, -1);
 1035261        negative.Add(minimum, -1);
 1495262        if (CompareScaledHullValues(negative, rational) < 0) { negative.CopyTo(rational); negate = true; }
 1035263        ContactQuadratic.Multiply(x, x, ReadOnlySpan<ulong>.Empty, square);
 2070264        ContactQuadratic.Multiply(y, y, ReadOnlySpan<ulong>.Empty, term); square.Add(term);
 2070265        ContactQuadratic.Multiply(z, z, ReadOnlySpan<ulong>.Empty, term); square.Add(term);
 1035266        return GetScaledHullCapsuleOverlapSign(rational, square, geometry.Denominator, radius) < 0 ? -1 : 1;
 267    }
 268
 269    private static int GetScaledHullCapsuleOverlapSign(scoped ContactQuadratic rational, scoped ContactQuadratic square,
 270        Signed576 denominator, Fixed64 radius)
 271    {
 1360272        Span<ulong> coefficient = stackalloc ulong[13];
 1360273        Signed832 radial = WideArithmetic.MultiplySigned576ToSigned832(denominator, Signed576.ExtendValue(Signed192.Raw(
 1360274        WideArithmetic.GetMagnitude(radial, coefficient);
 1360275        return WideArithmetic.GetSignedMagnitudeAndSquareRootSign(rational.Rational, rational.Signs[0],
 1360276            coefficient, radial.Sign, square.Rational);
 277    }
 278
 279    private static void BuildScaledHullCapsuleAxis(scoped in ScaledHullCapsuleFrame geometry,
 280        HullCapsuleCandidate candidate, scoped ContactQuadratic x, scoped ContactQuadratic y, scoped ContactQuadratic z)
 281    {
 2358282        WideDirection3d first = geometry.Endpoint(false), core = Subtract(geometry.Endpoint(true), first);
 283        WideDirection3d edge, offset;
 1179284        if (candidate.Kind == HullCapsuleCandidateKind.Face)
 285        {
 295286            WideDirection3d a = geometry.Point(geometry.Triangles[candidate.Index]);
 295287            SetScaledHullCross(Subtract(geometry.Point(geometry.Triangles[candidate.Index + 1]), a),
 590288                Subtract(geometry.Point(geometry.Triangles[candidate.Index + 2]), a), x, y, z); return;
 289        }
 884290        if (candidate.Kind == HullCapsuleCandidateKind.VertexCore)
 324291        { edge = core; offset = Subtract(geometry.Point(candidate.Index), first); }
 292        else
 293        {
 722294            WideDirection3d start = geometry.Point(geometry.Edges[candidate.Index]);
 722295            edge = Subtract(geometry.Point(geometry.Edges[candidate.Index + 1]), start);
 1202296            if (candidate.Kind == HullCapsuleCandidateKind.EdgeCross) { SetScaledHullCross(edge, core, x, y, z); return;
 482297            offset = Subtract(geometry.Endpoint(candidate.EndpointSign > 0), start);
 298        }
 299        const int words = ScaledHullCapsuleWords;
 1288300        Span<ulong> values = stackalloc ulong[8 * words]; Span<int> signs = stackalloc int[8];
 644301        var length = ContactQuadratic.At(values, signs, 0, words);
 644302        var projection = ContactQuadratic.At(values, signs, 1, words);
 644303        var term = ContactQuadratic.At(values, signs, 2, words);
 644304        var coordinate = ContactQuadratic.At(values, signs, 3, words);
 1288305        SetScaledHullVectorDot(edge, edge, length, term); SetScaledHullVectorDot(offset, edge, projection, term);
 1388306        if (length.Signs[0] == 0 || projection.Signs[0] <= 0) { x.Set(offset.X); y.Set(offset.Y); z.Set(offset.Z); retur
 458307        if (CompareScaledHullValues(projection, length) >= 0)
 620308        { offset = Subtract(offset, edge); x.Set(offset.X); y.Set(offset.Y); z.Set(offset.Z); return; }
 2672309        for (int axis = 0; axis < 3; axis++)
 310        {
 1002311            var output = axis == 0 ? x : axis == 1 ? y : z;
 1002312            ContactQuadratic.Scale(length, axis == 0 ? offset.X : axis == 1 ? offset.Y : offset.Z, output);
 1002313            ContactQuadratic.Scale(projection, axis == 0 ? edge.X : axis == 1 ? edge.Y : edge.Z, coordinate);
 1002314            output.Add(coordinate, -1);
 315        }
 334316    }
 317
 318    private static void SetScaledHullCross(in WideDirection3d first, in WideDirection3d second,
 319        scoped ContactQuadratic x, scoped ContactQuadratic y, scoped ContactQuadratic z)
 320    {
 321        const int words = ScaledHullCapsuleWords;
 1070322        Span<ulong> values = stackalloc ulong[4 * words]; Span<int> signs = stackalloc int[4];
 1070323        var value = ContactQuadratic.At(values, signs, 0, words); var term = ContactQuadratic.At(values, signs, 1, words
 4280324        for (int axis = 0; axis < 3; axis++)
 325        {
 1605326            var output = axis == 0 ? x : axis == 1 ? y : z;
 1605327            Signed576 a = axis == 0 ? first.Y : axis == 1 ? first.Z : first.X;
 1605328            Signed576 b = axis == 0 ? second.Z : axis == 1 ? second.X : second.Y;
 3210329            value.Set(a); ContactQuadratic.Scale(value, b, output);
 1605330            a = axis == 0 ? first.Z : axis == 1 ? first.X : first.Y;
 1605331            b = axis == 0 ? second.Y : axis == 1 ? second.Z : second.X;
 4815332            value.Set(a); ContactQuadratic.Scale(value, b, term); output.Add(term, -1);
 333        }
 535334    }
 335
 3287336    private static WideDirection3d Subtract(in WideDirection3d a, in WideDirection3d b) => new(
 3287337        WideArithmetic.SubtractSigned576(a.X,b.X), WideArithmetic.SubtractSigned576(a.Y,b.Y), WideArithmetic.SubtractSig
 338    private static int CompareScaledHullValues(scoped ContactQuadratic a, scoped ContactQuadratic b) =>
 17613339        CompareHullCapsuleSignedMagnitudes(a.Rational, a.Signs[0], b.Rational, b.Signs[0]);
 340    private static void SetScaledHullVectorDot(in WideDirection3d a, in WideDirection3d b,
 341        scoped ContactQuadratic result, scoped ContactQuadratic term)
 342    {
 3864343        result.Clear(); term.Set(a.X); ContactQuadratic.Scale(term,b.X,result);
 3864344        term.Set(a.Y); Span<ulong> v=stackalloc ulong[2*ScaledHullCapsuleWords]; Span<int> s=stackalloc int[2];
 3864345        var product=ContactQuadratic.At(v,s,0,ScaledHullCapsuleWords); ContactQuadratic.Scale(term,b.Y,product); result.
 3864346        term.Set(a.Z); ContactQuadratic.Scale(term,b.Z,product); result.Add(product);
 1288347    }
 348    private static void SetScaledHullAxisDot(scoped ContactQuadratic x, scoped ContactQuadratic y,
 349        scoped ContactQuadratic z, in WideDirection3d point, scoped ContactQuadratic result, scoped ContactQuadratic ter
 350    {
 32961351        ContactQuadratic.Scale(x,point.X,result); ContactQuadratic.Scale(y,point.Y,term); result.Add(term);
 21974352        ContactQuadratic.Scale(z,point.Z,term); result.Add(term);
 10987353    }
 354    private static Vector3d NormalizeScaledHullAxis(scoped ContactQuadratic x, scoped ContactQuadratic y, scoped Contact
 355    {
 14356        ReadOnlySpan<ulong> maximum = WideArithmetic.CompareMagnitudeEqualLength(x.Rational,y.Rational)>=0?x.Rational:y.
 17357        if(WideArithmetic.CompareMagnitudeEqualLength(z.Rational,maximum)>0) maximum=z.Rational;
 28358        Span<ulong> numerator=stackalloc ulong[ScaledHullCapsuleWords+1]; Vector3d result=default;
 112359        for(int axis=0;axis<3;axis++)
 360        {
 126361            var value=axis==0?x:axis==1?y:z; numerator.Clear(); int sign=0;
 42362            WideArithmetic.AddShiftedSignedMagnitude(value.Rational,1,32,numerator,ref sign);
 84363            _=Fixed64.TryGetSignedRawRatio(numerator,maximum,value.Signs[0]<0,out Fixed64 coordinate); result[axis]=coor
 364        }
 14365        return Vector3d.GetScaleNormalized(result);
 366    }
 367}

/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        {
 635440            Kind = kind;
 635441            Index = index;
 635442            EndpointSign = endpointSign;
 635443        }
 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    {
 57        // The axis and rational basis are invariant across every hull point.
 58        // Retain their exact projections; only the local coordinate products vary.
 457259        Signed704 xProjection = GetCapsuleBasisProjection(
 457260            axis, basis.Xx, basis.Xy, basis.Xz);
 457261        Signed704 yProjection = GetCapsuleBasisProjection(
 457262            axis, basis.Yx, basis.Yy, basis.Yz);
 457263        Signed704 zProjection = GetCapsuleBasisProjection(
 457264            axis, basis.Zx, basis.Zy, basis.Zz);
 457265        BuildHullCapsuleLocalProjection(
 457266            points[0],
 457267            xProjection,
 457268            yProjection,
 457269            zProjection,
 457270            minimum,
 457271            out minimumSign);
 457272        minimum.CopyTo(maximum);
 457273        maximumSign = minimumSign;
 457274        Span<ulong> candidate =
 457275            stackalloc ulong[HullCapsuleMagnitudeWords];
 7056076        for (int index = 1; index < points.Length; index++)
 77        {
 3070878            BuildHullCapsuleLocalProjection(
 3070879                points[index],
 3070880                xProjection,
 3070881                yProjection,
 3070882                zProjection,
 3070883                candidate,
 3070884                out int candidateSign);
 3070885            if (CompareHullCapsuleSignedMagnitudes(
 3070886                    candidate,
 3070887                    candidateSign,
 3070888                    minimum,
 3070889                    minimumSign) < 0)
 90            {
 356591                candidate.CopyTo(minimum);
 356592                minimumSign = candidateSign;
 93            }
 3070894            if (CompareHullCapsuleSignedMagnitudes(
 3070895                    candidate,
 3070896                    candidateSign,
 3070897                    maximum,
 3070898                    maximumSign) > 0)
 99            {
 5312100                candidate.CopyTo(maximum);
 5312101                maximumSign = candidateSign;
 102            }
 103        }
 4572104    }
 105
 106    private static void BuildHullCapsuleLocalProjection(
 107        Vector3d point,
 108        Signed704 xProjection,
 109        Signed704 yProjection,
 110        Signed704 zProjection,
 111        Span<ulong> result,
 112        out int resultSign)
 113    {
 114        // Each signed 704-bit projection times a raw signed 64-bit coordinate
 115        // has magnitude at most 2^766. Three terms need at most 769 signed
 116        // bits, so both products and their exact sum fit Signed832.
 38762117        Signed832 projection = WideArithmetic.AddSigned832(
 38762118            WideArithmetic.AddSigned832(
 38762119                WideArithmetic.MultiplySigned704ToSigned832(
 38762120                    xProjection, Signed192.Raw(point.X)),
 38762121                WideArithmetic.MultiplySigned704ToSigned832(
 38762122                    yProjection, Signed192.Raw(point.Y))),
 38762123            WideArithmetic.MultiplySigned704ToSigned832(
 38762124                zProjection, Signed192.Raw(point.Z)));
 38762125        WideArithmetic.GetMagnitude(projection, result);
 38762126        resultSign = projection.Sign;
 38762127    }
 128
 129    private static Signed704 GetHullCapsuleCenterProjection(
 130        Vector3d end,
 131        Vector3d start,
 132        CapsuleAxis3 axis) =>
 4545133        WideArithmetic.AddSigned704(
 4545134            WideArithmetic.AddSigned704(
 4545135                WideArithmetic.MultiplySigned576ToSigned704(
 4545136                    axis.X,
 4545137                    Signed320.ExtendValue(
 4545138                        WideArithmetic.SubtractSigned192(
 4545139                            Signed192.Raw(end.X),
 4545140                            Signed192.Raw(start.X)))),
 4545141                WideArithmetic.MultiplySigned576ToSigned704(
 4545142                    axis.Y,
 4545143                    Signed320.ExtendValue(
 4545144                        WideArithmetic.SubtractSigned192(
 4545145                            Signed192.Raw(end.Y),
 4545146                            Signed192.Raw(start.Y))))),
 4545147            WideArithmetic.MultiplySigned576ToSigned704(
 4545148                axis.Z,
 4545149                Signed320.ExtendValue(
 4545150                    WideArithmetic.SubtractSigned192(
 4545151                        Signed192.Raw(end.Z),
 4545152                        Signed192.Raw(start.Z)))));
 153
 154    private static void BuildHullCapsuleAxisSquared(
 155        CapsuleAxis3 axis,
 156        Span<ulong> result)
 157    {
 4987158        Span<ulong> component =
 4987159            stackalloc ulong[HullCapsuleMagnitudeWords];
 4987160        Span<ulong> square =
 4987161            stackalloc ulong[HullCapsuleMagnitudeWords];
 4987162        result.Clear();
 4987163        GetHullCapsuleMagnitude(axis.X, component);
 4987164        WideArithmetic.MultiplyMagnitudes(
 4987165            component,
 4987166            component,
 4987167            square);
 4987168        WideArithmetic.AddMagnitudeInto(square, result);
 4987169        GetHullCapsuleMagnitude(axis.Y, component);
 4987170        WideArithmetic.MultiplyMagnitudes(
 4987171            component,
 4987172            component,
 4987173            square);
 4987174        WideArithmetic.AddMagnitudeInto(square, result);
 4987175        GetHullCapsuleMagnitude(axis.Z, component);
 4987176        WideArithmetic.MultiplyMagnitudes(
 4987177            component,
 4987178            component,
 4987179            square);
 4987180        WideArithmetic.AddMagnitudeInto(square, result);
 4987181    }
 182
 183    private static bool ContainsHullSphereSupportProjection(
 184        Vector3d hullOrigin, FixedQuaternion hullRotation, WideRationalBasis3d basis,
 185        ReadOnlySpan<Vector3d> points, ReadOnlySpan<int> triangles,
 186        CapsuleAxis3 orientedAxis, Vector3d sphereCenter)
 187    {
 27188        Span<ulong> minimum = stackalloc ulong[HullCapsuleMagnitudeWords];
 27189        Span<ulong> maximum = stackalloc ulong[HullCapsuleMagnitudeWords];
 27190        GetHullCapsuleProjectionInterval(points, basis, orientedAxis,
 27191            minimum, out _, maximum, out int maximumSign);
 27192        Signed704 x = GetCapsuleBasisProjection(orientedAxis, basis.Xx, basis.Xy, basis.Xz);
 27193        Signed704 y = GetCapsuleBasisProjection(orientedAxis, basis.Yx, basis.Yy, basis.Yz);
 27194        Signed704 z = GetCapsuleBasisProjection(orientedAxis, basis.Zx, basis.Zy, basis.Zz);
 27195        FixedPointAnchor center = new(sphereCenter, FixedQuaternion.Identity, Vector3d.Zero);
 196        // Only a finite triangle on the selected support plane can certify
 197        // the closest point. The winning axis may come from the opposite face.
 480198        for (int index = 0; index < triangles.Length; index += 3)
 199        {
 225200            Vector3d first = points[triangles[index]];
 225201            Vector3d second = points[triangles[index + 1]];
 225202            Vector3d third = points[triangles[index + 2]];
 225203            if (IsHullCapsuleSupportPoint(first, x, y, z, maximum, maximumSign)
 225204                && IsHullCapsuleSupportPoint(second, x, y, z, maximum, maximumSign)
 225205                && IsHullCapsuleSupportPoint(third, x, y, z, maximum, maximumSign)
 225206                && WideTriangleRelations.ContainsProjection(new FixedTriangle(first, second, third),
 225207                    hullOrigin, hullRotation, center))
 12208                return true;
 209        }
 15210        return false;
 211    }
 212
 213    private static FixedPointAnchor GetMatchedHullCapsuleSupportAnchor(
 214        Vector3d hullOrigin,
 215        FixedQuaternion hullRotation,
 216        WideRationalBasis3d basis,
 217        ReadOnlySpan<Vector3d> points,
 218        ReadOnlySpan<int> triangleVertexIndices,
 219        ReadOnlySpan<int> edgeVertexPairs,
 220        CapsuleAxis3 orientedAxis,
 221        in FixedPointAnchor target,
 222        Vector3d capsuleCenter, FixedQuaternion capsuleRotation, Vector3d capsuleAxis,
 223        Fixed64 capsuleLength, Fixed64 capsuleRadius, Vector3d normal, bool matchCore,
 224        out FixedPointAnchor matchedCapsule)
 225    {
 153226        matchedCapsule = target;
 153227        bool hasCoreMatch = false;
 306228        Signed832 coreN = default, coreD = default;
 153229        FixedTriangle coreFeature = default;
 306230        FixedPointAnchor firstEnd = default, secondEnd = default;
 153231        Signed704 xProjection = GetCapsuleBasisProjection(
 153232            orientedAxis, basis.Xx, basis.Xy, basis.Xz);
 153233        Signed704 yProjection = GetCapsuleBasisProjection(
 153234            orientedAxis, basis.Yx, basis.Yy, basis.Yz);
 153235        Signed704 zProjection = GetCapsuleBasisProjection(
 153236            orientedAxis, basis.Zx, basis.Zy, basis.Zz);
 153237        int supportIndex = 0;
 153238        Span<ulong> best =
 153239            stackalloc ulong[HullCapsuleMagnitudeWords];
 153240        BuildHullCapsuleLocalProjection(
 153241            points[0],
 153242            xProjection,
 153243            yProjection,
 153244            zProjection,
 153245            best,
 153246            out int bestSign);
 153247        Span<ulong> candidate =
 153248            stackalloc ulong[HullCapsuleMagnitudeWords];
 1666249        for (int index = 1; index < points.Length; index++)
 250        {
 680251            BuildHullCapsuleLocalProjection(
 680252                points[index],
 680253                xProjection,
 680254                yProjection,
 680255                zProjection,
 680256                candidate,
 680257                out int candidateSign);
 680258            if (CompareHullCapsuleSignedMagnitudes(
 680259                    candidate,
 680260                    candidateSign,
 680261                    best,
 680262                    bestSign) <= 0)
 263            {
 264                continue;
 265            }
 89266            supportIndex = index;
 89267            candidate.CopyTo(best);
 89268            bestSign = candidateSign;
 269        }
 270
 153271        FixedPointAnchor closest = new(
 153272            hullOrigin,
 153273            hullRotation,
 153274            points[supportIndex]);
 153275        for (int index = 0;
 935276            index < triangleVertexIndices.Length;
 782277            index += 3)
 278        {
 832279            Vector3d first = points[
 832280                triangleVertexIndices[index]];
 832281            Vector3d second = points[
 832282                triangleVertexIndices[index + 1]];
 832283            Vector3d third = points[
 832284                triangleVertexIndices[index + 2]];
 832285            if (!IsHullCapsuleSupportPoint(
 832286                    first,
 832287                    xProjection,
 832288                    yProjection,
 832289                    zProjection,
 832290                    best,
 832291                    bestSign)
 832292                || !IsHullCapsuleSupportPoint(
 832293                    second,
 832294                    xProjection,
 832295                    yProjection,
 832296                    zProjection,
 832297                    best,
 832298                    bestSign)
 832299                || !IsHullCapsuleSupportPoint(
 832300                    third,
 832301                    xProjection,
 832302                    yProjection,
 832303                    zProjection,
 832304                    best,
 832305                    bestSign))
 306            {
 307                continue;
 308            }
 309
 108310            var triangle = new FixedTriangle(first, second, third);
 311            // A projection inside a support face is the unique nearest point
 312            // on the entire support set; boundary edges cannot improve it.
 313            // Keep the first authored certified face rather than ranking
 314            // triangulation differences introduced by final anchor rounding.
 108315            if (WideTriangleRelations.ContainsProjection(triangle, hullOrigin, hullRotation, target))
 50316                return WideTriangleRelations.GetClosestPointAnchor(triangle, hullOrigin, hullRotation, target,
 50317                    preserveExactFace: true);
 318
 58319            if (matchCore)
 320                continue;
 321
 5322            FixedPointAnchor candidateAnchor =
 5323                triangle
 5324                    .GetClosestPointAnchor(
 5325                        hullOrigin,
 5326                        hullRotation,
 5327                        target);
 5328            if (target.CompareSquaredDistance(
 5329                    candidateAnchor,
 5330                    closest) < 0)
 331            {
 1332                closest = candidateAnchor;
 333            }
 334        }
 335
 103336        if (matchCore)
 337        {
 338            // Ordinary midpoint contacts return above, before endpoint work.
 91339            firstEnd = WideGeometry.GetCenteredCapsuleSupportAnchor(capsuleCenter, capsuleRotation,
 91340                capsuleAxis, capsuleLength, Fixed64.Zero, -normal, -1);
 91341            secondEnd = WideGeometry.GetCenteredCapsuleSupportAnchor(capsuleCenter, capsuleRotation,
 91342                capsuleAxis, capsuleLength, Fixed64.Zero, -normal, 1);
 1016343            for (int index = 0; index < triangleVertexIndices.Length; index += 3)
 344            {
 417345                var triangle = new FixedTriangle(points[triangleVertexIndices[index]],
 417346                    points[triangleVertexIndices[index + 1]], points[triangleVertexIndices[index + 2]]);
 417347                if (!GetHullTriangleNormal(points, triangleVertexIndices, index).IsZero
 417348                    && IsHullCapsuleSupportPoint(triangle.A, xProjection, yProjection, zProjection, best, bestSign)
 417349                    && IsHullCapsuleSupportPoint(triangle.B, xProjection, yProjection, zProjection, best, bestSign)
 417350                    && IsHullCapsuleSupportPoint(triangle.C, xProjection, yProjection, zProjection, best, bestSign))
 48351                    KeepHullCapsuleCoreMatch(triangle, hullOrigin, hullRotation, firstEnd, secondEnd,
 48352                        capsuleCenter, capsuleRotation, capsuleAxis, capsuleLength,
 48353                        ref hasCoreMatch, ref coreFeature, ref coreN, ref coreD);
 354            }
 355        }
 356        // A finite face match owns the footprint; edges/vertices cannot replace
 357        // it merely because their unrelated closest core parameter is smaller.
 103358        bool hasFaceMatch = hasCoreMatch;
 103359        for (int index = 0;
 431360            !hasFaceMatch && index < edgeVertexPairs.Length;
 328361            index += 2)
 362        {
 328363            Vector3d start =
 328364                points[edgeVertexPairs[index]];
 328365            Vector3d end =
 328366                points[edgeVertexPairs[index + 1]];
 328367            if (!IsHullCapsuleSupportPoint(
 328368                    start,
 328369                    xProjection,
 328370                    yProjection,
 328371                    zProjection,
 328372                    best,
 328373                    bestSign)
 328374                || !IsHullCapsuleSupportPoint(
 328375                    end,
 328376                    xProjection,
 328377                    yProjection,
 328378                    zProjection,
 328379                    best,
 328380                    bestSign))
 381            {
 382                continue;
 383            }
 384
 68385            if (matchCore)
 60386                KeepHullCapsuleCoreMatch(new FixedTriangle(start, end, end), hullOrigin, hullRotation,
 60387                    firstEnd, secondEnd, capsuleCenter, capsuleRotation, capsuleAxis, capsuleLength,
 60388                    ref hasCoreMatch, ref coreFeature, ref coreN, ref coreD);
 68389            if (hasCoreMatch)
 390                continue;
 391
 8392            FixedPointAnchor candidateAnchor =
 8393                new FixedTriangle(start, end, end)
 8394                    .GetClosestPointAnchor(
 8395                        hullOrigin,
 8396                        hullRotation,
 8397                        target);
 8398            if (target.CompareSquaredDistance(
 8399                    candidateAnchor,
 8400                    closest) < 0)
 401            {
 7402                closest = candidateAnchor;
 403            }
 404        }
 103405        if (matchCore)
 406        {
 222407            for (int index = 0; !hasCoreMatch && index < points.Length; index++)
 408            {
 20409                Vector3d point = points[index];
 20410                if (IsHullCapsuleSupportPoint(point, xProjection, yProjection, zProjection, best, bestSign))
 8411                    KeepHullCapsuleCoreMatch(new FixedTriangle(point, point, point), hullOrigin, hullRotation,
 8412                        firstEnd, secondEnd, capsuleCenter, capsuleRotation, capsuleAxis, capsuleLength,
 8413                        ref hasCoreMatch, ref coreFeature, ref coreN, ref coreD);
 414            }
 91415            if (hasCoreMatch)
 416            {
 91417                Signed832 magnitude = coreN.Sign < 0 ? WideArithmetic.SubtractSigned832(default, coreN) : coreN;
 91418                bool isEndpoint = WideArithmetic.SubtractSigned832(
 91419                    WideArithmetic.MultiplySigned832(coreD, Signed192.Raw(capsuleLength)),
 91420                    WideArithmetic.AddSigned832(magnitude, magnitude)).IsZero;
 91421                matchedCapsule = isEndpoint
 91422                    ? WideGeometry.GetCenteredCapsuleSupportAnchor(capsuleCenter, capsuleRotation,
 91423                        capsuleAxis, capsuleLength, capsuleRadius, -normal, coreN.Sign)
 91424                    : new FixedPointAnchor(capsuleCenter, capsuleRotation,
 91425                        WideTriangleRelations.MaterializeCorePoint(capsuleAxis, coreN, coreD),
 91426                        target.LocalDisplacement, target.ExactLocalTerm);
 427                // Admitted faces are nondegenerate; edge/vertex features repeat B as C.
 91428                if (coreFeature.A == coreFeature.B)
 8429                    return FixedPointAnchor.FromValidatedFrame(hullOrigin, hullRotation, coreFeature.A);
 83430                return WideTriangleRelations.GetClosestPointAnchor(coreFeature, hullOrigin, hullRotation, matchedCapsule
 83431                    preserveExactFace: true);
 432            }
 433        }
 12434        return closest;
 435    }
 436
 437    private static void KeepHullCapsuleCoreMatch(
 438        FixedTriangle feature, Vector3d origin, FixedQuaternion rotation,
 439        in FixedPointAnchor firstEnd, in FixedPointAnchor secondEnd,
 440        Vector3d center, FixedQuaternion coreRotation, Vector3d axis, Fixed64 length,
 441        ref bool found, ref FixedTriangle bestFeature, ref Signed832 bestN, ref Signed832 bestD)
 442    {
 116443        if (WideTriangleRelations.TryGetProjectedCoreParameter(feature, origin, rotation,
 116444                firstEnd, secondEnd, center, coreRotation, axis, length,
 116445                out Signed832 n, out Signed832 d)
 116446            && (!found || WideTriangleRelations.CompareCoreParameters(n, d, bestN, bestD) < 0))
 392447        { found = true; bestFeature = feature; bestN = n; bestD = d; }
 116448    }
 449
 450    private static bool IsHullCapsuleSupportPoint(
 451        Vector3d point,
 452        Signed704 xProjection,
 453        Signed704 yProjection,
 454        Signed704 zProjection,
 455        ReadOnlySpan<ulong> supportProjection,
 456        int supportProjectionSign)
 457    {
 2649458        Span<ulong> projection =
 2649459            stackalloc ulong[HullCapsuleMagnitudeWords];
 2649460        BuildHullCapsuleLocalProjection(
 2649461            point,
 2649462            xProjection,
 2649463            yProjection,
 2649464            zProjection,
 2649465            projection,
 2649466            out int projectionSign);
 2649467        return CompareHullCapsuleSignedMagnitudes(
 2649468            projection,
 2649469            projectionSign,
 2649470            supportProjection,
 2649471            supportProjectionSign) == 0;
 472    }
 473
 474    private static void GetHullCapsuleDepth(ReadOnlySpan<ulong> rational, int rationalSign,
 475        ReadOnlySpan<ulong> squaredAxisLength, Signed192 commonDenominator, Fixed64 radius,
 98476        out Fixed64 depth, out bool clamped) => GetHullCapsuleDepth(rational, rationalSign,
 98477            squaredAxisLength, Signed576.ExtendValue(commonDenominator), radius, out depth, out clamped);
 478
 479    private static void GetHullCapsuleDepth(
 480        ReadOnlySpan<ulong> rational,
 481        int rationalSign,
 482        ReadOnlySpan<ulong> squaredAxisLength,
 483        Signed576 commonDenominator,
 484        Fixed64 radius,
 485        out Fixed64 depth,
 486        out bool depthIsClamped)
 487    {
 488        // floor(sqrt(floor(N/D))) equals floor(sqrt(N/D)). Reuse the exact
 489        // ratio-root owner instead of searching the entire scalar range.
 112490        Span<ulong> numerator = stackalloc ulong[2 * HullCapsuleMagnitudeWords];
 112491        Span<ulong> denominator = stackalloc ulong[2 * HullCapsuleMagnitudeWords];
 112492        Span<ulong> common = stackalloc ulong[9];
 112493        Span<ulong> commonSquared = stackalloc ulong[18];
 112494        WideArithmetic.GetMagnitude(commonDenominator, common);
 112495        WideArithmetic.MultiplyMagnitudes(rational, rational, numerator);
 112496        WideArithmetic.MultiplyMagnitudes(common, common, commonSquared);
 112497        WideArithmetic.MultiplyMagnitudes(squaredAxisLength, commonSquared, denominator);
 112498        ulong distanceFloor = WideArithmetic.GetRatioFloorSquareRoot(
 112499            numerator, denominator, unchecked((ulong)long.MaxValue));
 112500        ulong floor = rationalSign < 0
 112501            ? (ulong)radius.m_rawValue - distanceFloor
 112502            : (ulong)radius.m_rawValue + distanceFloor;
 503        // Subtracting a noninteger distance puts this integer one unit above
 504        // the true floor. Decide that one correction before nearest-even rounding.
 112505        if (rationalSign < 0 && CompareHullCapsuleDepthToTwiceRaw(
 112506                rational, rationalSign, squaredAxisLength, commonDenominator,
 112507                radius, new Signed192(0UL, 0UL, floor << 1)) < 0)
 508        {
 25509            floor--;
 510        }
 511
 112512        if (floor >= unchecked((ulong)long.MaxValue))
 513        {
 2514            depth = Fixed64.MaxValue;
 2515            depthIsClamped =
 2516                CompareHullCapsuleDepthToTwiceRaw(
 2517                    rational,
 2518                    rationalSign,
 2519                    squaredAxisLength,
 2520                    commonDenominator,
 2521                    radius,
 2522                    new Signed192(
 2523                        0UL,
 2524                        0UL,
 2525                        unchecked((ulong)long.MaxValue << 1))) > 0;
 2526            return;
 527        }
 528
 110529        int midpointComparison =
 110530            CompareHullCapsuleDepthToTwiceRaw(
 110531                rational,
 110532                rationalSign,
 110533                squaredAxisLength,
 110534                commonDenominator,
 110535                radius,
 110536                new Signed192(
 110537                    0UL,
 110538                    0UL,
 110539                    (floor << 1) | 1UL));
 540        // The comparator is -1, 0, or 1. Adding one plus the floor parity
 541        // encodes greater-than-half and midpoint-to-even as a 0/1 increment.
 110542        ulong roundingIncrement =
 110543            (ulong)((midpointComparison + 1 + (int)(floor & 1UL)) >> 1);
 110544        depth = Fixed64.FromRaw(
 110545            (long)(floor + roundingIncrement));
 110546        depthIsClamped = false;
 110547    }
 548
 549    private static int CompareHullCapsuleDepthToTwiceRaw(
 550        ReadOnlySpan<ulong> rational,
 551        int rationalSign,
 552        ReadOnlySpan<ulong> squaredAxisLength,
 553        Signed576 commonDenominator,
 554        Fixed64 radius,
 555        Signed192 twiceRaw)
 556    {
 175557        Span<ulong> twiceRational =
 175558            stackalloc ulong[HullCapsuleMagnitudeWords];
 175559        rational.CopyTo(twiceRational);
 175560        WideArithmetic.AddMagnitudeInto(
 175561            rational,
 175562            twiceRational);
 175563        Signed192 radialDelta = WideArithmetic.SubtractSigned192(
 175564            WideArithmetic.AddSigned192(
 175565                Signed192.Raw(radius),
 175566                Signed192.Raw(radius)),
 175567            twiceRaw);
 175568        Signed832 coefficient = WideArithmetic.MultiplySigned576ToSigned832(
 175569            commonDenominator, Signed576.ExtendValue(radialDelta));
 175570        Span<ulong> coefficientMagnitude =
 175571            stackalloc ulong[HullCapsuleMagnitudeWords];
 175572        WideArithmetic.GetMagnitude(coefficient, coefficientMagnitude);
 175573        return WideArithmetic.GetSignedMagnitudeAndSquareRootSign(
 175574            twiceRational,
 175575            rationalSign,
 175576            coefficientMagnitude,
 175577            coefficient.Sign,
 175578            squaredAxisLength);
 579    }
 580
 581    private static void MultiplyHullCapsuleMagnitude(
 582        Span<ulong> value,
 583        Signed192 factor,
 584        Span<ulong> result)
 585    {
 9090586        Span<ulong> factorMagnitude =
 9090587            stackalloc ulong[HullCapsuleMagnitudeWords];
 9090588        Span<ulong> product =
 9090589            stackalloc ulong[HullCapsuleMagnitudeWords];
 9090590        GetHullCapsuleMagnitude(factor, factorMagnitude);
 9090591        WideArithmetic.MultiplyMagnitudes(
 9090592            value,
 9090593            factorMagnitude,
 9090594            product);
 9090595        product.CopyTo(result);
 9090596    }
 597
 598    private static void MultiplyHullCapsuleMagnitude(
 599        Span<ulong> value,
 600        Signed320 factor,
 601        Span<ulong> result)
 602    {
 9090603        Span<ulong> factorMagnitude =
 9090604            stackalloc ulong[HullCapsuleMagnitudeWords];
 9090605        Span<ulong> product =
 9090606            stackalloc ulong[HullCapsuleMagnitudeWords];
 9090607        GetHullCapsuleMagnitude(factor, factorMagnitude);
 9090608        WideArithmetic.MultiplyMagnitudes(
 9090609            value,
 9090610            factorMagnitude,
 9090611            product);
 9090612        product.CopyTo(result);
 9090613    }
 614
 615    private static void GetHullCapsuleMagnitude(
 616        Signed192 value,
 617        Span<ulong> result)
 618    {
 13635619        result.Clear();
 13635620        WideArithmetic.GetMagnitude(
 13635621            value,
 13635622            out result[2],
 13635623            out result[1],
 13635624            out result[0]);
 13635625    }
 626
 627    private static void GetHullCapsuleMagnitude(
 628        Signed320 value,
 629        Span<ulong> result)
 630    {
 13635631        result.Clear();
 13635632        WideArithmetic.GetMagnitude(
 13635633            value,
 13635634            out result[4],
 13635635            out result[3],
 13635636            out result[2],
 13635637            out result[1],
 13635638            out result[0]);
 13635639    }
 640
 641    private static void GetHullCapsuleMagnitude(
 642        Signed576 value,
 643        Span<ulong> result)
 644    {
 15403645        result.Clear();
 15403646        Span<ulong> magnitude = stackalloc ulong[9];
 15403647        WideArithmetic.GetMagnitude(value, magnitude);
 15403648        magnitude.CopyTo(result);
 15403649    }
 650
 651    private static void GetHullCapsuleMagnitude(
 652        Signed704 value,
 653        Span<ulong> result)
 654    {
 9090655        result.Clear();
 9090656        Span<ulong> magnitude = stackalloc ulong[11];
 9090657        WideArithmetic.GetMagnitude(value, magnitude);
 9090658        magnitude.CopyTo(result);
 9090659    }
 660
 661    private static int CompareHullCapsuleSignedMagnitudes(
 662        ReadOnlySpan<ulong> left,
 663        int leftSign,
 664        ReadOnlySpan<ulong> right,
 665        int rightSign)
 666    {
 86903667        if (leftSign != rightSign)
 41207668            return leftSign < rightSign ? -1 : 1;
 45696669        if (leftSign == 0)
 2071670            return 0;
 43625671        int comparison =
 43625672            WideArithmetic.CompareMagnitudeEqualLength(left, right);
 43625673        return leftSign > 0 ? comparison : -comparison;
 674    }
 675
 676    private static void CombineHullCapsuleSignedMagnitudes(
 677        ReadOnlySpan<ulong> left,
 678        int leftSign,
 679        ReadOnlySpan<ulong> right,
 680        int rightSign,
 681        Span<ulong> result,
 682        out int resultSign)
 683    {
 18180684        if (leftSign == 0
 18180685            || WideArithmetic.IsZeroMagnitude(left))
 686        {
 1522687            right.CopyTo(result);
 1522688            resultSign = WideArithmetic.IsZeroMagnitude(right)
 1522689                ? 0
 1522690                : rightSign;
 1522691            return;
 692        }
 16658693        if (rightSign == 0
 16658694            || WideArithmetic.IsZeroMagnitude(right))
 695        {
 6548696            left.CopyTo(result);
 6548697            resultSign = leftSign;
 6548698            return;
 699        }
 10110700        if (leftSign == rightSign)
 701        {
 6014702            left.CopyTo(result);
 6014703            WideArithmetic.AddMagnitudeInto(right, result);
 6014704            resultSign = leftSign;
 6014705            return;
 706        }
 707
 4096708        int comparison =
 4096709            WideArithmetic.CompareMagnitudeEqualLength(left, right);
 4096710        if (comparison == 0)
 711        {
 263712            result.Clear();
 263713            resultSign = 0;
 714        }
 3833715        else if (comparison > 0)
 716        {
 1664717            WideArithmetic.SubtractEqualMagnitudes(
 1664718                left,
 1664719                right,
 1664720                result);
 1664721            resultSign = leftSign;
 722        }
 723        else
 724        {
 2169725            WideArithmetic.SubtractEqualMagnitudes(
 2169726                right,
 2169727                left,
 2169728                result);
 2169729            resultSign = rightSign;
 730        }
 2169731    }
 732}

/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
 13
 14
 15
 16/// <content>
 17/// Provides high-precision convex hull containment and separating-axis
 18/// tests for oriented boxes against arbitrary convex hulls.
 19/// </content>
 20internal static partial class WideOrientedBox
 21{
 22    internal static bool ContainsConvexHullPoint(
 23        Vector3d hullOrigin,
 24        FixedQuaternion hullRotation,
 25        ReadOnlySpan<Vector3d> hullLocalPoints,
 26        ReadOnlySpan<int> triangleVertexIndices,
 27        Vector3d hullInteriorLocalPoint,
 28        FixedPointAnchor point)
 29    {
 530        if (!point.Rotation.IsNormalized())
 131            return false;
 32
 433        WideRationalBasis3d hullBasis = new(hullRotation);
 434        WideRationalBasis3d pointBasis = new(point.Rotation);
 8835        for (int index = 0; index < triangleVertexIndices.Length; index += 3)
 36        {
 4237            Vector3d first = hullLocalPoints[triangleVertexIndices[index]];
 4238            Vector3d second = hullLocalPoints[triangleVertexIndices[index + 1]];
 4239            Vector3d third = hullLocalPoints[triangleVertexIndices[index + 2]];
 4240            WideGeometry.GetDifferenceCrossProduct3D(
 4241                second.X,
 4242                first.X,
 4243                second.Y,
 4244                first.Y,
 4245                second.Z,
 4246                first.Z,
 4247                third.X,
 4248                first.X,
 4249                third.Y,
 4250                first.Y,
 4251                third.Z,
 4252                first.Z,
 4253                out Signed192 normalX,
 4254                out Signed192 normalY,
 4255                out Signed192 normalZ);
 4256            WideAxis3 axis = WideRigidProjection.TransformLocalAxis(
 4257                hullBasis,
 4258                normalX,
 4259                normalY,
 4260                normalZ);
 4261            if (axis.IsZero)
 62                continue;
 63
 4064            WideRigidProjection.GetLocalAxisProjections(
 4065                axis,
 4066                hullBasis,
 4067                out Signed576 hullAxisX,
 4068                out Signed576 hullAxisY,
 4069                out Signed576 hullAxisZ);
 4070            Signed576 faceProjection = WideRigidProjection.GetLocalOffsetProjection(
 4071                first,
 4072                hullAxisX,
 4073                hullAxisY,
 4074                hullAxisZ);
 4075            Signed576 interiorDelta = WideArithmetic.SubtractSigned576(
 4076                WideRigidProjection.GetLocalOffsetProjection(
 4077                    hullInteriorLocalPoint,
 4078                    hullAxisX,
 4079                    hullAxisY,
 4080                    hullAxisZ),
 4081                faceProjection);
 4082            if (interiorDelta.Sign == 0)
 83                continue;
 84
 3885            Signed576 originProjection = WideRigidProjection.GetWorldOriginDifferenceProjection(
 3886                point.Origin,
 3887                hullOrigin,
 3888                axis);
 3889            WideRigidProjection.GetLocalAxisProjections(
 3890                axis,
 3891                pointBasis,
 3892                out Signed576 pointAxisX,
 3893                out Signed576 pointAxisY,
 3894                out Signed576 pointAxisZ);
 3895            Signed576 pointProjection = WideArithmetic.MultiplySigned576(
 3896                WideArithmetic.AddSigned576(
 3897                    WideArithmetic.MultiplySigned576(
 3898                        originProjection,
 3899                        pointBasis.Denominator),
 38100                    WideRigidProjection.GetLocalOffsetProjection(
 38101                        point.LocalPoint,
 38102                        pointAxisX,
 38103                        pointAxisY,
 38104                        pointAxisZ)),
 38105                hullBasis.Denominator);
 38106            Signed576 faceProjectionCommon = WideArithmetic.MultiplySigned576(
 38107                faceProjection,
 38108                pointBasis.Denominator);
 38109            Signed576 pointDelta = WideArithmetic.SubtractSigned576(
 38110                pointProjection,
 38111                faceProjectionCommon);
 38112            if ((pointDelta.Sign != 0)
 38113                & (pointDelta.Sign != interiorDelta.Sign))
 114            {
 2115                return false;
 116            }
 117        }
 118
 2119        return true;
 120    }
 121
 122    internal static bool TryGetConvexHullContact(
 123        Vector3d firstOrigin,
 124        FixedQuaternion firstRotation,
 125        ReadOnlySpan<Vector3d> firstLocalPoints,
 126        ReadOnlySpan<int> firstTriangleVertexIndices,
 127        ReadOnlySpan<int> firstEdgeVertexPairs,
 128        Vector3d secondOrigin,
 129        FixedQuaternion secondRotation,
 130        ReadOnlySpan<Vector3d> secondLocalPoints,
 131        ReadOnlySpan<int> secondTriangleVertexIndices,
 132        ReadOnlySpan<int> secondEdgeVertexPairs,
 133        out FixedContactAnchors contact)
 134    {
 7135        WideRationalBasis3d firstBasis = new(firstRotation);
 7136        WideRationalBasis3d secondBasis = new(secondRotation);
 7137        if (!TryGetConvexHullPenetration(
 7138                firstOrigin, firstBasis, firstLocalPoints, firstTriangleVertexIndices, firstEdgeVertexPairs,
 7139                secondOrigin, secondBasis, secondLocalPoints, secondTriangleVertexIndices, secondEdgeVertexPairs,
 7140                out WidePointSpanPenetration best, skipParallelDirections: false))
 141        {
 4142            contact = default;
 4143            return false;
 144        }
 145
 3146        WideAxis3 orientedAxis = best.Negate ? -best.Axis : best.Axis;
 3147        Vector3d normal = WideNormalization.GetNormalized(
 3148            Signed576.ExtendValue(orientedAxis.X),
 3149            Signed576.ExtendValue(orientedAxis.Y),
 3150            Signed576.ExtendValue(orientedAxis.Z));
 3151        Vector3d firstLocalPoint = GetHullSupportLocalPoint(
 3152            firstBasis,
 3153            firstLocalPoints,
 3154            orientedAxis,
 3155            maximize: true);
 3156        Vector3d secondLocalPoint = GetHullSupportLocalPoint(
 3157            secondBasis,
 3158            secondLocalPoints,
 3159            orientedAxis,
 3160            maximize: false);
 3161        Fixed64 depth = best.GetRoundedDepth(out bool depthIsClamped);
 3162        contact = new FixedContactAnchors(
 3163            new FixedPointAnchor(
 3164                firstOrigin,
 3165                firstRotation,
 3166                firstLocalPoint),
 3167            new FixedPointAnchor(
 3168                secondOrigin,
 3169                secondRotation,
 3170                secondLocalPoint),
 3171            normal,
 3172            depth,
 3173            depthIsClamped);
 3174        return true;
 175    }
 176
 177    // planarPair requires two convex planar vertex sets with their real boundary edges.
 178    internal static bool TryGetConvexHullPenetration(
 179        Vector3d firstOrigin,
 180        FixedQuaternion firstRotation,
 181        ReadOnlySpan<Vector3d> firstLocalPoints,
 182        ReadOnlySpan<int> firstTriangleVertexIndices,
 183        ReadOnlySpan<int> firstEdgeVertexPairs,
 184        Vector3d secondOrigin,
 185        FixedQuaternion secondRotation,
 186        ReadOnlySpan<Vector3d> secondLocalPoints,
 187        ReadOnlySpan<int> secondTriangleVertexIndices,
 188        ReadOnlySpan<int> secondEdgeVertexPairs,
 189        out WidePointSpanPenetration best, bool skipParallelDirections = false,
 190        PointSpanPenetrationAdmission? admission = null, bool planarPair = false)
 191    {
 65192        WideRationalBasis3d firstBasis = new(firstRotation);
 65193        WideRationalBasis3d secondBasis = new(secondRotation);
 65194        return TryGetConvexHullPenetration(
 65195            firstOrigin, firstBasis, firstLocalPoints, firstTriangleVertexIndices, firstEdgeVertexPairs,
 65196            secondOrigin, secondBasis, secondLocalPoints, secondTriangleVertexIndices, secondEdgeVertexPairs,
 65197            out best, skipParallelDirections, admission, planarPair);
 198    }
 199
 200    private static bool TryGetConvexHullPenetration(
 201        Vector3d firstOrigin, in WideRationalBasis3d firstBasis,
 202        ReadOnlySpan<Vector3d> firstLocalPoints, ReadOnlySpan<int> firstTriangleVertexIndices, ReadOnlySpan<int> firstEd
 203        Vector3d secondOrigin, in WideRationalBasis3d secondBasis,
 204        ReadOnlySpan<Vector3d> secondLocalPoints, ReadOnlySpan<int> secondTriangleVertexIndices, ReadOnlySpan<int> secon
 205        out WidePointSpanPenetration best, bool skipParallelDirections,
 206        PointSpanPenetrationAdmission? admission = null, bool planarPair = false)
 207    {
 72208        best = default;
 72209        bool hasAxis = false;
 210
 72211        if (!TryKeepHullFaceAxes(
 72212                firstLocalPoints,
 72213                firstTriangleVertexIndices,
 72214                firstBasis,
 72215                firstOrigin,
 72216                firstBasis,
 72217                firstLocalPoints,
 72218                secondOrigin,
 72219                secondBasis,
 72220                secondLocalPoints,
 72221                ref best, skipParallelDirections, ref hasAxis, admission)
 72222            || !TryKeepHullFaceAxes(
 72223                secondLocalPoints,
 72224                secondTriangleVertexIndices,
 72225                secondBasis,
 72226                firstOrigin,
 72227                firstBasis,
 72228                firstLocalPoints,
 72229                secondOrigin,
 72230                secondBasis,
 72231                secondLocalPoints,
 72232                ref best, skipParallelDirections, ref hasAxis, admission))
 233        {
 11234            best = default;
 11235            return false;
 236        }
 237
 61238        if (planarPair)
 239        {
 240            // Two finite planar polygons also need their own in-plane edge
 241            // normals. Face normals and cross-edge axes alone cannot separate
 242            // disjoint coplanar polygons. Keep the cross in the local chart:
 243            // raw differences <65 bits, normal <132, cross <198 and transformed
 244            // components <264; crossing transformed normals could exceed 320.
 42245            for (int side = 0; side < 2; side++)
 246            {
 17247                ReadOnlySpan<Vector3d> points = side == 0 ? firstLocalPoints : secondLocalPoints;
 17248                ReadOnlySpan<int> triangles = side == 0 ? firstTriangleVertexIndices : secondTriangleVertexIndices;
 17249                ReadOnlySpan<int> edges = side == 0 ? firstEdgeVertexPairs : secondEdgeVertexPairs;
 17250                ref readonly WideRationalBasis3d basis = ref (side == 0 ? ref firstBasis : ref secondBasis);
 17251                WideAxis3 normal = default;
 68252                for (int triangle = 0; triangle < triangles.Length && normal.IsZero; triangle += 3)
 17253                    normal = GetLocalHullFaceAxis(points, triangles, triangle);
 108254                for (int edge = 0; edge < edges.Length; edge += 2)
 255                {
 45256                    if (skipParallelDirections && !IsFirstHullEdgeDirection(points, edges, edge)) continue;
 90257                    Vector3d start = points[edges[edge]], end = points[edges[edge + 1]];
 45258                    WideAxis3 axis = WideRigidProjection.TransformLocalNormalCrossEdge(basis,
 45259                        Signed192.NarrowProven(normal.X), Signed192.NarrowProven(normal.Y), Signed192.NarrowProven(norma
 45260                        WideArithmetic.Difference(end.X, start.X), WideArithmetic.Difference(end.Y, start.Y),
 45261                        WideArithmetic.Difference(end.Z, start.Z));
 45262                    if (!TryKeepHullPairAxis(axis, firstOrigin, firstBasis, firstLocalPoints,
 45263                            secondOrigin, secondBasis, secondLocalPoints, ref best, ref hasAxis, admission))
 16264                    { best = default; return false; }
 265                }
 266            }
 267        }
 268
 53269        for (int firstIndex = 0;
 649270            firstIndex < firstEdgeVertexPairs.Length;
 596271            firstIndex += 2)
 272        {
 598273            if (skipParallelDirections && !IsFirstHullEdgeDirection(firstLocalPoints, firstEdgeVertexPairs, firstIndex))
 492274            WideAxis3 firstEdge = GetHullEdge(
 492275                firstBasis,
 492276                firstLocalPoints[firstEdgeVertexPairs[firstIndex]],
 492277                firstLocalPoints[firstEdgeVertexPairs[firstIndex + 1]]);
 492278            for (int secondIndex = 0;
 6032279                secondIndex < secondEdgeVertexPairs.Length;
 5540280                secondIndex += 2)
 281            {
 5542282                if (skipParallelDirections && !IsFirstHullEdgeDirection(secondLocalPoints, secondEdgeVertexPairs, second
 5224283                WideAxis3 secondEdge = GetHullEdge(
 5224284                    secondBasis,
 5224285                    secondLocalPoints[secondEdgeVertexPairs[secondIndex]],
 5224286                    secondLocalPoints[secondEdgeVertexPairs[secondIndex + 1]]);
 5224287                if (!TryKeepHullPairAxis(
 5224288                        WideAxis3.Cross(firstEdge, secondEdge),
 5224289                        firstOrigin,
 5224290                        firstBasis,
 5224291                        firstLocalPoints,
 5224292                        secondOrigin,
 5224293                        secondBasis,
 5224294                        secondLocalPoints,
 5224295                        ref best, ref hasAxis, admission))
 296                {
 2297                    best = default;
 2298                    return false;
 299                }
 300            }
 301        }
 302
 303        // Admission restricts response witnesses, never the geometric SAT
 304        // overlap result. Its caller can retain overlap without a response.
 51305        return admission == null ? best.HasValue : hasAxis;
 306    }
 307
 308    internal static int VisitConvexHullContacts<TState>(
 309        Vector3d firstOrigin, FixedQuaternion firstRotation,
 310        ReadOnlySpan<Vector3d> firstLocalPoints, ReadOnlySpan<int> firstTriangleVertexIndices, ReadOnlySpan<int> firstEd
 311        Vector3d secondOrigin, FixedQuaternion secondRotation,
 312        ReadOnlySpan<Vector3d> secondLocalPoints, ReadOnlySpan<int> secondTriangleVertexIndices, ReadOnlySpan<int> secon
 313        in WidePointSpanPenetration penetration, TState state, Action<TState, FixedContactAnchors> visitor,
 314        IConvexHullContactDomain? domain = null, bool admissionOnly = false)
 315    {
 316        System.Diagnostics.Debug.Assert(penetration.HasValue);
 39317        WideAxis3 axis = penetration.Negate ? -penetration.Axis : penetration.Axis;
 39318        Vector3d normal = admissionOnly ? default : WideNormalization.GetNormalized(Signed576.ExtendValue(axis.X),
 39319            Signed576.ExtendValue(axis.Y), Signed576.ExtendValue(axis.Z));
 39320        bool clamped = false;
 39321        Fixed64 depth = admissionOnly ? default : penetration.GetRoundedDepth(out clamped);
 78322        WideRationalBasis3d firstBasis = new(firstRotation), secondBasis = new(secondRotation);
 39323        int count = 0;
 198324        for (int side = 0; side < 2; side++)
 325        {
 70326            bool reverse = side != 0;
 70327            Vector3d sourceOrigin = reverse ? secondOrigin : firstOrigin;
 70328            Vector3d targetOrigin = reverse ? firstOrigin : secondOrigin;
 70329            FixedQuaternion sourceRotation = reverse ? secondRotation : firstRotation;
 70330            FixedQuaternion targetRotation = reverse ? firstRotation : secondRotation;
 70331            ReadOnlySpan<Vector3d> sourcePoints = reverse ? secondLocalPoints : firstLocalPoints;
 70332            ReadOnlySpan<Vector3d> targetPoints = reverse ? firstLocalPoints : secondLocalPoints;
 70333            ReadOnlySpan<int> targetTriangles = reverse ? firstTriangleVertexIndices : secondTriangleVertexIndices;
 70334            ReadOnlySpan<int> sourceEdges = reverse ? secondEdgeVertexPairs : firstEdgeVertexPairs;
 70335            ReadOnlySpan<int> targetEdges = reverse ? firstEdgeVertexPairs : secondEdgeVertexPairs;
 70336            ref readonly WideRationalBasis3d sourceBasis = ref (reverse ? ref secondBasis : ref firstBasis);
 70337            ref readonly WideRationalBasis3d targetBasis = ref (reverse ? ref firstBasis : ref secondBasis);
 70338            WideRigidProjection.GetLocalAxisProjections(axis, sourceBasis,
 70339                out Signed576 sourceX, out Signed576 sourceY, out Signed576 sourceZ);
 70340            WideRigidProjection.GetLocalAxisProjections(axis, targetBasis,
 70341                out Signed576 targetX, out Signed576 targetY, out Signed576 targetZ);
 70342            Signed576 sourceSupport = WideRigidProjection.GetLocalOffsetProjection(
 70343                GetHullSupportLocalPoint(sourceBasis, sourcePoints, axis, maximize: !reverse),
 70344                sourceX, sourceY, sourceZ);
 70345            Signed576 targetSupport = WideRigidProjection.GetLocalOffsetProjection(
 70346                GetHullSupportLocalPoint(targetBasis, targetPoints, axis, maximize: reverse),
 70347                targetX, targetY, targetZ);
 140348            int supportVertices = 0, admittedVertices = 0;
 1040349            for (int vertexIndex = 0; vertexIndex < sourcePoints.Length; vertexIndex++)
 350            {
 453351                Vector3d vertex = sourcePoints[vertexIndex];
 453352                if (!IsSupport(vertex, sourceX, sourceY, sourceZ, sourceSupport)) continue;
 223353                supportVertices++;
 223354                var source = new FixedPointAnchor(sourceOrigin, sourceRotation, vertex);
 3846355                for (int triangle = 0; triangle < targetTriangles.Length; triangle += 3)
 356                {
 1753357                    Vector3d a = targetPoints[targetTriangles[triangle]],
 1753358                        b = targetPoints[targetTriangles[triangle + 1]],
 1753359                        c = targetPoints[targetTriangles[triangle + 2]];
 1753360                    if (!IsSupport(a, targetX, targetY, targetZ, targetSupport)
 1753361                        || !IsSupport(b, targetX, targetY, targetZ, targetSupport)
 1753362                        || !IsSupport(c, targetX, targetY, targetZ, targetSupport)) continue;
 293363                    var face = new FixedTriangle(a, b, c);
 293364                    if (!WideTriangleRelations.ContainsProjection(face, targetOrigin, targetRotation, source)) continue;
 365                    // The domain does not depend on which target triangle
 366                    // admits the vertex. Reject it once, after finite geometry.
 53367                    if (domain != null && !domain.ContainsPoint(!reverse, vertexIndex, vertexIndex,
 53368                        default, Signed832.ExtendValue(Signed192.Signed(1)), axis)) break;
 40369                    if (admissionOnly) return 1;
 34370                    FixedPointAnchor target = WideTriangleRelations.GetClosestPointAnchor(
 34371                        face, targetOrigin, targetRotation, source, preserveExactFace: true);
 34372                    visitor(state, reverse
 34373                        ? new FixedContactAnchors(target, source, normal, depth, clamped)
 34374                        : new FixedContactAnchors(source, target, normal, depth, clamped));
 34375                    count++;
 34376                    admittedVertices++;
 34377                    break;
 378                }
 379            }
 380            // Convexity makes admitted support vertices certify the complete projected feature.
 73381            if (!reverse && supportVertices != 0 && admittedVertices == supportVertices) return count;
 1284382            for (int edge = 0; edge < sourceEdges.Length; edge += 2)
 383            {
 1164384                Vector3d start = sourcePoints[sourceEdges[edge]], end = sourcePoints[sourceEdges[edge + 1]];
 582385                if (!IsSupport(start, sourceX, sourceY, sourceZ, sourceSupport)
 582386                    || !IsSupport(end, sourceX, sourceY, sourceZ, sourceSupport)) continue;
 179387                var first = new FixedPointAnchor(sourceOrigin, sourceRotation, start);
 179388                var second = new FixedPointAnchor(sourceOrigin, sourceRotation, end);
 179389                ReadOnlySpan<RationalSegmentInterval> intervals = domain == null ? default
 179390                    : domain.GetEdgeIntervals(!reverse, sourceEdges[edge], sourceEdges[edge + 1], axis);
 179391                if (domain != null && intervals.IsEmpty) continue;
 2910392                for (int triangle = 0; triangle < targetTriangles.Length; triangle += 3)
 393                {
 3927394                    int ia = targetTriangles[triangle], ib = targetTriangles[triangle + 1], ic = targetTriangles[triangl
 3927395                    Vector3d a = targetPoints[ia], b = targetPoints[ib], c = targetPoints[ic];
 1309396                    if (!IsSupport(a, targetX, targetY, targetZ, targetSupport)
 1309397                        || !IsSupport(b, targetX, targetY, targetZ, targetSupport)
 1309398                        || !IsSupport(c, targetX, targetY, targetZ, targetSupport)) continue;
 205399                    var face = new FixedTriangle(a, b, c);
 205400                    if (!WideTriangleRelations.TryGetProjectedSegmentInterval(face, targetOrigin, targetRotation, first,
 205401                            out Signed832 lowerN, out Signed832 lowerD, out Signed832 upperN, out Signed832 upperD)) con
 106402                    int mask = (HasEdge(ib, ic, targetEdges) ? 1 : 0)
 106403                        | (HasEdge(ic, ia, targetEdges) ? 2 : 0) | (HasEdge(ia, ib, targetEdges) ? 4 : 0);
 422404                    for (int interval = 0; interval < (domain == null ? 1 : intervals.Length); interval++)
 405                    {
 106406                        RationalSegmentInterval clip = domain == null ? default : intervals[interval];
 424407                        Signed832 ln = lowerN, ld = lowerD, un = upperN, ud = upperD;
 106408                        if (!Intersect(clip, ref ln, ref ld, ref un, ref ud)) continue;
 560409                        for (int endpoint = 0; endpoint < 2; endpoint++)
 410                        {
 374411                            Signed832 n = endpoint == 0 ? ln : un, d = endpoint == 0 ? ld : ud;
 187412                            if (n.Sign == 0 || WideArithmetic.SubtractSigned832(d, n).IsZero
 187413                                || domain != null && !domain.ContainsPoint(!reverse, sourceEdges[edge], sourceEdges[edge
 87414                            bool clipEnd = clip.IsClipped && (Equal(n, d, clip.LowerNumerator, clip.LowerDenominator)
 87415                                || Equal(n, d, clip.UpperNumerator, clip.UpperDenominator));
 87416                            if (!WideTriangleRelations.TryGetProjectedSegmentFaceAnchors(face, targetOrigin, targetRotat
 87417                                    first, second, n, d, mask, out FixedPointAnchor source, out FixedPointAnchor target,
 87418                                    requirePhysicalTargetBoundary: !clipEnd, materialize: !admissionOnly)) continue;
 48419                            if (admissionOnly) return 1;
 46420                            visitor(state, reverse
 46421                                ? new FixedContactAnchors(target, source, normal, depth, clamped)
 46422                                : new FixedContactAnchors(source, target, normal, depth, clamped));
 46423                            count++;
 424                        }
 425                    }
 426                }
 427            }
 428        }
 38429        if (count != 0) return count;
 20430        WideRigidProjection.GetLocalAxisProjections(axis, firstBasis,
 20431            out Signed576 firstX, out Signed576 firstY, out Signed576 firstZ);
 20432        WideRigidProjection.GetLocalAxisProjections(axis, secondBasis,
 20433            out Signed576 secondX, out Signed576 secondY, out Signed576 secondZ);
 20434        Signed576 firstSupport = WideRigidProjection.GetLocalOffsetProjection(
 20435            GetHullSupportLocalPoint(firstBasis, firstLocalPoints, axis, maximize: true), firstX, firstY, firstZ);
 20436        Signed576 secondSupport = WideRigidProjection.GetLocalOffsetProjection(
 20437            GetHullSupportLocalPoint(secondBasis, secondLocalPoints, axis, maximize: false), secondX, secondY, secondZ);
 402438        for (int firstEdge = 0; firstEdge < firstEdgeVertexPairs.Length; firstEdge += 2)
 439        {
 370440            Vector3d a = firstLocalPoints[firstEdgeVertexPairs[firstEdge]], b = firstLocalPoints[firstEdgeVertexPairs[fi
 185441            if (!IsSupport(a, firstX, firstY, firstZ, firstSupport) || !IsSupport(b, firstX, firstY, firstZ, firstSuppor
 1082442            for (int secondEdge = 0; secondEdge < secondEdgeVertexPairs.Length; secondEdge += 2)
 443            {
 974444                Vector3d c = secondLocalPoints[secondEdgeVertexPairs[secondEdge]], d = secondLocalPoints[secondEdgeVerte
 487445                if (!IsSupport(c, secondX, secondY, secondZ, secondSupport) || !IsSupport(d, secondX, secondY, secondZ, 
 308446                var firstSegment = new FixedSegment(a, b); var secondSegment = new FixedSegment(c, d);
 154447                if (!WideTriangleRelations.TryGetClosestNonparallelSegmentParameters(
 154448                        firstOrigin, firstRotation, firstSegment, secondOrigin, secondRotation, secondSegment,
 154449                        out Signed832 firstN, out Signed832 firstD, out Signed832 secondN, out Signed832 secondD)) conti
 32450                if (domain != null && (!domain.ContainsPoint(true, firstEdgeVertexPairs[firstEdge], firstEdgeVertexPairs
 32451                    || !domain.ContainsPoint(false, secondEdgeVertexPairs[secondEdge], secondEdgeVertexPairs[secondEdge 
 5452                if (admissionOnly) return 1;
 3453                FixedPointAnchor firstAnchor = new(firstOrigin, firstRotation, WideTriangleRelations.MaterializeSegmentP
 3454                FixedPointAnchor secondAnchor = new(secondOrigin, secondRotation, WideTriangleRelations.MaterializeSegme
 3455                visitor(state, new FixedContactAnchors(firstAnchor, secondAnchor, normal, depth, clamped));
 3456                return 1;
 457            }
 458        }
 16459        return 0;
 460
 461        static bool IsSupport(Vector3d point, Signed576 x, Signed576 y, Signed576 z, Signed576 support) =>
 462            CompareSigned(WideRigidProjection.GetLocalOffsetProjection(point, x, y, z), support) == 0;
 463
 464        static bool HasEdge(int first, int second, ReadOnlySpan<int> edges)
 465        {
 466            for (int index = 0; index < edges.Length; index += 2)
 467                if (edges[index] == first && edges[index + 1] == second
 468                    || edges[index] == second && edges[index + 1] == first) return true;
 469            return false;
 470        }
 471
 472        static bool Equal(Signed832 n, Signed832 d, Signed320 otherN, Signed320 otherD) =>
 473            WideArithmetic.CompareNonNegativeProducts(n, Signed832.ExtendValue(Signed576.ExtendValue(otherD)),
 474                Signed832.ExtendValue(Signed576.ExtendValue(otherN)), d) == 0;
 475
 476        static bool Intersect(in RationalSegmentInterval clip, ref Signed832 ln, ref Signed832 ld,
 477            ref Signed832 un, ref Signed832 ud)
 478        {
 479            if (!clip.IsClipped) return true;
 480            Signed832 n = Signed832.ExtendValue(Signed576.ExtendValue(clip.LowerNumerator)),
 481                d = Signed832.ExtendValue(Signed576.ExtendValue(clip.LowerDenominator));
 482            if (WideArithmetic.CompareNonNegativeProducts(n, ld, ln, d) > 0) { ln = n; ld = d; }
 483            n = Signed832.ExtendValue(Signed576.ExtendValue(clip.UpperNumerator));
 484            d = Signed832.ExtendValue(Signed576.ExtendValue(clip.UpperDenominator));
 485            if (WideArithmetic.CompareNonNegativeProducts(n, ud, un, d) < 0) { un = n; ud = d; }
 486            return WideArithmetic.CompareNonNegativeProducts(ln, ud, un, ld) <= 0;
 487        }
 488    }
 489
 490    private static bool TryKeepHullFaceAxes(
 491        ReadOnlySpan<Vector3d> axisSourcePoints,
 492        ReadOnlySpan<int> axisSourceTriangles,
 493        in WideRationalBasis3d axisBasis,
 494        Vector3d firstOrigin,
 495        in WideRationalBasis3d firstBasis,
 496        ReadOnlySpan<Vector3d> firstPoints,
 497        Vector3d secondOrigin,
 498        in WideRationalBasis3d secondBasis,
 499        ReadOnlySpan<Vector3d> secondPoints,
 500        ref WidePointSpanPenetration best, bool skipParallelDirections, ref bool hasAxis, PointSpanPenetrationAdmission?
 501    {
 2830502        for (int index = 0; index < axisSourceTriangles.Length; index += 3)
 503        {
 1293504            WideAxis3 local = GetLocalHullFaceAxis(axisSourcePoints, axisSourceTriangles, index);
 1293505            if (local.IsZero) continue;
 1235506            bool duplicate = false;
 6358507            for (int previous = 0; skipParallelDirections && previous < index; previous += 3)
 508            {
 2162509                WideAxis3 earlier = GetLocalHullFaceAxis(axisSourcePoints, axisSourceTriangles, previous);
 2598510                if (!earlier.IsZero && WideAxis3.Cross(local, earlier).IsZero) { duplicate = true; break; }
 511            }
 1235512            if (duplicate) continue;
 1017513            if (!TryKeepHullPairAxis(
 1017514                    WideRigidProjection.TransformLocalAxis(
 1017515                        axisBasis,
 1017516                        Signed192.NarrowProven(local.X),
 1017517                        Signed192.NarrowProven(local.Y),
 1017518                        Signed192.NarrowProven(local.Z)),
 1017519                    firstOrigin,
 1017520                    firstBasis,
 1017521                    firstPoints,
 1017522                    secondOrigin,
 1017523                    secondBasis,
 1017524                    secondPoints,
 1017525                    ref best, ref hasAxis, admission))
 526            {
 11527                return false;
 528            }
 529        }
 530
 122531        return true;
 532    }
 533
 534    private static WideAxis3 GetLocalHullFaceAxis(ReadOnlySpan<Vector3d> points, ReadOnlySpan<int> triangles, int index)
 535    {
 10416536        Vector3d a = points[triangles[index]], b = points[triangles[index + 1]], c = points[triangles[index + 2]];
 3472537        WideGeometry.GetDifferenceCrossProduct3D(b.X, a.X, b.Y, a.Y, b.Z, a.Z,
 3472538            c.X, a.X, c.Y, a.Y, c.Z, a.Z, out Signed192 x, out Signed192 y, out Signed192 z);
 3472539        return new WideAxis3(Signed320.ExtendValue(x), Signed320.ExtendValue(y), Signed320.ExtendValue(z));
 540    }
 541
 542    private static bool IsFirstHullEdgeDirection(ReadOnlySpan<Vector3d> points, ReadOnlySpan<int> edges, int index)
 543    {
 920544        WideAxis3 local = Direction(points[edges[index]], points[edges[index + 1]]);
 936545        if (local.IsZero) return false;
 546        // Local edge/face crosses fit 132/264 bits; crossing already transformed SAT axes need not fit.
 9864547        for (int previous = 0; previous < index; previous += 2)
 548        {
 4728549            WideAxis3 earlier = Direction(points[edges[previous]], points[edges[previous + 1]]);
 5428550            if (!earlier.IsZero && WideAxis3.Cross(local, earlier).IsZero) return false;
 551        }
 204552        return true;
 553
 554        static WideAxis3 Direction(Vector3d first, Vector3d second) => new(
 555            Signed320.ExtendValue(WideArithmetic.Difference(second.X, first.X)),
 556            Signed320.ExtendValue(WideArithmetic.Difference(second.Y, first.Y)),
 557            Signed320.ExtendValue(WideArithmetic.Difference(second.Z, first.Z)));
 558    }
 559
 560    private static bool TryKeepHullPairAxis(
 561        in WideAxis3 axis,
 562        Vector3d firstOrigin,
 563        in WideRationalBasis3d firstBasis,
 564        ReadOnlySpan<Vector3d> firstPoints,
 565        Vector3d secondOrigin,
 566        in WideRationalBasis3d secondBasis,
 567        ReadOnlySpan<Vector3d> secondPoints,
 568        ref WidePointSpanPenetration best, ref bool hasAxis, PointSpanPenetrationAdmission? admission)
 569    {
 6286570        if (axis.IsZero)
 1451571            return true;
 4835572        hasAxis = true;
 573
 4835574        GetHullProjectionInterval(
 4835575            firstPoints,
 4835576            firstBasis,
 4835577            axis,
 4835578            secondBasis.Denominator,
 4835579            out Signed576 firstMinimum,
 4835580            out Signed576 firstMaximum);
 4835581        GetHullProjectionInterval(
 4835582            secondPoints,
 4835583            secondBasis,
 4835584            axis,
 4835585            firstBasis.Denominator,
 4835586            out Signed576 secondMinimum,
 4835587            out Signed576 secondMaximum);
 4835588        Signed576 originProjection = WideRigidProjection.GetWorldOriginDifferenceProjection(
 4835589            secondOrigin,
 4835590            firstOrigin,
 4835591            axis);
 4835592        Signed576 originCommon = WideArithmetic.MultiplySigned576(
 4835593            WideArithmetic.MultiplySigned576(
 4835594                originProjection,
 4835595                secondBasis.Denominator),
 4835596            firstBasis.Denominator);
 4835597        secondMinimum = WideArithmetic.AddSigned576(
 4835598            secondMinimum,
 4835599            originCommon);
 4835600        secondMaximum = WideArithmetic.AddSigned576(
 4835601            secondMaximum,
 4835602            originCommon);
 603
 4835604        Signed576 pushFirstNegative = WideArithmetic.SubtractSigned576(
 4835605            firstMaximum,
 4835606            secondMinimum);
 4835607        Signed576 pushFirstPositive = WideArithmetic.SubtractSigned576(
 4835608            secondMaximum,
 4835609            firstMinimum);
 4835610        if (pushFirstNegative.Sign < 0 || pushFirstPositive.Sign < 0)
 21611            return false;
 612
 4814613        bool negate = CompareSigned(
 4814614            pushFirstPositive,
 4814615            pushFirstNegative) < 0;
 4814616        Signed576 overlap = negate
 4814617            ? pushFirstPositive
 4814618            : pushFirstNegative;
 4814619        Signed320 commonDenominator = WideArithmetic.MultiplySigned192(
 4814620            firstBasis.Denominator,
 4814621            secondBasis.Denominator);
 4814622        Signed576 squaredAxisLength = axis.SquaredLength;
 4814623        if (best.ShouldReplace(
 4814624            overlap,
 4814625            squaredAxisLength,
 4814626            commonDenominator))
 627        {
 421628            var candidate = new WidePointSpanPenetration(
 421629                axis,
 421630                negate,
 421631                overlap,
 421632                squaredAxisLength,
 421633                commonDenominator);
 539634            if (admission == null || admission(candidate)) best = candidate;
 635        }
 636
 4814637        if (admission != null)
 638        {
 755639            overlap = negate ? pushFirstNegative : pushFirstPositive;
 755640            if (best.ShouldReplace(overlap, squaredAxisLength, commonDenominator))
 641            {
 253642                var candidate = new WidePointSpanPenetration(axis, !negate, overlap, squaredAxisLength, commonDenominato
 255643                if (admission(candidate)) best = candidate;
 644            }
 645        }
 646
 4814647        return true;
 648    }
 649
 650    private static void GetHullProjectionInterval(
 651        ReadOnlySpan<Vector3d> points,
 652        in WideRationalBasis3d basis,
 653        in WideAxis3 axis,
 654        Signed192 otherDenominator,
 655        out Signed576 minimum,
 656        out Signed576 maximum)
 657    {
 11476658        WideRigidProjection.GetLocalAxisProjections(
 11476659            axis,
 11476660            basis,
 11476661            out Signed576 localAxisX,
 11476662            out Signed576 localAxisY,
 11476663            out Signed576 localAxisZ);
 11476664        minimum = WideArithmetic.MultiplySigned576(
 11476665            WideRigidProjection.GetLocalOffsetProjection(
 11476666                points[0],
 11476667                localAxisX,
 11476668                localAxisY,
 11476669                localAxisZ),
 11476670            otherDenominator);
 11476671        maximum = minimum;
 161672672        for (int index = 1; index < points.Length; index++)
 673        {
 69360674            WideRigidProjection.IncludeProjection(
 69360675                WideArithmetic.MultiplySigned576(
 69360676                    WideRigidProjection.GetLocalOffsetProjection(
 69360677                        points[index],
 69360678                        localAxisX,
 69360679                        localAxisY,
 69360680                        localAxisZ),
 69360681                    otherDenominator),
 69360682                ref minimum,
 69360683                ref maximum);
 684        }
 11476685    }
 686
 687    private static WideAxis3 GetHullEdge(
 688        in WideRationalBasis3d basis,
 689        Vector3d start,
 690        Vector3d end) =>
 9746691        WideRigidProjection.TransformLocalAxis(
 9746692            basis,
 9746693            WideArithmetic.SubtractSigned192(Signed192.Raw(end.X), Signed192.Raw(start.X)),
 9746694            WideArithmetic.SubtractSigned192(Signed192.Raw(end.Y), Signed192.Raw(start.Y)),
 9746695            WideArithmetic.SubtractSigned192(Signed192.Raw(end.Z), Signed192.Raw(start.Z)));
 696
 697    private static Vector3d GetHullSupportLocalPoint(
 698        in WideRationalBasis3d basis,
 699        ReadOnlySpan<Vector3d> points,
 700        in WideAxis3 axis,
 701        bool maximize)
 702    {
 329703        WideRigidProjection.GetLocalAxisProjections(
 329704            axis,
 329705            basis,
 329706            out Signed576 localAxisX,
 329707            out Signed576 localAxisY,
 329708            out Signed576 localAxisZ);
 329709        Vector3d best = points[0];
 329710        Signed576 bestProjection = WideRigidProjection.GetLocalOffsetProjection(
 329711            best,
 329712            localAxisX,
 329713            localAxisY,
 329714            localAxisZ);
 4054715        for (int index = 1; index < points.Length; index++)
 716        {
 1698717            Vector3d candidate = points[index];
 1698718            Signed576 projection = WideRigidProjection.GetLocalOffsetProjection(
 1698719                candidate,
 1698720                localAxisX,
 1698721                localAxisY,
 1698722                localAxisZ);
 1698723            int comparison = CompareSigned(projection, bestProjection);
 1698724            if (maximize ? comparison > 0 : comparison < 0)
 725            {
 87726                best = candidate;
 87727                bestProjection = projection;
 728            }
 729        }
 730
 329731        return best;
 732    }
 733}

/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    {
 23343        return new Vector3d(
 23344            WideRigidProjection.GetBasisAxisProjection(axis, basis.Xx, basis.Xy, basis.Xz).Sign > 0
 23345                ? halfExtents.X
 23346                : -halfExtents.X,
 23347            WideRigidProjection.GetBasisAxisProjection(axis, basis.Yx, basis.Yy, basis.Yz).Sign > 0
 23348                ? halfExtents.Y
 23349                : -halfExtents.Y,
 23350            WideRigidProjection.GetBasisAxisProjection(axis, basis.Zx, basis.Zy, basis.Zz).Sign > 0
 23351                ? halfExtents.Z
 23352                : -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) =>
 972410        new(
 972411            WideArithmetic.SubtractSigned320(default, axis.Z),
 972412            default,
 972413            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        {
 34640            Axis = axis;
 34641            Negate = negate;
 34642            Depth = depth;
 34643            DepthIsClamped = depthIsClamped;
 34644            Rational = rational;
 34645            RadialNumerator = radialNumerator;
 34646            RadialDenominator = radialDenominator;
 34647            AxisSquared = axisSquared;
 34648            HasValue = true;
 34649        }
 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    {
 74373        WideRationalBasis3d basis = new(orientation);
 74374        GetDirectionProjections(
 74375            worldDirection,
 74376            basis,
 74377            out Signed320 x,
 74378            out Signed320 y,
 74379            out Signed320 z);
 74380        return new Vector3d(
 74381            x.Sign > 0 ? halfExtents.X : -halfExtents.X,
 74382            y.Sign > 0 ? halfExtents.Y : -halfExtents.Y,
 74383            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    {
 735256        WideRationalBasis3d basis = new(orientation);
 735257        Signed576 denominator = ToSigned576(basis.Denominator);
 735258        bool representable = TryMaterializeCoordinate(
 735259            center.X,
 735260            basis.Xx,
 735261            basis.Yx,
 735262            basis.Zx,
 735263            basis.Denominator,
 735264            denominator,
 735265            localPoint,
 735266            out Fixed64 x)
 735267            & TryMaterializeCoordinate(
 735268                center.Y,
 735269                basis.Xy,
 735270                basis.Yy,
 735271                basis.Zy,
 735272                basis.Denominator,
 735273                denominator,
 735274                localPoint,
 735275                out Fixed64 y)
 735276            & TryMaterializeCoordinate(
 735277                center.Z,
 735278                basis.Xz,
 735279                basis.Yz,
 735280                basis.Zz,
 735281                basis.Denominator,
 735282                denominator,
 735283                localPoint,
 735284                out Fixed64 z);
 735285        if (!representable)
 286        {
 8287            worldPoint = default;
 8288            return false;
 289        }
 290
 727291        worldPoint = new Vector3d(x, y, z);
 727292        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) =>
 168348        TryMaterializeLocalPoint(
 168349            Vector3d.Zero,
 168350            orientation,
 168351            localOffset,
 168352            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    {
 1774573        Signed192 directionX = Signed192.Raw(direction.X);
 1774574        Signed192 directionY = Signed192.Raw(direction.Y);
 1774575        Signed192 directionZ = Signed192.Raw(direction.Z);
 1774576        x = WideArithmetic.GetDotProduct3D(directionX, directionY, directionZ, basis.Xx, basis.Xy, basis.Xz);
 1774577        y = WideArithmetic.GetDotProduct3D(directionX, directionY, directionZ, basis.Yx, basis.Yy, basis.Yz);
 1774578        z = WideArithmetic.GetDotProduct3D(directionX, directionY, directionZ, basis.Zx, basis.Zy, basis.Zz);
 1774579    }
 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    {
 22411590        Signed192 differenceX = WideArithmetic.SubtractSigned192(Signed192.Raw(point.X), Signed192.Raw(center.X));
 22411591        Signed192 differenceY = WideArithmetic.SubtractSigned192(Signed192.Raw(point.Y), Signed192.Raw(center.Y));
 22411592        Signed192 differenceZ = WideArithmetic.SubtractSigned192(Signed192.Raw(point.Z), Signed192.Raw(center.Z));
 22411593        x = WideArithmetic.GetDotProduct3D(differenceX, differenceY, differenceZ, basis.Xx, basis.Xy, basis.Xz);
 22411594        y = WideArithmetic.GetDotProduct3D(differenceX, differenceY, differenceZ, basis.Yx, basis.Yy, basis.Yz);
 22411595        z = WideArithmetic.GetDotProduct3D(differenceX, differenceY, differenceZ, basis.Zx, basis.Zy, basis.Zz);
 22411596    }
 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) =>
 11236622        WideArithmetic.MultiplySigned192(Signed192.Raw(extent), denominator);
 623
 624    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 625    private static Signed576 GetMagnitude(Signed576 value) =>
 258879626        value.Sign < 0
 258879627            ? WideArithmetic.SubtractSigned576(default, value)
 258879628            : value;
 629
 630    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 631    private static Signed320 GetMagnitude(Signed320 value) =>
 22428632        value.Sign < 0
 22428633            ? WideArithmetic.SubtractSigned320(default, value)
 22428634            : 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    {
 2121692        if (negate)
 693        {
 9694            x = WideArithmetic.SubtractSigned192(default, x);
 9695            y = WideArithmetic.SubtractSigned192(default, y);
 9696            z = WideArithmetic.SubtractSigned192(default, z);
 697        }
 698
 2121699        Signed576 denominatorWide = ToSigned576(denominator);
 2121700        Signed192 scale = Signed192.Signed(1L << FixedMath.SHIFT_AMOUNT_I);
 2121701        _ = Fixed64.TryGetSignedRawRatio(
 2121702            Signed576.ExtendValue(WideArithmetic.MultiplySigned192(x, scale)),
 2121703            denominatorWide,
 2121704            out Fixed64 roundedX);
 2121705        _ = Fixed64.TryGetSignedRawRatio(
 2121706            Signed576.ExtendValue(WideArithmetic.MultiplySigned192(y, scale)),
 2121707            denominatorWide,
 2121708            out Fixed64 roundedY);
 2121709        _ = Fixed64.TryGetSignedRawRatio(
 2121710            Signed576.ExtendValue(WideArithmetic.MultiplySigned192(z, scale)),
 2121711            denominatorWide,
 2121712            out Fixed64 roundedZ);
 2121713        return new Vector3d(roundedX, roundedY, roundedZ);
 714    }
 715
 716    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 717    private static int CompareSigned(Signed320 left, Signed320 right)
 718    {
 84254719        int leftSign = left.Sign;
 84254720        int rightSign = right.Sign;
 84254721        if (leftSign != rightSign)
 38439722            return leftSign < rightSign ? -1 : 1;
 45815723        return WideArithmetic.SubtractSigned320(left, right).Sign;
 724    }
 725
 726    private static int CompareSigned(Signed576 left, Signed576 right) =>
 45000727        WideArithmetic.SubtractSigned576(left, right).Sign;
 728
 729    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 730    private static Signed576 ToSigned576(Signed192 value) =>
 4527731        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>Exact minimum-depth contact with a finite cylinder.</content>
 13internal static partial class WideOrientedBox
 14{
 15    internal static bool TryGetCenteredCylinderContact(
 16        Vector3d center, FixedQuaternion orientation, Vector3d halfExtents,
 17        Vector3d cylinderCenter, FixedQuaternion cylinderRotation,
 18        Vector3d localCylinderAxisDirection, Fixed64 cylinderAxisLength,
 19        Fixed64 cylinderRadius, out FixedContactAnchors contact) =>
 14720        TryGetCenteredCylinderContact(center, orientation, halfExtents,
 14721            cylinderCenter, cylinderRotation, localCylinderAxisDirection,
 14722            cylinderAxisLength, cylinderRadius, out contact, out _);
 23
 24    internal static bool TryGetCenteredCylinderContact(
 25        Vector3d center, FixedQuaternion orientation, Vector3d halfExtents,
 26        Vector3d cylinderCenter, FixedQuaternion cylinderRotation,
 27        Vector3d localCylinderAxisDirection, Fixed64 cylinderAxisLength,
 28        Fixed64 cylinderRadius, out FixedContactAnchors contact,
 29        out CenteredCylinderContactFeature feature)
 30    {
 118231        contact = default;
 118232        feature = default;
 118233        if (!CanOverlapCenteredCapsule(center, orientation, halfExtents,
 118234                cylinderCenter, cylinderRotation, localCylinderAxisDirection,
 118235                cylinderAxisLength, cylinderRadius))
 636            return false;
 37
 117638        var geometry = new BoxCylinderGeometry(center, orientation, halfExtents,
 117639            cylinderCenter, cylinderRotation, localCylinderAxisDirection,
 117640            cylinderAxisLength, cylinderRadius);
 117641        Span<ulong> values = stackalloc ulong[ConvexContactCandidate.Slots * ConvexContactCandidate.Words];
 117642        Span<int> signs = stackalloc int[ConvexContactCandidate.Slots];
 117643        if (!BoxCylinderAnalyticFeatures.TryGetBest(geometry, values, signs,
 117644                out int gapSign, out Vector3d localSigns))
 1445            return false;
 116246        var best = new ConvexContactCandidate(values, signs, gapSign);
 116247        WideConvexPrismRelations.GetRoundedConvexContactCandidateDepth(best, Fixed64.Zero,
 116248            out Fixed64 analyticDepth, out bool analyticClamped);
 116249        bool edgeWinner = false;
 116250        Vector3d normal = default;
 116251        Fixed64 depth = default;
 116252        bool clamped = false;
 116253        if (cylinderRadius != Fixed64.Zero)
 54        {
 115755            if (!BoxCylinderEdgeContacts.TryGetContact(geometry, best, analyticDepth, analyticClamped,
 115756                    out edgeWinner, out normal, out depth, out clamped, out Vector3d edgeSigns))
 257                return false;
 115558            if (edgeWinner)
 3459                localSigns = edgeSigns;
 60        }
 116061        if (!edgeWinner)
 62        {
 112663            normal = WideConvexPrismRelations.GetConvexContactCandidateNormal(best);
 112664            depth = analyticDepth;
 112665            clamped = analyticClamped;
 112666            feature = GetCylinderCapFace(geometry.Axis, localSigns);
 67        }
 68
 69        // Preserve the existing lexicographically negative support tie. The
 70        // signs come from the exact selected direction, never its rounded normal.
 116071        Vector3d localPoint = new(localSigns.X > Fixed64.Zero ? halfExtents.X : -halfExtents.X,
 116072            localSigns.Y > Fixed64.Zero ? halfExtents.Y : -halfExtents.Y,
 116073            localSigns.Z > Fixed64.Zero ? halfExtents.Z : -halfExtents.Z);
 116074        FixedPointAnchor cylinderAnchor = WideGeometry.GetCenteredCylinderSupportAnchor(
 116075            cylinderCenter, cylinderRotation, localCylinderAxisDirection,
 116076            cylinderAxisLength, cylinderRadius, -normal);
 116077        contact = new FixedContactAnchors(new FixedPointAnchor(center, orientation, localPoint),
 116078            cylinderAnchor, normal, depth, clamped);
 116079        return true;
 80    }
 81
 82    private static CenteredCylinderContactFeature GetCylinderCapFace(WideAxis3 cylinderAxis, Vector3d localSigns)
 83    {
 112684        int x = localSigns.X.m_rawValue.CompareTo(0L);
 112685        int y = localSigns.Y.m_rawValue.CompareTo(0L);
 112686        int z = localSigns.Z.m_rawValue.CompareTo(0L);
 112687        if (x != 0 && y == 0 && z == 0 && cylinderAxis.Y.IsZero && cylinderAxis.Z.IsZero)
 588            return new CenteredCylinderContactFeature(0, x, -x * cylinderAxis.X.Sign);
 112189        if (y != 0 && x == 0 && z == 0 && cylinderAxis.X.IsZero && cylinderAxis.Z.IsZero)
 101490            return new CenteredCylinderContactFeature(1, y, -y * cylinderAxis.Y.Sign);
 10791        if (z != 0 && x == 0 && y == 0 && cylinderAxis.X.IsZero && cylinderAxis.Y.IsZero)
 292            return new CenteredCylinderContactFeature(2, z, -z * cylinderAxis.Z.Sign);
 10593        return default;
 94    }
 95}

/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        {
 406823            U = u;
 406824            V = v;
 406825        }
 26
 27        internal Signed320 U { get; }
 28        internal Signed320 V { get; }
 29
 30        public bool Equals(LocalCapContact other) =>
 608731            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    {
 102755        count = 0;
 102756        if (!feature.IsCapFace)
 1057            return;
 58
 101759        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.
 101763        FixedPointAnchor capCenterAnchor =
 101764            WideGeometry.GetCenteredCylinderSupportAnchor(
 101765            cylinderCenter,
 101766            cylinderRotation,
 101767            localCylinderAxis,
 101768            cylinderLength,
 101769            Fixed64.Zero,
 101770            -primary.Normal,
 101771            feature.CylinderCapSign);
 101772        _ = capCenterAnchor.TryGetOffsetFrom(
 101773            new FixedPointAnchor(
 101774                cylinderCenter,
 101775                FixedQuaternion.Identity,
 101776                Vector3d.Zero),
 101777            out Vector3d capCenterOffset);
 78
 101779        WideRationalBasis3d basis = new(boxOrientation);
 101780        GetPointProjections(
 101781            cylinderCenter,
 101782            boxCenter,
 101783            basis,
 101784            out Signed320 centerX,
 101785            out Signed320 centerY,
 101786            out Signed320 centerZ);
 101787        GetDirectionProjections(
 101788            capCenterOffset,
 101789            basis,
 101790            out Signed320 capX,
 101791            out Signed320 capY,
 101792            out Signed320 capZ);
 101793        centerX = WideArithmetic.AddSigned320(centerX, capX);
 101794        centerY = WideArithmetic.AddSigned320(centerY, capY);
 101795        centerZ = WideArithmetic.AddSigned320(centerZ, capZ);
 96
 101797        Signed320 extentX = GetExtentNumerator(
 101798            boxHalfExtents.X,
 101799            basis.Denominator);
 1017100        Signed320 extentY = GetExtentNumerator(
 1017101            boxHalfExtents.Y,
 1017102            basis.Denominator);
 1017103        Signed320 extentZ = GetExtentNumerator(
 1017104            boxHalfExtents.Z,
 1017105            basis.Denominator);
 1017106        Signed320 radius = WideArithmetic.MultiplySigned192(
 1017107            Signed192.Raw(cylinderRadius),
 1017108            basis.Denominator);
 1017109        GetFaceCoordinates(
 1017110            faceAxis,
 1017111            centerX,
 1017112            centerY,
 1017113            centerZ,
 1017114            extentX,
 1017115            extentY,
 1017116            extentZ,
 1017117            out Signed320 centerU,
 1017118            out Signed320 centerV,
 1017119            out Signed320 extentU,
 1017120            out Signed320 extentV);
 1017121        Span<LocalCapContact> localContacts =
 1017122            stackalloc LocalCapContact[4];
 1017123        KeepCapExtreme(
 1017124            centerU,
 1017125            centerV,
 1017126            extentU,
 1017127            extentV,
 1017128            radius,
 1017129            positive: false,
 1017130            primaryAxisIsU: true,
 1017131            localContacts,
 1017132            ref count);
 1017133        KeepCapExtreme(
 1017134            centerU,
 1017135            centerV,
 1017136            extentU,
 1017137            extentV,
 1017138            radius,
 1017139            positive: true,
 1017140            primaryAxisIsU: true,
 1017141            localContacts,
 1017142            ref count);
 1017143        KeepCapExtreme(
 1017144            centerV,
 1017145            centerU,
 1017146            extentV,
 1017147            extentU,
 1017148            radius,
 1017149            positive: false,
 1017150            primaryAxisIsU: false,
 1017151            localContacts,
 1017152            ref count);
 1017153        KeepCapExtreme(
 1017154            centerV,
 1017155            centerU,
 1017156            extentV,
 1017157            extentU,
 1017158            radius,
 1017159            positive: true,
 1017160            primaryAxisIsU: false,
 1017161            localContacts,
 1017162            ref count);
 163
 1017164        FixedPointAnchor cylinderSupport =
 1017165            WideGeometry.GetCenteredCylinderSupportAnchor(
 1017166                cylinderCenter,
 1017167                cylinderRotation,
 1017168                localCylinderAxis,
 1017169                cylinderLength,
 1017170                Fixed64.Zero,
 1017171                -primary.Normal,
 1017172                feature.CylinderCapSign);
 1017173        Fixed64 supportAxial =
 1017174            Vector3d.Dot(cylinderSupport.LocalPoint, localCylinderAxis);
 1017175        int outputCount = 0;
 10140176        for (int index = 0; index < count; index++)
 177        {
 4053178            LocalCapContact local = localContacts[index];
 4053179            GetLocalCoordinates(
 4053180                faceAxis,
 4053181                local.U,
 4053182                local.V,
 4053183                GetSignedFaceExtent(
 4053184                    faceAxis,
 4053185                    feature.BoxFaceSign,
 4053186                    extentX,
 4053187                    extentY,
 4053188                    extentZ),
 4053189                out Signed320 localX,
 4053190                out Signed320 localY,
 4053191                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.
 4053195            Vector3d boxLocalPoint = GetRationalLocalPoint(
 4053196                localX,
 4053197                localY,
 4053198                localZ,
 4053199                basis.Denominator);
 200
 4053201            var boxPoint = new FixedPointAnchor(
 4053202                boxCenter,
 4053203                boxOrientation,
 4053204                boxLocalPoint);
 4053205            _ = boxPoint.TryGetLocalPointIn(
 4053206                cylinderCenter,
 4053207                cylinderRotation,
 4053208                out Vector3d cylinderLocalPoint);
 209
 4053210            Fixed64 currentAxial =
 4053211                Vector3d.Dot(cylinderLocalPoint, localCylinderAxis);
 4053212            cylinderLocalPoint +=
 4053213                localCylinderAxis * (supportAxial - currentAxial);
 4053214            contacts[outputCount++] = new FixedContactLocalPoints(
 4053215                boxLocalPoint,
 4053216                cylinderLocalPoint);
 217        }
 218
 1017219        count = outputCount;
 1017220    }
 221
 222    private static Vector3d GetRationalLocalPoint(
 223        Signed320 xNumerator,
 224        Signed320 yNumerator,
 225        Signed320 zNumerator,
 226        Signed192 denominator)
 227    {
 4053228        Signed576 denominatorWide = Signed576.ExtendValue(
 4053229            Signed320.ExtendValue(denominator));
 4053230        _ = Fixed64.TryGetSignedRawRatio(
 4053231            Signed576.ExtendValue(xNumerator),
 4053232            denominatorWide,
 4053233            out Fixed64 x);
 4053234        _ = Fixed64.TryGetSignedRawRatio(
 4053235            Signed576.ExtendValue(yNumerator),
 4053236            denominatorWide,
 4053237            out Fixed64 y);
 4053238        _ = Fixed64.TryGetSignedRawRatio(
 4053239            Signed576.ExtendValue(zNumerator),
 4053240            denominatorWide,
 4053241            out Fixed64 z);
 4053242        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    {
 1017258        if (faceAxis == 0)
 259        {
 1260            u = y;
 1261            v = z;
 1262            extentU = extentY;
 1263            extentV = extentZ;
 1264            return;
 265        }
 1016266        if (faceAxis == 1)
 267        {
 1014268            u = x;
 1014269            v = z;
 1014270            extentU = extentX;
 1014271            extentV = extentZ;
 1014272            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    {
 4068292        Signed320 secondary = ClampToExtent(
 4068293            centerSecondary,
 4068294            extentSecondary);
 4068295        Signed320 secondaryDelta = WideArithmetic.SubtractSigned320(
 4068296            secondary,
 4068297            centerSecondary);
 4068298        Signed576 radialSquared = WideArithmetic.SubtractSigned576(
 4068299            WideArithmetic.MultiplySigned320(radius, radius),
 4068300            WideArithmetic.MultiplySigned320(
 4068301                secondaryDelta,
 4068302                secondaryDelta));
 4068303        Signed576 remaining = WideArithmetic.GetFloorSquareRoot(
 4068304            Signed704.ExtendValue(radialSquared));
 4068305        Signed576 center = Signed576.ExtendValue(centerPrimary);
 4068306        Signed576 extreme = positive
 4068307            ? WideArithmetic.AddSigned576(center, remaining)
 4068308            : WideArithmetic.SubtractSigned576(center, remaining);
 4068309        Signed576 minimum = Signed576.ExtendValue(
 4068310            WideArithmetic.SubtractSigned320(default, extentPrimary));
 4068311        Signed576 maximum = Signed576.ExtendValue(extentPrimary);
 4068312        if (CompareSigned(extreme, minimum) < 0)
 2313            extreme = minimum;
 4066314        else if (CompareSigned(extreme, maximum) > 0)
 5315            extreme = maximum;
 316        // The extreme was just clamped between Signed320 extents.
 4068317        Signed320 primary = new(
 4068318            extreme.Word4,
 4068319            extreme.Word3,
 4068320            extreme.Word2,
 4068321            extreme.Word1,
 4068322            extreme.Word0);
 323
 4068324        LocalCapContact candidate = primaryAxisIsU
 4068325            ? new LocalCapContact(primary, secondary)
 4068326            : new LocalCapContact(secondary, primary);
 20280327        for (int index = 0; index < count; index++)
 328        {
 6087329            if (contacts[index].Equals(candidate))
 15330                return;
 331        }
 332
 4053333        contacts[count++] = candidate;
 4053334    }
 335
 336    private static Signed320 GetSignedFaceExtent(
 337        int faceAxis,
 338        int faceSign,
 339        Signed320 extentX,
 340        Signed320 extentY,
 341        Signed320 extentZ)
 342    {
 4053343        Signed320 extent = faceAxis == 0
 4053344            ? extentX
 4053345            : faceAxis == 1
 4053346                ? extentY
 4053347                : extentZ;
 4053348        return faceSign < 0
 4053349            ? WideArithmetic.SubtractSigned320(default, extent)
 4053350            : 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    {
 4053362        if (faceAxis == 0)
 363        {
 4364            x = face;
 4365            y = u;
 4366            z = v;
 4367            return;
 368        }
 4049369        if (faceAxis == 1)
 370        {
 4041371            x = u;
 4041372            y = face;
 4041373            z = v;
 4041374            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    {
 4068386        Signed320 minimum =
 4068387            WideArithmetic.SubtractSigned320(default, extent);
 4068388        if (CompareSigned(value, minimum) < 0)
 2389            return minimum;
 4066390        return CompareSigned(value, extent) > 0 ? extent : value;
 391    }
 392}

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

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.CylinderStrictOverlap.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/// Complete strict finite-cylinder tests against triangles and convex solids.
 14/// Cap clipping and radial minimization preserve exact rigid-frame fractions.
 15/// </content>
 16internal static partial class WideOrientedBox
 17{
 18    /// <summary>
 19    /// Tests positive-volume overlap of a local-+Y cylinder with an oriented
 20    /// box. Rotations are normalized, height/radius and all half-extents positive.
 21    /// No world vertex, witness, normal, or penetration depth is materialized.
 22    /// </summary>
 23    internal static bool DoesCenteredCylinderPenetrateBox(
 24        Vector3d cylinderCenter, FixedQuaternion cylinderRotation, Fixed64 height, Fixed64 radius,
 25        Vector3d boxCenter, FixedQuaternion boxRotation, Vector3d halfExtents)
 26    {
 2527        GetRelativeLocalPointNumerators(cylinderCenter, boxCenter, boxRotation,
 2528            out Signed192 x, out Signed192 y, out Signed192 z, out Signed192 d);
 2529        if (IsStrictCylinderBoxCoordinateInside(x, halfExtents.X, d)
 2530            && IsStrictCylinderBoxCoordinateInside(y, halfExtents.Y, d)
 2531            && IsStrictCylinderBoxCoordinateInside(z, halfExtents.Z, d))
 32        {
 333            return true;
 34        }
 35
 2236        CylinderPolytopeFrame frame = new(cylinderCenter, cylinderRotation, height, radius,
 2237            boxCenter, boxRotation);
 2238        Span<WideAxis3> vertices = stackalloc WideAxis3[8];
 39639        for (int index = 0; index < vertices.Length; index++)
 40        {
 17641            vertices[index] = frame.Transform(new Vector3d(
 17642                (index & 1) == 0 ? -halfExtents.X : halfExtents.X,
 17643                (index & 2) == 0 ? -halfExtents.Y : halfExtents.Y,
 17644                (index & 4) == 0 ? -halfExtents.Z : halfExtents.Z));
 45        }
 2246        ReadOnlySpan<int> triangles = stackalloc int[]
 2247        {
 2248            0, 1, 3, 0, 3, 2, 4, 6, 7, 4, 7, 5,
 2249            0, 4, 5, 0, 5, 1, 2, 3, 7, 2, 7, 6,
 2250            0, 2, 6, 0, 6, 4, 1, 5, 7, 1, 7, 3
 2251        };
 24452        for (int index = 0; index < triangles.Length; index += 3)
 53        {
 11754            if (DoesCylinderTrianglePenetrate(frame, vertices[triangles[index]],
 11755                    vertices[triangles[index + 1]], vertices[triangles[index + 2]]))
 1756                return true;
 57        }
 558        return false;
 59    }
 60
 61    /// <summary>
 62    /// Tests whether an authored triangle contains any point strictly inside a
 63    /// local-+Y cylinder. Height/radius are positive and rotations normalized.
 64    /// Degenerate triangles retain their segment/point meaning; cap and radial
 65    /// tangencies are excluded independently.
 66    /// </summary>
 67    internal static bool DoesCenteredCylinderPenetrateTriangle(
 68        Vector3d cylinderCenter, FixedQuaternion cylinderRotation, Fixed64 height, Fixed64 radius,
 69        FixedTriangle triangle, Vector3d triangleOrigin, FixedQuaternion triangleRotation)
 70    {
 24671        CylinderPolytopeFrame frame = new(cylinderCenter, cylinderRotation, height, radius,
 24672            triangleOrigin, triangleRotation);
 24673        return DoesCylinderTrianglePenetrate(frame, frame.Transform(triangle.A),
 24674            frame.Transform(triangle.B), frame.Transform(triangle.C));
 75    }
 76
 77    /// <summary>
 78    /// Tests a cylinder against validated convex triangle topology. Closed
 79    /// volumes include cylinder enclosure; open coplanar surfaces use triangle
 80    /// intrusion only. Height/radius are positive, frames normalized, indices
 81    /// valid, and closed-volume triangles are nondegenerate with consistent
 82    /// shell winding, as required by the owning mesh admission contract.
 83    /// </summary>
 84    internal static bool DoesCenteredCylinderPenetrateConvexHull(
 85        Vector3d cylinderCenter, FixedQuaternion cylinderRotation, Fixed64 height, Fixed64 radius,
 86        Vector3d hullOrigin, FixedQuaternion hullRotation, ReadOnlySpan<Vector3d> localPoints,
 87        ReadOnlySpan<int> triangleIndices, bool closedVolume)
 88    {
 16489        if (closedVolume && IsCylinderCenterStrictlyInsideHull(cylinderCenter,
 16490                hullOrigin, hullRotation, localPoints, triangleIndices))
 491            return true;
 92
 16093        CylinderPolytopeFrame frame = new(cylinderCenter, cylinderRotation, height, radius,
 16094            hullOrigin, hullRotation);
 282495        for (int index = 0; index < triangleIndices.Length; index += 3)
 96        {
 133597            if (DoesCylinderTrianglePenetrate(frame,
 133598                    frame.Transform(localPoints[triangleIndices[index]]),
 133599                    frame.Transform(localPoints[triangleIndices[index + 1]]),
 1335100                    frame.Transform(localPoints[triangleIndices[index + 2]])))
 83101                return true;
 102        }
 77103        return false;
 104    }
 105
 106    internal static bool DoesCenteredCylinderPenetrateTriangle(
 107        Vector3d center, FixedQuaternion rotation, Fixed64 height, Fixed64 radius,
 108        FixedTriangle triangle, in ScaledRigidFrame3d sourceFrame)
 109    {
 24110        if (sourceFrame.IsRigid)
 2111            return DoesCenteredCylinderPenetrateTriangle(center, rotation, height, radius,
 2112                triangle, sourceFrame.RigidOrigin, sourceFrame.Rotation);
 22113        return TriangleCylinderContact.DoesPenetrate(triangle, sourceFrame, center, rotation, height, radius);
 114    }
 115
 116    internal static bool DoesCenteredCylinderPenetrateConvexHull(
 117        Vector3d center, FixedQuaternion rotation, Fixed64 height, Fixed64 radius,
 118        in ScaledRigidFrame3d sourceFrame, ReadOnlySpan<Vector3d> points,
 119        ReadOnlySpan<int> triangles, bool closedVolume)
 120    {
 187121        if (sourceFrame.IsRigid)
 139122            return DoesCenteredCylinderPenetrateConvexHull(center, rotation, height, radius,
 139123                sourceFrame.RigidOrigin, sourceFrame.Rotation, points, triangles, closedVolume);
 49124        if (closedVolume && ContainsConvexHullPoint(sourceFrame, points, triangles, center, strict: true)) return true;
 886125        for (int index = 0; index < triangles.Length; index += 3)
 126        {
 419127            FixedTriangle face = new(points[triangles[index]], points[triangles[index + 1]], points[triangles[index + 2]
 442128            if (TriangleCylinderContact.DoesPenetrate(face, sourceFrame, center, rotation, height, radius)) return true;
 129        }
 24130        return false;
 131    }
 132
 133    private static bool IsStrictCylinderBoxCoordinateInside(Signed192 coordinate,
 134        Fixed64 extent, Signed192 denominator) =>
 47135        WideArithmetic.CompareMagnitude(Signed320.ExtendValue(coordinate),
 47136            WideArithmetic.MultiplySigned192(Signed192.Raw(extent), denominator)) < 0;
 137
 138    private static bool IsCylinderCenterStrictlyInsideHull(Vector3d center,
 139        Vector3d origin, FixedQuaternion rotation, ReadOnlySpan<Vector3d> vertices,
 140        ReadOnlySpan<int> triangles, bool strict = true)
 141    {
 217142        GetRelativeLocalPointNumerators(center, origin, rotation,
 217143            out Signed192 x, out Signed192 y, out Signed192 z, out Signed192 denominator);
 217144        int interiorSign = 0;
 3290145        for (int index = 0; index < triangles.Length; index += 3)
 146        {
 1597147            Vector3d a = vertices[triangles[index]];
 1597148            Vector3d b = vertices[triangles[index + 1]];
 1597149            Vector3d c = vertices[triangles[index + 2]];
 1597150            WideGeometry.GetDifferenceCrossProduct3D(b.X, a.X, b.Y, a.Y, b.Z, a.Z,
 1597151                c.X, a.X, c.Y, a.Y, c.Z, a.Z,
 1597152                out Signed192 nx, out Signed192 ny, out Signed192 nz);
 1597153            Signed192 dx = WideArithmetic.SubtractSigned192(x, Signed192.NarrowProven(
 1597154                WideArithmetic.MultiplySigned192(Signed192.Raw(a.X), denominator)));
 1597155            Signed192 dy = WideArithmetic.SubtractSigned192(y, Signed192.NarrowProven(
 1597156                WideArithmetic.MultiplySigned192(Signed192.Raw(a.Y), denominator)));
 1597157            Signed192 dz = WideArithmetic.SubtractSigned192(z, Signed192.NarrowProven(
 1597158                WideArithmetic.MultiplySigned192(Signed192.Raw(a.Z), denominator)));
 1597159            int sign = WideArithmetic.GetDotProduct3D(nx, ny, nz, dx, dy, dz).Sign;
 1597160            if (sign == 0 && !strict) continue;
 1557161            if (sign == 0 || (interiorSign != 0 && sign != interiorSign))
 169162                return false;
 1388163            interiorSign = sign;
 164        }
 48165        return interiorSign != 0;
 166    }
 167
 168    /// <summary>Tests a point against a validated consistently wound closed convex hull, including its boundary unless 
 169    internal static bool ContainsConvexHullPoint(in ScaledRigidFrame3d sourceFrame, ReadOnlySpan<Vector3d> points,
 170        ReadOnlySpan<int> triangles, Vector3d center, bool strict = false)
 171    {
 201172        if (sourceFrame.IsRigid)
 55173            return IsCylinderCenterStrictlyInsideHull(center, sourceFrame.RigidOrigin, sourceFrame.Rotation, points, tri
 146174        int interiorSign = 0;
 146175        RationalPoint3d point = RationalPoint3d.FromScalarPoint(center);
 2952176        for (int index = 0; index < triangles.Length; index += 3)
 177        {
 1383178            FixedTriangle face = new(points[triangles[index]], points[triangles[index + 1]], points[triangles[index + 2]
 1383179            WideDirection3d normal = WideTriangleRelations.GetScaledTriangleLocalNormal(face, sourceFrame).Transform(sou
 1383180            int sign = WideDirection3d.Dot(normal, WideTriangleRelations.GetScaledPointDifference(
 1383181                point, sourceFrame.GetPoint(face.A), sourceFrame.RotationDenominator)).Sign;
 1383182            if (sign == 0 && !strict) continue;
 1398183            if (sign == 0 || interiorSign != 0 && sign != interiorSign) return false;
 1292184            interiorSign = sign;
 185        }
 93186        return interiorSign != 0;
 187    }
 188
 189    private static bool DoesCylinderTrianglePenetrate(in CylinderPolytopeFrame frame,
 190        in WideAxis3 a, in WideAxis3 b, in WideAxis3 c)
 191    {
 1698192        Signed320 lower = WideArithmetic.SubtractSigned320(default, frame.Cap);
 193        // The closed clipped polygon alone would admit a triangle coplanar
 194        // with a cap. Require an axial-interior point before minimizing radius.
 1698195        if ((CompareSigned(a.Y, lower) <= 0 && CompareSigned(b.Y, lower) <= 0 && CompareSigned(c.Y, lower) <= 0)
 1698196            || (CompareSigned(a.Y, frame.Cap) >= 0 && CompareSigned(b.Y, frame.Cap) >= 0 && CompareSigned(c.Y, frame.Cap
 691197            return false;
 198
 1007199        if (IsCylinderAxisInsideTriangleProjection(a, b, c, lower, frame.Cap))
 26200            return true;
 981201        if (DoesCylinderClippedEdgePenetrate(a, b, lower, frame.Cap, frame)
 981202            || DoesCylinderClippedEdgePenetrate(b, c, lower, frame.Cap, frame)
 981203            || DoesCylinderClippedEdgePenetrate(c, a, lower, frame.Cap, frame))
 118204            return true;
 205
 206        // These are the remaining two possible edges of the clipped polygon.
 863207        return DoesCylinderCapSectionPenetrate(a, b, c, lower, frame)
 863208            || DoesCylinderCapSectionPenetrate(a, b, c, frame.Cap, frame);
 209    }
 210
 211    private static bool IsCylinderAxisInsideTriangleProjection(in WideAxis3 a,
 212        in WideAxis3 b, in WideAxis3 c, Signed320 lower, Signed320 upper)
 213    {
 1007214        Signed576 wa = GetCylinderRadialCross(b, c);
 1007215        Signed576 wb = GetCylinderRadialCross(c, a);
 1007216        Signed576 wc = GetCylinderRadialCross(a, b);
 1007217        Signed576 area = WideArithmetic.AddSigned576(WideArithmetic.AddSigned576(wa, wb), wc);
 1007218        if (area.IsZero)
 387219            return false;
 620220        if ((wa.Sign != 0 && wa.Sign != area.Sign) || (wb.Sign != 0 && wb.Sign != area.Sign)
 620221            || (wc.Sign != 0 && wc.Sign != area.Sign))
 561222            return false;
 59223        if (area.Sign < 0)
 224        {
 32225            wa = WideArithmetic.SubtractSigned576(default, wa);
 32226            wb = WideArithmetic.SubtractSigned576(default, wb);
 32227            wc = WideArithmetic.SubtractSigned576(default, wc);
 32228            area = WideArithmetic.SubtractSigned576(default, area);
 229        }
 59230        Signed832 y = WideArithmetic.AddSigned832(WideArithmetic.AddSigned832(
 59231            WideArithmetic.MultiplySigned576ToSigned832(wa, a.Y),
 59232            WideArithmetic.MultiplySigned576ToSigned832(wb, b.Y)),
 59233            WideArithmetic.MultiplySigned576ToSigned832(wc, c.Y));
 59234        return WideArithmetic.SubtractSigned832(y,
 59235                WideArithmetic.MultiplySigned576ToSigned832(area, lower)).Sign >= 0
 59236            && WideArithmetic.SubtractSigned832(y,
 59237                WideArithmetic.MultiplySigned576ToSigned832(area, upper)).Sign <= 0;
 238    }
 239
 240    private static Signed576 GetCylinderRadialCross(in WideAxis3 a, in WideAxis3 b) =>
 3021241        WideArithmetic.SubtractSigned576(WideArithmetic.MultiplySigned320(a.X, b.Z),
 3021242            WideArithmetic.MultiplySigned320(a.Z, b.X));
 243
 244    private static bool DoesCylinderClippedEdgePenetrate(in WideAxis3 a, in WideAxis3 b,
 245        Signed320 lower, Signed320 upper, in CylinderPolytopeFrame frame)
 246    {
 2859247        if ((CompareSigned(a.Y, lower) < 0 && CompareSigned(b.Y, lower) < 0)
 2859248            || (CompareSigned(a.Y, upper) > 0 && CompareSigned(b.Y, upper) > 0))
 615249            return false;
 2244250        SweepRationalPoint first = GetCylinderClippedEndpoint(a, b, lower, upper, frame.Denominator);
 2244251        SweepRationalPoint second = GetCylinderClippedEndpoint(b, a, lower, upper, frame.Denominator);
 2244252        return IsCylinderRadialSegmentInside(first, second, frame.Radius);
 253    }
 254
 255    private static SweepRationalPoint GetCylinderClippedEndpoint(in WideAxis3 endpoint,
 256        in WideAxis3 other, Signed320 lower, Signed320 upper, Signed192 denominator)
 257    {
 4488258        if (CompareSigned(endpoint.Y, lower) < 0)
 1203259            return GetCylinderPlaneIntersection(endpoint, other, lower, denominator);
 3285260        if (CompareSigned(endpoint.Y, upper) > 0)
 1350261            return GetCylinderPlaneIntersection(endpoint, other, upper, denominator);
 1935262        return GetCylinderRadialPoint(endpoint, denominator);
 263    }
 264
 265    private static SweepRationalPoint GetCylinderRadialPoint(in WideAxis3 point, Signed192 denominator) =>
 2223266        new(Signed576.ExtendValue(point.X), Signed576.ExtendValue(point.Z),
 2223267            Signed576.ExtendValue(Signed320.ExtendValue(denominator)));
 268
 269    private static SweepRationalPoint GetCylinderPlaneIntersection(in WideAxis3 a,
 270        in WideAxis3 b, Signed320 plane, Signed192 denominator)
 271    {
 4884272        Signed320 wa = WideArithmetic.SubtractSigned320(b.Y, plane);
 4884273        Signed320 wb = WideArithmetic.SubtractSigned320(plane, a.Y);
 4884274        Signed576 x = WideArithmetic.AddSigned576(WideArithmetic.MultiplySigned320(a.X, wa),
 4884275            WideArithmetic.MultiplySigned320(b.X, wb));
 4884276        Signed576 z = WideArithmetic.AddSigned576(WideArithmetic.MultiplySigned320(a.Z, wa),
 4884277            WideArithmetic.MultiplySigned320(b.Z, wb));
 4884278        Signed576 d = WideArithmetic.MultiplySigned320(WideArithmetic.SubtractSigned320(b.Y, a.Y), denominator);
 4884279        if (d.Sign < 0)
 280        {
 2516281            x = WideArithmetic.SubtractSigned576(default, x);
 2516282            z = WideArithmetic.SubtractSigned576(default, z);
 2516283            d = WideArithmetic.SubtractSigned576(default, d);
 284        }
 4884285        return new SweepRationalPoint(x, z, d);
 286    }
 287
 288    private static bool DoesCylinderCapSectionPenetrate(in WideAxis3 a, in WideAxis3 b,
 289        in WideAxis3 c, Signed320 plane, in CylinderPolytopeFrame frame)
 290    {
 1713291        Span<SweepRationalPoint> points = stackalloc SweepRationalPoint[3];
 1713292        int count = 0;
 1713293        AddCylinderPlaneIntersection(a, b, plane, frame.Denominator, points, ref count);
 1713294        AddCylinderPlaneIntersection(b, c, plane, frame.Denominator, points, ref count);
 1713295        AddCylinderPlaneIntersection(c, a, plane, frame.Denominator, points, ref count);
 1713296        return count == 1 ? IsCylinderRadialPointInside(points[0], frame.Radius)
 1713297            : count >= 2 && IsCylinderRadialSegmentInside(points[0], points[1], frame.Radius);
 298    }
 299
 300    private static void AddCylinderPlaneIntersection(in WideAxis3 a, in WideAxis3 b,
 301        Signed320 plane, Signed192 denominator, Span<SweepRationalPoint> points, ref int count)
 302    {
 5139303        int first = CompareSigned(a.Y, plane);
 5139304        int second = CompareSigned(b.Y, plane);
 5139305        if (first == 0)
 144306            AddUniqueSweepPoint(GetCylinderRadialPoint(a, denominator), points, ref count);
 5139307        if (second == 0)
 144308            AddUniqueSweepPoint(GetCylinderRadialPoint(b, denominator), points, ref count);
 5139309        if (first != 0 && second != 0 && first != second)
 2331310            AddUniqueSweepPoint(GetCylinderPlaneIntersection(a, b, plane, denominator), points, ref count);
 5139311    }
 312
 313    private static bool IsCylinderRadialPointInside(in SweepRationalPoint point, Signed192 radius)
 314    {
 6901315        Signed832 squared = WideArithmetic.AddSigned832(
 6901316            WideArithmetic.MultiplySigned576ToSigned832(point.X, point.X),
 6901317            WideArithmetic.MultiplySigned576ToSigned832(point.Z, point.Z));
 6901318        Signed576 bound = WideArithmetic.MultiplySigned576(point.Denominator, radius);
 6901319        return WideArithmetic.SubtractSigned832(squared,
 6901320            WideArithmetic.MultiplySigned576ToSigned832(bound, bound)).Sign < 0;
 321    }
 322
 323    private static bool IsCylinderRadialSegmentInside(in SweepRationalPoint a,
 324        in SweepRationalPoint b, Signed192 radius)
 325    {
 3454326        if (IsCylinderRadialPointInside(a, radius) || IsCylinderRadialPointInside(b, radius))
 91327            return true;
 3363328        Signed832 ex = WideArithmetic.SubtractSigned832(
 3363329            WideArithmetic.MultiplySigned576ToSigned832(b.X, a.Denominator),
 3363330            WideArithmetic.MultiplySigned576ToSigned832(a.X, b.Denominator));
 3363331        Signed832 ez = WideArithmetic.SubtractSigned832(
 3363332            WideArithmetic.MultiplySigned576ToSigned832(b.Z, a.Denominator),
 3363333            WideArithmetic.MultiplySigned576ToSigned832(a.Z, b.Denominator));
 3363334        if (ex.IsZero && ez.IsZero)
 353335            return false;
 3010336        Span<ulong> scratch = stackalloc ulong[TriangleSweepMagnitudeWords];
 3010337        GetDotMagnitude(ex, ez, a.X, a.Z, scratch, out int startDot);
 3010338        if (startDot >= 0)
 1137339            return false;
 1873340        GetDotMagnitude(ex, ez, b.X, b.Z, scratch, out int endDot);
 1873341        if (endDot <= 0)
 1064342            return false;
 343
 344        // For A/a, B/b and E=a*B-b*A the interior distance squared is
 345        // cross(A,B)^2 / dot(E,E): the common a^2 cancels exactly.
 809346        Signed832 cross = WideArithmetic.SubtractSigned832(
 809347            WideArithmetic.MultiplySigned576ToSigned832(a.X, b.Z),
 809348            WideArithmetic.MultiplySigned576ToSigned832(a.Z, b.X));
 809349        Span<ulong> crossWords = stackalloc ulong[13];
 809350        WideArithmetic.GetMagnitude(cross, crossWords);
 809351        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 809352        WideArithmetic.MultiplyMagnitudes(crossWords, crossWords, left);
 809353        GetEdgeSquaredMagnitude(ex, ez, scratch);
 809354        Span<ulong> radiusWords = stackalloc ulong[3];
 809355        WideArithmetic.GetMagnitude(radius, out radiusWords[2], out radiusWords[1], out radiusWords[0]);
 809356        Span<ulong> radiusSquared = stackalloc ulong[6];
 809357        WideArithmetic.MultiplyMagnitudes(radiusWords, radiusWords, radiusSquared);
 809358        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 809359        WideArithmetic.MultiplyMagnitudes(radiusSquared, scratch, right);
 360        // Conservatively each normalized basis denominator is <2^68. Relative
 361        // D<2^136 and doubled transformed vertices <2^204. Clipping ORIGINAL
 362        // edges once gives numerator <2^410 and denominator <2^341. Hence E
 363        // fits <2^752, cross(A,B) <2^821, and this comparison <2^1642, below
 364        // the existing fixed 36-word capacity. No repeated rational clipping.
 809365        return WideArithmetic.CompareMagnitudeEqualLength(left, right) < 0;
 366    }
 367}

/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    {
 221748        Signed320 numerator = WideArithmetic.AddSigned320(
 221749            WideArithmetic.MultiplySigned192(Signed192.Raw(center), denominator),
 221750            WideArithmetic.AddSigned320(
 221751                WideArithmetic.AddSigned320(
 221752                    WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.X), axisX),
 221753                    WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.Y), axisY)),
 221754                WideArithmetic.MultiplySigned192(Signed192.Raw(localPoint.Z), axisZ)));
 221755        return Fixed64.TryGetSignedRawRatio(
 221756            Signed576.ExtendValue(numerator),
 221757            denominatorWide,
 221758            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 distance comparison needs fewer than 2252 bits for a
 22    // direction or 2312 bits for a full-domain segment-distance denominator.
 23    private const int TriangleSweepMagnitudeWords = 37;
 24
 25    private static bool TryGetRationalSegmentSweepDistance(
 26        TriangleSweepPoint firstPoint,
 27        TriangleSweepPoint secondPoint,
 28        Vector2d start,
 29        in SweepTrajectory trajectory,
 30        Fixed64 maximumDistance,
 31        Fixed64 radius,
 32        out Fixed64 distance,
 33        out Vector3d localPoint,
 34        out Signed576 referenceYOffset)
 35    {
 79036        SweepRationalPoint first = firstPoint.RationalPoint;
 79037        SweepRationalPoint second = secondPoint.RationalPoint;
 79038        Signed832 edgeX = WideArithmetic.SubtractSigned832(
 79039            WideArithmetic.MultiplySigned576ToSigned832(
 79040                second.X,
 79041                first.Denominator),
 79042            WideArithmetic.MultiplySigned576ToSigned832(
 79043                first.X,
 79044                second.Denominator));
 79045        Signed832 edgeZ = WideArithmetic.SubtractSigned832(
 79046            WideArithmetic.MultiplySigned576ToSigned832(
 79047                second.Z,
 79048                first.Denominator),
 79049            WideArithmetic.MultiplySigned576ToSigned832(
 79050                first.Z,
 79051                second.Denominator));
 79052        if (edgeX.IsZero && edgeZ.IsZero)
 53        {
 1554            distance = default;
 1555            localPoint = default;
 1556            referenceYOffset = default;
 1557            return false;
 58        }
 59
 77560        Signed576 startX = WideArithmetic.SubtractSigned576(
 77561            WideArithmetic.MultiplySigned576(
 77562                first.Denominator,
 77563                Signed192.Raw(start.X)),
 77564            first.X);
 77565        Signed576 startZ = WideArithmetic.SubtractSigned576(
 77566            WideArithmetic.MultiplySigned576(
 77567                first.Denominator,
 77568                Signed192.Raw(start.Y)),
 77569            first.Z);
 77570        Span<ulong> startCross =
 77571            stackalloc ulong[TriangleSweepMagnitudeWords];
 77572        GetCrossMagnitude(
 77573            edgeX,
 77574            edgeZ,
 77575            startX,
 77576            startZ,
 77577            startCross,
 77578            out int startCrossSign);
 79
 77580        Signed192 directionX = trajectory.DirectionX;
 77581        Signed192 directionZ = trajectory.DirectionZ;
 77582        Span<ulong> velocityCore =
 77583            stackalloc ulong[TriangleSweepMagnitudeWords];
 77584        GetCrossMagnitude(
 77585            edgeX,
 77586            edgeZ,
 77587            directionX,
 77588            directionZ,
 77589            velocityCore,
 77590            out int velocitySign);
 77591        Span<ulong> denominatorMagnitude = stackalloc ulong[9];
 77592        WideArithmetic.GetMagnitude(
 77593            first.Denominator,
 77594            denominatorMagnitude);
 77595        Span<ulong> velocity =
 77596            stackalloc ulong[TriangleSweepMagnitudeWords];
 77597        WideArithmetic.MultiplyMagnitudes(
 77598            velocityCore,
 77599            denominatorMagnitude,
 775100            velocity);
 101
 775102        Span<ulong> edgeSquared =
 775103            stackalloc ulong[TriangleSweepMagnitudeWords];
 775104        GetEdgeSquaredMagnitude(edgeX, edgeZ, edgeSquared);
 775105        if (CompareRationalSegmentLineAt(
 775106                startCross, startCrossSign, velocity, velocitySign,
 775107                edgeSquared, denominatorMagnitude, radius,
 775108                default, trajectory.TimeScale) <= 0)
 109        {
 47110            distance = Fixed64.Zero;
 47111            return TryGetExactRationalSegmentWitness(
 47112                firstPoint, secondPoint, edgeX, edgeZ, edgeSquared,
 47113                startX, startZ, startCross, velocity, trajectory, radius,
 47114                atStart: true, out localPoint, out referenceYOffset);
 115        }
 116
 117        // The expanded-line start test already returned for a zero cross.
 728118        if (maximumDistance == Fixed64.Zero
 728119            || velocitySign == 0
 728120            || startCrossSign == velocitySign)
 121        {
 22122            distance = default;
 22123            localPoint = default;
 22124            referenceYOffset = default;
 22125            return false;
 126        }
 127
 706128        Span<ulong> startAtUnit =
 706129            stackalloc ulong[TriangleSweepMagnitudeWords];
 706130        Span<ulong> velocityAtMaximum =
 706131            stackalloc ulong[TriangleSweepMagnitudeWords];
 706132        Span<ulong> oneMagnitude = stackalloc ulong[3];
 706133        WideArithmetic.GetMagnitude(trajectory.TimeScale, out oneMagnitude[2], out oneMagnitude[1], out oneMagnitude[0])
 706134        Span<ulong> maximumMagnitude = stackalloc ulong[3];
 706135        WideArithmetic.GetMagnitude(
 706136            Signed192.Signed(maximumDistance.m_rawValue),
 706137            out maximumMagnitude[2],
 706138            out maximumMagnitude[1],
 706139            out maximumMagnitude[0]);
 706140        WideArithmetic.MultiplyMagnitudes(startCross, oneMagnitude, startAtUnit);
 706141        WideArithmetic.MultiplyMagnitudes(velocity, maximumMagnitude, velocityAtMaximum);
 706142        bool closestBeyondMaximum =
 706143            WideArithmetic.CompareMagnitudeEqualLength(startAtUnit, velocityAtMaximum) > 0;
 706144        if (closestBeyondMaximum
 706145            && CompareRationalSegmentLineAt(
 706146                startCross,
 706147                startCrossSign,
 706148                velocity,
 706149                velocitySign,
 706150                edgeSquared,
 706151                denominatorMagnitude,
 706152                radius,
 706153                Signed192.Signed(maximumDistance.m_rawValue),
 706154                trajectory.TimeScale) > 0)
 155        {
 39156            distance = default;
 39157            localPoint = default;
 39158            referenceYOffset = default;
 39159            return false;
 160        }
 161
 667162        Span<ulong> values = stackalloc ulong[6 * TriangleSweepMagnitudeWords];
 667163        Span<int> signs = stackalloc int[6];
 667164        ContactQuadratic entry = ContactQuadratic.At(values, signs, 0, TriangleSweepMagnitudeWords);
 667165        ContactQuadratic divisor = ContactQuadratic.At(values, signs, 1, TriangleSweepMagnitudeWords);
 667166        ContactQuadratic work = ContactQuadratic.At(values, signs, 2, TriangleSweepMagnitudeWords);
 2001167        entry.Clear(); divisor.Clear(); work.Clear();
 168        // Entry in raw distance is (|cross|-R*D*sqrt(L))*TimeScale/|velocity|.
 1334169        startCross.CopyTo(entry.Rational); entry.Signs[0] = 1;
 667170        Span<ulong> radiusMagnitude = stackalloc ulong[1] { (ulong)radius.m_rawValue };
 667171        WideArithmetic.MultiplyMagnitudes(denominatorMagnitude, radiusMagnitude, entry.Radical);
 667172        entry.Signs[1] = radius == Fixed64.Zero ? 0 : -1;
 1334173        velocity.CopyTo(divisor.Rational); divisor.Signs[0] = 1;
 667174        ContactQuadratic.Scale(entry, Signed576.ExtendValue(Signed320.ExtendValue(trajectory.TimeScale)), work);
 667175        work.CopyTo(entry);
 176        // Earlier admission bounds this positive entering root by the maximum distance.
 667177        distance = ContactQuadratic.RoundRatio(entry, divisor, edgeSquared, 0L, maximumDistance.m_rawValue);
 178
 667179        if (TryGetExactRationalSegmentWitness(
 667180                firstPoint, secondPoint, edgeX, edgeZ, edgeSquared,
 667181                startX, startZ, startCross, velocity, trajectory, radius,
 667182                atStart: false, out localPoint, out referenceYOffset))
 602183            return true;
 184
 65185        distance = default;
 65186        return false;
 187    }
 188
 189    private static int CompareRationalSegmentLineAt(
 190        ReadOnlySpan<ulong> startCross,
 191        int startCrossSign,
 192        ReadOnlySpan<ulong> velocity,
 193        int velocitySign,
 194        ReadOnlySpan<ulong> edgeSquared,
 195        ReadOnlySpan<ulong> denominator,
 196        Fixed64 radius,
 197        Signed192 timeNumerator,
 198        Signed192 timeDenominator)
 199    {
 837200        Span<ulong> timeNumeratorMagnitude = stackalloc ulong[3];
 837201        Span<ulong> timeDenominatorMagnitude = stackalloc ulong[3];
 837202        WideArithmetic.GetMagnitude(
 837203            timeNumerator,
 837204            out timeNumeratorMagnitude[2],
 837205            out timeNumeratorMagnitude[1],
 837206            out timeNumeratorMagnitude[0]);
 837207        WideArithmetic.GetMagnitude(
 837208            timeDenominator,
 837209            out timeDenominatorMagnitude[2],
 837210            out timeDenominatorMagnitude[1],
 837211            out timeDenominatorMagnitude[0]);
 837212        Span<ulong> firstTerm =
 837213            stackalloc ulong[TriangleSweepMagnitudeWords];
 837214        Span<ulong> secondTerm =
 837215            stackalloc ulong[TriangleSweepMagnitudeWords];
 837216        Span<ulong> line =
 837217            stackalloc ulong[TriangleSweepMagnitudeWords];
 837218        WideArithmetic.MultiplyMagnitudes(
 837219            startCross,
 837220            timeDenominatorMagnitude,
 837221            firstTerm);
 837222        WideArithmetic.MultiplyMagnitudes(
 837223            velocity,
 837224            timeNumeratorMagnitude,
 837225            secondTerm);
 837226        CombineSignedMagnitudes(
 837227            firstTerm,
 837228            startCrossSign,
 837229            secondTerm,
 837230            velocitySign * timeNumerator.Sign,
 837231            line,
 837232            out _);
 837233        Span<ulong> leftSquared =
 837234            stackalloc ulong[TriangleSweepMagnitudeWords];
 837235        WideArithmetic.MultiplyMagnitudes(line, line, leftSquared);
 236
 837237        Span<ulong> radiusMagnitude = stackalloc ulong[1]
 837238        {
 837239            unchecked((ulong)radius.m_rawValue),
 837240        };
 837241        Span<ulong> right =
 837242            stackalloc ulong[TriangleSweepMagnitudeWords];
 837243        Span<ulong> scratch =
 837244            stackalloc ulong[TriangleSweepMagnitudeWords];
 837245        WideArithmetic.MultiplyMagnitudes(edgeSquared, denominator, right);
 837246        WideArithmetic.MultiplyMagnitudes(right, denominator, scratch);
 837247        WideArithmetic.MultiplyMagnitudes(scratch, radiusMagnitude, right);
 837248        WideArithmetic.MultiplyMagnitudes(right, radiusMagnitude, scratch);
 837249        WideArithmetic.MultiplyMagnitudes(
 837250            scratch,
 837251            timeDenominatorMagnitude,
 837252            right);
 837253        WideArithmetic.MultiplyMagnitudes(
 837254            right,
 837255            timeDenominatorMagnitude,
 837256            scratch);
 837257        return WideArithmetic.CompareMagnitudeEqualLength(leftSquared, scratch);
 258    }
 259
 260    private static bool TryGetExactRationalSegmentWitness(
 261        TriangleSweepPoint first,
 262        TriangleSweepPoint second,
 263        Signed832 edgeX,
 264        Signed832 edgeZ,
 265        ReadOnlySpan<ulong> edgeSquared,
 266        Signed576 startX,
 267        Signed576 startZ,
 268        ReadOnlySpan<ulong> startCross,
 269        ReadOnlySpan<ulong> velocityCross,
 270        in SweepTrajectory trajectory,
 271        Fixed64 radius,
 272        bool atStart,
 273        out Vector3d localPoint,
 274        out Signed576 referenceYOffset)
 275    {
 276        // Full clipped endpoints bound exact foot fields below 2508 bits;
 277        // multiplying by a 65-bit local difference stays below 2574 bits.
 278        const int words = 42;
 714279        Span<ulong> values = stackalloc ulong[8 * words];
 714280        Span<int> signs = stackalloc int[8];
 714281        ContactQuadratic time = ContactQuadratic.At(values, signs, 0, words);
 714282        ContactQuadratic numerator = ContactQuadratic.At(values, signs, 1, words);
 714283        ContactQuadratic denominator = ContactQuadratic.At(values, signs, 2, words);
 714284        ContactQuadratic work = ContactQuadratic.At(values, signs, 3, words);
 2856285        time.Clear(); numerator.Clear(); denominator.Clear(); work.Clear();
 714286        Span<ulong> startDot = stackalloc ulong[TriangleSweepMagnitudeWords];
 714287        GetDotMagnitude(edgeX, edgeZ, startX, startZ, startDot, out int startDotSign);
 714288        Span<ulong> secondDenominator = stackalloc ulong[9];
 714289        WideArithmetic.GetMagnitude(second.RationalPoint.Denominator, secondDenominator);
 714290        if (atStart)
 291        {
 47292            startDot.CopyTo(numerator.Rational);
 47293            numerator.Signs[0] = startDotSign;
 47294            edgeSquared.CopyTo(denominator.Rational);
 47295            denominator.Signs[0] = 1;
 296        }
 297        else
 298        {
 299            // The exact approaching root is (|cross|-R*D*sqrt(L))/|velocity|.
 300            // Retain this field when certifying and materializing its finite foot.
 667301            startCross.CopyTo(time.Rational);
 667302            time.Signs[0] = 1;
 667303            Span<ulong> firstDenominator = stackalloc ulong[9];
 667304            WideArithmetic.GetMagnitude(first.RationalPoint.Denominator, firstDenominator);
 667305            Span<ulong> radiusMagnitude = stackalloc ulong[1] { (ulong)radius.m_rawValue };
 667306            WideArithmetic.MultiplyMagnitudes(firstDenominator, radiusMagnitude, time.Radical);
 667307            time.Signs[1] = radius == Fixed64.Zero ? 0 : -1;
 667308            Span<ulong> velocityDot = stackalloc ulong[TriangleSweepMagnitudeWords];
 667309            GetDotMagnitude(edgeX, edgeZ,
 667310                WideArithmetic.MultiplySigned576(first.RationalPoint.Denominator, trajectory.DirectionX),
 667311                WideArithmetic.MultiplySigned576(first.RationalPoint.Denominator, trajectory.DirectionZ),
 667312                velocityDot, out int velocityDotSign);
 667313            ContactQuadratic.Scale(time, velocityDot, velocityDotSign, numerator);
 667314            WideArithmetic.MultiplyMagnitudes(startDot, velocityCross, work.Rational);
 667315            work.Signs[0] = startDotSign;
 667316            numerator.Add(work);
 667317            WideArithmetic.MultiplyMagnitudes(edgeSquared, velocityCross, denominator.Rational);
 667318            denominator.Signs[0] = 1;
 319        }
 714320        ContactQuadratic.Scale(numerator, secondDenominator, 1, work);
 714321        work.CopyTo(numerator);
 714322        numerator.CopyTo(time);
 714323        time.Add(denominator, -1);
 714324        if (numerator.Sign(edgeSquared) < 0 || time.Sign(edgeSquared) > 0)
 325        {
 106326            localPoint = default;
 106327            referenceYOffset = default;
 106328            return false;
 329        }
 330
 608331        localPoint = new Vector3d(
 608332            RoundRationalSegmentCoordinate(first.LocalPoint.X, second.LocalPoint.X, numerator, denominator, edgeSquared,
 608333            RoundRationalSegmentCoordinate(first.LocalPoint.Y, second.LocalPoint.Y, numerator, denominator, edgeSquared,
 608334            RoundRationalSegmentCoordinate(first.LocalPoint.Z, second.LocalPoint.Z, numerator, denominator, edgeSquared,
 608335        ContactQuadratic.Scale(numerator, Signed576.ExtendValue(Signed320.ExtendValue(SweepRawScale)), work);
 608336        Fixed64 parameter = ContactQuadratic.RoundRatio(work, denominator, edgeSquared, 0L, FixedMath.ONE_L);
 608337        referenceYOffset = WideArithmetic.AddSigned576(
 608338            WideArithmetic.MultiplySigned320(first.ReferenceYOffset, Signed320.ExtendValue(Signed192.Raw(Fixed64.One - p
 608339            WideArithmetic.MultiplySigned320(second.ReferenceYOffset, Signed320.ExtendValue(Signed192.Raw(parameter))));
 608340        return true;
 341    }
 342
 343    private static Fixed64 RoundRationalSegmentCoordinate(
 344        Fixed64 first,
 345        Fixed64 second,
 346        ContactQuadratic numerator,
 347        ContactQuadratic denominator,
 348        ReadOnlySpan<ulong> root,
 349        ContactQuadratic work,
 350        ContactQuadratic scratch)
 351    {
 1824352        Signed192 delta = WideArithmetic.SubtractSigned192(Signed192.Raw(second), Signed192.Raw(first));
 1824353        ContactQuadratic.Scale(numerator, Signed576.ExtendValue(Signed320.ExtendValue(delta)), work);
 1824354        ContactQuadratic.Scale(denominator, Signed576.ExtendValue(Signed320.ExtendValue(Signed192.Raw(first))), scratch)
 1824355        work.Add(scratch);
 1824356        return ContactQuadratic.RoundRatio(work, denominator, root,
 1824357            Math.Min(first.m_rawValue, second.m_rawValue), Math.Max(first.m_rawValue, second.m_rawValue));
 358    }
 359
 360    private static void GetEdgeSquaredMagnitude(
 361        Signed832 edgeX,
 362        Signed832 edgeZ,
 363        Span<ulong> result)
 364    {
 1584365        Span<ulong> x = stackalloc ulong[13];
 1584366        Span<ulong> z = stackalloc ulong[13];
 1584367        WideArithmetic.GetMagnitude(edgeX, x);
 1584368        WideArithmetic.GetMagnitude(edgeZ, z);
 1584369        Span<ulong> xSquared =
 1584370            stackalloc ulong[TriangleSweepMagnitudeWords];
 1584371        Span<ulong> zSquared =
 1584372            stackalloc ulong[TriangleSweepMagnitudeWords];
 1584373        WideArithmetic.MultiplyMagnitudes(x, x, xSquared);
 1584374        WideArithmetic.MultiplyMagnitudes(z, z, zSquared);
 1584375        WideArithmetic.AddEqualMagnitudes(xSquared, zSquared, result);
 1584376    }
 377
 378    private static void GetCrossMagnitude(
 379        Signed832 firstX,
 380        Signed832 firstZ,
 381        Signed576 secondX,
 382        Signed576 secondZ,
 383        Span<ulong> result,
 384        out int sign)
 385    {
 775386        Span<ulong> firstXMag = stackalloc ulong[13];
 775387        Span<ulong> firstZMag = stackalloc ulong[13];
 775388        Span<ulong> secondXMag = stackalloc ulong[9];
 775389        Span<ulong> secondZMag = stackalloc ulong[9];
 775390        WideArithmetic.GetMagnitude(firstX, firstXMag);
 775391        WideArithmetic.GetMagnitude(firstZ, firstZMag);
 775392        WideArithmetic.GetMagnitude(secondX, secondXMag);
 775393        WideArithmetic.GetMagnitude(secondZ, secondZMag);
 775394        GetCrossMagnitude(
 775395            firstXMag,
 775396            firstX.Sign,
 775397            firstZMag,
 775398            firstZ.Sign,
 775399            secondXMag,
 775400            secondX.Sign,
 775401            secondZMag,
 775402            secondZ.Sign,
 775403            result,
 775404            out sign);
 775405    }
 406
 407    private static void GetCrossMagnitude(
 408        Signed832 firstX,
 409        Signed832 firstZ,
 410        Signed192 secondX,
 411        Signed192 secondZ,
 412        Span<ulong> result,
 413        out int sign)
 414    {
 775415        Span<ulong> firstXMag = stackalloc ulong[13];
 775416        Span<ulong> firstZMag = stackalloc ulong[13];
 775417        Span<ulong> secondXMag = stackalloc ulong[3];
 775418        Span<ulong> secondZMag = stackalloc ulong[3];
 775419        WideArithmetic.GetMagnitude(firstX, firstXMag);
 775420        WideArithmetic.GetMagnitude(firstZ, firstZMag);
 775421        WideArithmetic.GetMagnitude(
 775422            secondX,
 775423            out secondXMag[2],
 775424            out secondXMag[1],
 775425            out secondXMag[0]);
 775426        WideArithmetic.GetMagnitude(
 775427            secondZ,
 775428            out secondZMag[2],
 775429            out secondZMag[1],
 775430            out secondZMag[0]);
 775431        GetCrossMagnitude(
 775432            firstXMag,
 775433            firstX.Sign,
 775434            firstZMag,
 775435            firstZ.Sign,
 775436            secondXMag,
 775437            secondX.Sign,
 775438            secondZMag,
 775439            secondZ.Sign,
 775440            result,
 775441            out sign);
 775442    }
 443
 444    private static void GetCrossMagnitude(
 445        ReadOnlySpan<ulong> firstX,
 446        int firstXSign,
 447        ReadOnlySpan<ulong> firstZ,
 448        int firstZSign,
 449        ReadOnlySpan<ulong> secondX,
 450        int secondXSign,
 451        ReadOnlySpan<ulong> secondZ,
 452        int secondZSign,
 453        Span<ulong> result,
 454        out int sign)
 455    {
 1550456        Span<ulong> firstTerm =
 1550457            stackalloc ulong[TriangleSweepMagnitudeWords];
 1550458        Span<ulong> secondTerm =
 1550459            stackalloc ulong[TriangleSweepMagnitudeWords];
 1550460        WideArithmetic.MultiplyMagnitudes(firstX, secondZ, firstTerm);
 1550461        WideArithmetic.MultiplyMagnitudes(firstZ, secondX, secondTerm);
 1550462        CombineSignedMagnitudes(
 1550463            firstTerm,
 1550464            firstXSign * secondZSign,
 1550465            secondTerm,
 1550466            -(firstZSign * secondXSign),
 1550467            result,
 1550468            out sign);
 1550469    }
 470
 471    private static void GetDotMagnitude(
 472        Signed832 firstX,
 473        Signed832 firstZ,
 474        Signed576 secondX,
 475        Signed576 secondZ,
 476        Span<ulong> result,
 477        out int sign)
 478    {
 6264479        Span<ulong> firstXMag = stackalloc ulong[13];
 6264480        Span<ulong> firstZMag = stackalloc ulong[13];
 6264481        Span<ulong> secondXMag = stackalloc ulong[9];
 6264482        Span<ulong> secondZMag = stackalloc ulong[9];
 6264483        WideArithmetic.GetMagnitude(firstX, firstXMag);
 6264484        WideArithmetic.GetMagnitude(firstZ, firstZMag);
 6264485        WideArithmetic.GetMagnitude(secondX, secondXMag);
 6264486        WideArithmetic.GetMagnitude(secondZ, secondZMag);
 6264487        Span<ulong> firstTerm =
 6264488            stackalloc ulong[TriangleSweepMagnitudeWords];
 6264489        Span<ulong> secondTerm =
 6264490            stackalloc ulong[TriangleSweepMagnitudeWords];
 6264491        WideArithmetic.MultiplyMagnitudes(firstXMag, secondXMag, firstTerm);
 6264492        WideArithmetic.MultiplyMagnitudes(firstZMag, secondZMag, secondTerm);
 6264493        CombineSignedMagnitudes(
 6264494            firstTerm,
 6264495            firstX.Sign * secondX.Sign,
 6264496            secondTerm,
 6264497            firstZ.Sign * secondZ.Sign,
 6264498            result,
 6264499            out sign);
 6264500    }
 501
 502    private static void CombineSignedMagnitudes(
 503        ReadOnlySpan<ulong> first,
 504        int firstSign,
 505        ReadOnlySpan<ulong> second,
 506        int secondSign,
 507        Span<ulong> result,
 508        out int sign)
 509    {
 8770510        if (firstSign == 0)
 511        {
 2714512            CopyMagnitude(second, result);
 2714513            sign = secondSign;
 2714514            return;
 515        }
 6056516        if (secondSign == 0)
 517        {
 2481518            CopyMagnitude(first, result);
 2481519            sign = firstSign;
 2481520            return;
 521        }
 3575522        if (firstSign == secondSign)
 523        {
 1654524            WideArithmetic.AddEqualMagnitudes(first, second, result);
 1654525            sign = firstSign;
 1654526            return;
 527        }
 528
 1921529        int comparison = WideArithmetic.CompareMagnitudeEqualLength(first, second);
 1921530        if (comparison == 0)
 531        {
 11532            result.Clear();
 11533            sign = 0;
 11534            return;
 535        }
 1910536        if (comparison > 0)
 537        {
 1066538            WideArithmetic.SubtractEqualMagnitudes(first, second, result);
 1066539            sign = firstSign;
 1066540            return;
 541        }
 542
 844543        WideArithmetic.SubtractEqualMagnitudes(second, first, result);
 844544        sign = secondSign;
 844545    }
 546
 547    private static void CopyMagnitude(
 548        ReadOnlySpan<ulong> source,
 549        Span<ulong> destination)
 550    {
 5195551        destination.Clear();
 5195552        source[..Math.Min(source.Length, destination.Length)]
 5195553            .CopyTo(destination);
 5195554    }
 555
 556}

/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    {
 7825        Vector3d normalizedMinimum =
 7826            Vector3d.Min(sourceLocalMin, sourceLocalMax);
 7827        sourceLocalMax = Vector3d.Max(sourceLocalMin, sourceLocalMax);
 7828        sourceLocalMin = normalizedMinimum;
 7829        WideRationalBasis3d sourceBasis = new(sourceRotation);
 7830        WideRationalBasis3d targetBasis = new(targetRotation);
 7831        Signed320 denominator = WideArithmetic.MultiplySigned192(
 7832            sourceBasis.Denominator,
 7833            targetBasis.Denominator);
 7834        Signed192 deltaX = WideArithmetic.SubtractSigned192(
 7835            Signed192.Raw(sourceOrigin.X),
 7836            Signed192.Raw(targetOrigin.X));
 7837        Signed192 deltaY = WideArithmetic.SubtractSigned192(
 7838            Signed192.Raw(sourceOrigin.Y),
 7839            Signed192.Raw(targetOrigin.Y));
 7840        Signed192 deltaZ = WideArithmetic.SubtractSigned192(
 7841            Signed192.Raw(sourceOrigin.Z),
 7842            Signed192.Raw(targetOrigin.Z));
 43
 7844        GetRelativeBoundsCoordinate(
 7845            sourceBasis,
 7846            targetBasis.Xx,
 7847            targetBasis.Xy,
 7848            targetBasis.Xz,
 7849            sourceLocalMin,
 7850            sourceLocalMax,
 7851            deltaX,
 7852            deltaY,
 7853            deltaZ,
 7854            denominator,
 7855            out Fixed64 minX,
 7856            out Fixed64 maxX);
 7857        GetRelativeBoundsCoordinate(
 7858            sourceBasis,
 7859            targetBasis.Yx,
 7860            targetBasis.Yy,
 7861            targetBasis.Yz,
 7862            sourceLocalMin,
 7863            sourceLocalMax,
 7864            deltaX,
 7865            deltaY,
 7866            deltaZ,
 7867            denominator,
 7868            out Fixed64 minY,
 7869            out Fixed64 maxY);
 7870        GetRelativeBoundsCoordinate(
 7871            sourceBasis,
 7872            targetBasis.Zx,
 7873            targetBasis.Zy,
 7874            targetBasis.Zz,
 7875            sourceLocalMin,
 7876            sourceLocalMax,
 7877            deltaX,
 7878            deltaY,
 7879            deltaZ,
 7880            denominator,
 7881            out Fixed64 minZ,
 7882            out Fixed64 maxZ);
 7883        return FixedBoundBox.FromMinMax(
 7884            new Vector3d(minX, minY, minZ),
 7885            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    {
 234102        Signed320 sourceXCoefficient = WideArithmetic.GetDotProduct3D(
 234103            targetAxisX,
 234104            targetAxisY,
 234105            targetAxisZ,
 234106            sourceBasis.Xx,
 234107            sourceBasis.Xy,
 234108            sourceBasis.Xz);
 234109        Signed320 sourceYCoefficient = WideArithmetic.GetDotProduct3D(
 234110            targetAxisX,
 234111            targetAxisY,
 234112            targetAxisZ,
 234113            sourceBasis.Yx,
 234114            sourceBasis.Yy,
 234115            sourceBasis.Yz);
 234116        Signed320 sourceZCoefficient = WideArithmetic.GetDotProduct3D(
 234117            targetAxisX,
 234118            targetAxisY,
 234119            targetAxisZ,
 234120            sourceBasis.Zx,
 234121            sourceBasis.Zy,
 234122            sourceBasis.Zz);
 234123        Signed320 translatedProjection = WideArithmetic.AddSigned320(
 234124            WideArithmetic.AddSigned320(
 234125                WideArithmetic.MultiplySigned192(deltaX, targetAxisX),
 234126                WideArithmetic.MultiplySigned192(deltaY, targetAxisY)),
 234127            WideArithmetic.MultiplySigned192(deltaZ, targetAxisZ));
 234128        Signed576 translatedNumerator = WideArithmetic.MultiplySigned320(
 234129            translatedProjection,
 234130            Signed320.ExtendValue(sourceBasis.Denominator));
 131
 234132        Signed576 minimumNumerator = GetRelativeEndpointNumerator(
 234133            translatedNumerator,
 234134            sourceXCoefficient,
 234135            sourceYCoefficient,
 234136            sourceZCoefficient,
 234137            sourceLocalMin,
 234138            sourceLocalMax,
 234139            true);
 234140        Signed576 maximumNumerator = GetRelativeEndpointNumerator(
 234141            translatedNumerator,
 234142            sourceXCoefficient,
 234143            sourceYCoefficient,
 234144            sourceZCoefficient,
 234145            sourceLocalMin,
 234146            sourceLocalMax,
 234147            false);
 234148        minimum = GetRelativeEndpointClippedToDomain(
 234149            minimumNumerator,
 234150            denominator,
 234151            true);
 234152        maximum = GetRelativeEndpointClippedToDomain(
 234153            maximumNumerator,
 234154            denominator,
 234155            false);
 234156    }
 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    {
 468167        Fixed64 x = SelectEndpoint(
 468168            sourceXCoefficient,
 468169            sourceLocalMin.X,
 468170            sourceLocalMax.X,
 468171            minimum);
 468172        Fixed64 y = SelectEndpoint(
 468173            sourceYCoefficient,
 468174            sourceLocalMin.Y,
 468175            sourceLocalMax.Y,
 468176            minimum);
 468177        Fixed64 z = SelectEndpoint(
 468178            sourceZCoefficient,
 468179            sourceLocalMin.Z,
 468180            sourceLocalMax.Z,
 468181            minimum);
 468182        return WideArithmetic.AddSigned576(
 468183            WideArithmetic.AddSigned576(
 468184                WideArithmetic.AddSigned576(
 468185                    translatedNumerator,
 468186                    WideArithmetic.MultiplySigned320(
 468187                        sourceXCoefficient,
 468188                        Signed320.ExtendValue(Signed192.Raw(x)))),
 468189                WideArithmetic.MultiplySigned320(
 468190                    sourceYCoefficient,
 468191                    Signed320.ExtendValue(Signed192.Raw(y)))),
 468192            WideArithmetic.MultiplySigned320(
 468193                sourceZCoefficient,
 468194                Signed320.ExtendValue(Signed192.Raw(z))));
 195    }
 196
 197    private static Fixed64 SelectEndpoint(
 198        Signed320 coefficient,
 199        Fixed64 minimum,
 200        Fixed64 maximum,
 201        bool lower) =>
 1404202        (coefficient.Sign < 0) == lower ? maximum : minimum;
 203
 204    private static Fixed64 GetRelativeEndpointClippedToDomain(
 205        Signed576 numerator,
 206        Signed320 denominator,
 207        bool minimum)
 208    {
 468209        Signed576 minimumNumerator = WideArithmetic.MultiplySigned320(
 468210            Signed320.ExtendValue(Signed192.Raw(Fixed64.MinValue)),
 468211            denominator);
 468212        Signed576 maximumNumerator = WideArithmetic.MultiplySigned320(
 468213            Signed320.ExtendValue(Signed192.Raw(Fixed64.MaxValue)),
 468214            denominator);
 468215        if (CompareSigned(numerator, minimumNumerator) <= 0)
 13216            return Fixed64.MinValue;
 455217        if (CompareSigned(numerator, maximumNumerator) >= 0)
 14218            return Fixed64.MaxValue;
 219
 441220        _ = Fixed64.TryGetSignedRawRatio(
 441221            numerator,
 441222            Signed576.ExtendValue(denominator),
 441223            out Fixed64 endpoint);
 441224        Signed576 roundedNumerator = WideArithmetic.MultiplySigned320(
 441225            Signed320.ExtendValue(Signed192.Raw(endpoint)),
 441226            denominator);
 441227        int comparison = CompareSigned(roundedNumerator, numerator);
 441228        if (minimum && comparison > 0)
 135229            return Fixed64.FromRaw(endpoint.m_rawValue - 1L);
 306230        if (!minimum && comparison < 0)
 71231            return Fixed64.FromRaw(endpoint.m_rawValue + 1L);
 235232        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        {
 11034            Signed192 rawLength = Signed192.Raw(length);
 11035            X = WideArithmetic.MultiplySigned192(x, rawLength);
 11036            Y = WideArithmetic.MultiplySigned192(y, rawLength);
 11037            Z = WideArithmetic.MultiplySigned192(z, rawLength);
 11038            Denominator = WideArithmetic.MultiplySigned192(
 11039                rotationDenominator,
 11040                Signed192.One);
 11041        }
 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        bool strict = false)
 58    {
 59        // Point cores have no orientation-dependent extent. Compare their raw
 60        // center distance directly, retaining the exact radius sum and tangency rule.
 9361        if (firstLength == Fixed64.Zero && secondLength == Fixed64.Zero)
 62        {
 3863            int comparison = WideGeometry.CompareDistanceToRadiusSum(
 3864                firstCenter, secondCenter, firstRadius, secondRadius);
 3865            return strict ? comparison < 0 : comparison <= 0;
 66        }
 67
 5568        GetRotatedLocalAxisNumerators(
 5569            firstRotation,
 5570            firstLocalAxis,
 5571            out Signed192 firstAxisX,
 5572            out Signed192 firstAxisY,
 5573            out Signed192 firstAxisZ,
 5574            out Signed192 firstRotationDenominator);
 5575        GetRotatedLocalAxisNumerators(
 5576            secondRotation,
 5577            secondLocalAxis,
 5578            out Signed192 secondAxisX,
 5579            out Signed192 secondAxisY,
 5580            out Signed192 secondAxisZ,
 5581            out Signed192 secondRotationDenominator);
 82
 5583        var firstAxis = new RigidSegmentAxis(
 5584            firstAxisX,
 5585            firstAxisY,
 5586            firstAxisZ,
 5587            firstRotationDenominator,
 5588            firstLength);
 5589        var secondAxis = new RigidSegmentAxis(
 5590            secondAxisX,
 5591            secondAxisY,
 5592            secondAxisZ,
 5593            secondRotationDenominator,
 5594            secondLength);
 5595        Signed576 relationDenominator = WideArithmetic.AddSigned576(
 5596            WideArithmetic.MultiplySigned320(
 5597                firstAxis.Denominator,
 5598                secondAxis.Denominator),
 5599            WideArithmetic.MultiplySigned320(
 55100                firstAxis.Denominator,
 55101                secondAxis.Denominator));
 55102        GetRigidSegmentLowerDifference(
 55103            firstCenter,
 55104            firstAxis,
 55105            secondCenter,
 55106            secondAxis,
 55107            relationDenominator,
 55108            out Signed576 relationX,
 55109            out Signed576 relationY,
 55110            out Signed576 relationZ);
 111
 55112        Signed576 firstSquared = Dot(firstAxis, firstAxis);
 55113        Signed576 directionsDot = Dot(firstAxis, secondAxis);
 55114        Signed576 secondSquared = Dot(secondAxis, secondAxis);
 55115        Signed704 firstDotDifference = Dot(
 55116            firstAxis,
 55117            relationX,
 55118            relationY,
 55119            relationZ);
 55120        Signed704 secondDotDifference = Dot(
 55121            secondAxis,
 55122            relationX,
 55123            relationY,
 55124            relationZ);
 125
 55126        Span<ulong> determinant = stackalloc ulong[TriangleSweepMagnitudeWords];
 55127        GetProductDifference(
 55128            firstSquared,
 55129            secondSquared,
 55130            directionsDot,
 55131            directionsDot,
 55132            determinant,
 55133            out int determinantSign);
 134
 55135        Span<ulong> firstNumerator = stackalloc ulong[TriangleSweepMagnitudeWords];
 55136        Span<ulong> firstDenominator = stackalloc ulong[TriangleSweepMagnitudeWords];
 55137        Span<ulong> secondNumerator = stackalloc ulong[TriangleSweepMagnitudeWords];
 55138        Span<ulong> secondDenominator = stackalloc ulong[TriangleSweepMagnitudeWords];
 139        int firstNumeratorSign;
 140        int secondNumeratorSign;
 141        int firstFeature;
 142        int secondFeature;
 55143        if (determinantSign > 0)
 144        {
 40145            Span<ulong> firstCore = stackalloc ulong[TriangleSweepMagnitudeWords];
 40146            GetProductDifference(
 40147                directionsDot,
 40148                secondDotDifference,
 40149                secondSquared,
 40150                firstDotDifference,
 40151                firstCore,
 40152                out int firstCoreSign);
 40153            SetRigidSegmentRatio(
 40154                firstCore,
 40155                firstAxis.Denominator,
 40156                determinant,
 40157                relationDenominator,
 40158                firstNumerator,
 40159                firstDenominator);
 40160            firstNumeratorSign = firstCoreSign;
 40161            firstFeature = ClampUnitRatio(
 40162                firstNumerator,
 40163                firstDenominator,
 40164                firstNumeratorSign);
 165
 40166            if (firstFeature == RigidSegmentLower)
 167            {
 12168                SetRigidSegmentProjectionRatio(
 12169                    secondDotDifference,
 12170                    secondAxis.Denominator,
 12171                    secondSquared,
 12172                    relationDenominator,
 12173                    secondNumerator,
 12174                    secondDenominator);
 12175                secondNumeratorSign = secondDotDifference.Sign;
 176            }
 28177            else if (firstFeature == RigidSegmentUpper)
 178            {
 12179                Signed704 upperProjection = WideArithmetic.AddSigned704(
 12180                    secondDotDifference,
 12181                    DoubleProduct(
 12182                        directionsDot,
 12183                        secondAxis.Denominator));
 12184                SetRigidSegmentProjectionRatio(
 12185                    upperProjection,
 12186                    secondAxis.Denominator,
 12187                    secondSquared,
 12188                    relationDenominator,
 12189                    secondNumerator,
 12190                    secondDenominator);
 12191                secondNumeratorSign = upperProjection.Sign;
 192            }
 193            else
 194            {
 16195                Span<ulong> secondCore = stackalloc ulong[TriangleSweepMagnitudeWords];
 16196                GetProductDifference(
 16197                    firstSquared,
 16198                    secondDotDifference,
 16199                    directionsDot,
 16200                    firstDotDifference,
 16201                    secondCore,
 16202                    out int secondCoreSign);
 16203                SetRigidSegmentRatio(
 16204                    secondCore,
 16205                    secondAxis.Denominator,
 16206                    determinant,
 16207                    relationDenominator,
 16208                    secondNumerator,
 16209                    secondDenominator);
 16210                secondNumeratorSign = secondCoreSign;
 211            }
 212        }
 213        else
 214        {
 15215            firstNumerator.Clear();
 15216            firstDenominator.Clear();
 15217            firstDenominator[0] = 1UL;
 15218            firstNumeratorSign = 0;
 15219            firstFeature = RigidSegmentLower;
 15220            SetRigidSegmentProjectionRatio(
 15221                secondDotDifference,
 15222                secondAxis.Denominator,
 15223                secondSquared,
 15224                relationDenominator,
 15225                secondNumerator,
 15226                secondDenominator);
 15227            secondNumeratorSign = secondDotDifference.Sign;
 228        }
 229
 55230        secondFeature = ClampUnitRatio(
 55231            secondNumerator,
 55232            secondDenominator,
 55233            secondNumeratorSign);
 55234        if (secondFeature == RigidSegmentLower)
 235        {
 30236            SetRigidSegmentProjectionRatio(
 30237                WideArithmetic.SubtractSigned704(
 30238                    default,
 30239                    firstDotDifference),
 30240                firstAxis.Denominator,
 30241                firstSquared,
 30242                relationDenominator,
 30243                firstNumerator,
 30244                firstDenominator);
 30245            firstNumeratorSign = -firstDotDifference.Sign;
 30246            firstFeature = ClampUnitRatio(
 30247                firstNumerator,
 30248                firstDenominator,
 30249                firstNumeratorSign);
 250        }
 25251        else if (secondFeature == RigidSegmentUpper)
 252        {
 12253            Signed704 upperProjection = WideArithmetic.SubtractSigned704(
 12254                DoubleProduct(
 12255                    directionsDot,
 12256                    firstAxis.Denominator),
 12257                firstDotDifference);
 12258            SetRigidSegmentProjectionRatio(
 12259                upperProjection,
 12260                firstAxis.Denominator,
 12261                firstSquared,
 12262                relationDenominator,
 12263                firstNumerator,
 12264                firstDenominator);
 12265            firstNumeratorSign = upperProjection.Sign;
 12266            firstFeature = ClampUnitRatio(
 12267                firstNumerator,
 12268                firstDenominator,
 12269                firstNumeratorSign);
 270        }
 271
 55272        if (firstFeature == RigidSegmentUpper)
 273        {
 20274            AddRigidSegmentDisplacement(
 20275                ref relationX,
 20276                firstAxis.X,
 20277                secondAxis.Denominator);
 20278            AddRigidSegmentDisplacement(
 20279                ref relationY,
 20280                firstAxis.Y,
 20281                secondAxis.Denominator);
 20282            AddRigidSegmentDisplacement(
 20283                ref relationZ,
 20284                firstAxis.Z,
 20285                secondAxis.Denominator);
 286        }
 55287        if (secondFeature == RigidSegmentUpper)
 288        {
 12289            SubtractRigidSegmentDisplacement(
 12290                ref relationX,
 12291                secondAxis.X,
 12292                firstAxis.Denominator);
 12293            SubtractRigidSegmentDisplacement(
 12294                ref relationY,
 12295                secondAxis.Y,
 12296                firstAxis.Denominator);
 12297            SubtractRigidSegmentDisplacement(
 12298                ref relationZ,
 12299                secondAxis.Z,
 12300                firstAxis.Denominator);
 301        }
 302
 55303        Signed192 combinedRadius = WideArithmetic.AddSigned192(
 55304            Signed192.Raw(firstRadius),
 55305            Signed192.Raw(secondRadius));
 55306        if (firstFeature == RigidSegmentInterior
 55307            && secondFeature == RigidSegmentInterior)
 308        {
 4309            return IsRigidLinePairWithinRadius(
 4310                relationX,
 4311                relationY,
 4312                relationZ,
 4313                firstSquared,
 4314                directionsDot,
 4315                secondSquared,
 4316                firstDotDifference,
 4317                secondDotDifference,
 4318                determinant,
 4319                relationDenominator,
 4320                combinedRadius,
 4321                strict);
 322        }
 51323        if (firstFeature == RigidSegmentInterior)
 324        {
 17325            Signed704 adjustedDot = Dot(
 17326                firstAxis,
 17327                relationX,
 17328                relationY,
 17329                relationZ);
 17330            return IsRigidPointLineWithinRadius(
 17331                relationX,
 17332                relationY,
 17333                relationZ,
 17334                firstSquared,
 17335                adjustedDot,
 17336                relationDenominator,
 17337                combinedRadius,
 17338                strict);
 339        }
 34340        if (secondFeature == RigidSegmentInterior)
 341        {
 9342            Signed704 adjustedDot = Dot(
 9343                secondAxis,
 9344                relationX,
 9345                relationY,
 9346                relationZ);
 9347            return IsRigidPointLineWithinRadius(
 9348                relationX,
 9349                relationY,
 9350                relationZ,
 9351                secondSquared,
 9352                adjustedDot,
 9353                relationDenominator,
 9354                combinedRadius,
 9355                strict);
 356        }
 357
 25358        return IsRigidPointWithinRadius(
 25359            relationX,
 25360            relationY,
 25361            relationZ,
 25362            relationDenominator,
 25363            combinedRadius,
 25364            strict);
 365    }
 366
 367    private const int RigidSegmentLower = -1;
 368    private const int RigidSegmentInterior = 0;
 369    private const int RigidSegmentUpper = 1;
 370
 371    private static int ClampUnitRatio(
 372        Span<ulong> numerator,
 373        Span<ulong> denominator,
 374        int numeratorSign)
 375    {
 137376        if (numeratorSign <= 0)
 377        {
 51378            numerator.Clear();
 51379            denominator.Clear();
 51380            denominator[0] = 1UL;
 51381            return RigidSegmentLower;
 382        }
 383
 86384        int comparison = WideArithmetic.CompareMagnitudeEqualLength(numerator, denominator);
 86385        if (comparison < 0)
 46386            return RigidSegmentInterior;
 387
 40388        denominator.CopyTo(numerator);
 40389        return RigidSegmentUpper;
 390    }
 391
 392    private static void SetRigidSegmentRatio(
 393        ReadOnlySpan<ulong> core,
 394        Signed320 axisDenominator,
 395        ReadOnlySpan<ulong> determinant,
 396        Signed576 relationDenominator,
 397        Span<ulong> numerator,
 398        Span<ulong> denominator)
 399    {
 56400        Span<ulong> axisDenominatorMagnitude = stackalloc ulong[5];
 56401        WideArithmetic.GetMagnitude(
 56402            axisDenominator,
 56403            out axisDenominatorMagnitude[4],
 56404            out axisDenominatorMagnitude[3],
 56405            out axisDenominatorMagnitude[2],
 56406            out axisDenominatorMagnitude[1],
 56407            out axisDenominatorMagnitude[0]);
 56408        WideArithmetic.MultiplyMagnitudes(core, axisDenominatorMagnitude, numerator);
 409
 56410        Span<ulong> relationDenominatorMagnitude = stackalloc ulong[9];
 56411        WideArithmetic.GetMagnitude(
 56412            relationDenominator,
 56413            relationDenominatorMagnitude);
 56414        WideArithmetic.MultiplyMagnitudes(
 56415            determinant,
 56416            relationDenominatorMagnitude,
 56417            denominator);
 56418    }
 419
 420    private static void SetRigidSegmentProjectionRatio(
 421        Signed704 projection,
 422        Signed320 axisDenominator,
 423        Signed576 axisSquared,
 424        Signed576 relationDenominator,
 425        Span<ulong> numerator,
 426        Span<ulong> denominator)
 427    {
 81428        Span<ulong> projectionMagnitude = stackalloc ulong[11];
 81429        Span<ulong> axisDenominatorMagnitude = stackalloc ulong[5];
 81430        Span<ulong> axisSquaredMagnitude = stackalloc ulong[9];
 81431        Span<ulong> relationDenominatorMagnitude = stackalloc ulong[9];
 81432        WideArithmetic.GetMagnitude(projection, projectionMagnitude);
 81433        WideArithmetic.GetMagnitude(
 81434            axisDenominator,
 81435            out axisDenominatorMagnitude[4],
 81436            out axisDenominatorMagnitude[3],
 81437            out axisDenominatorMagnitude[2],
 81438            out axisDenominatorMagnitude[1],
 81439            out axisDenominatorMagnitude[0]);
 81440        WideArithmetic.GetMagnitude(axisSquared, axisSquaredMagnitude);
 81441        WideArithmetic.GetMagnitude(
 81442            relationDenominator,
 81443            relationDenominatorMagnitude);
 81444        WideArithmetic.MultiplyMagnitudes(
 81445            projectionMagnitude,
 81446            axisDenominatorMagnitude,
 81447            numerator);
 81448        WideArithmetic.MultiplyMagnitudes(
 81449            axisSquaredMagnitude,
 81450            relationDenominatorMagnitude,
 81451            denominator);
 81452    }
 453
 454    private static bool IsRigidLinePairWithinRadius(
 455        Signed576 relationX,
 456        Signed576 relationY,
 457        Signed576 relationZ,
 458        Signed576 firstSquared,
 459        Signed576 directionsDot,
 460        Signed576 secondSquared,
 461        Signed704 firstDotDifference,
 462        Signed704 secondDotDifference,
 463        ReadOnlySpan<ulong> determinant,
 464        Signed576 relationDenominator,
 465        Signed192 radius,
 466        bool strict)
 467    {
 4468        Span<ulong> relationSquared = stackalloc ulong[13];
 4469        GetSquaredMagnitude(
 4470            relationX,
 4471            relationY,
 4472            relationZ,
 4473            relationSquared);
 4474        Span<ulong> relationTerm = stackalloc ulong[TriangleSweepMagnitudeWords];
 4475        WideArithmetic.MultiplyMagnitudes(
 4476            relationSquared,
 4477            determinant,
 4478            relationTerm);
 479
 4480        Span<ulong> firstCorrection = stackalloc ulong[TriangleSweepMagnitudeWords];
 4481        GetTripleProductMagnitude(
 4482            secondSquared,
 4483            firstDotDifference,
 4484            firstDotDifference,
 4485            firstCorrection);
 4486        Span<ulong> mixedCorrection = stackalloc ulong[TriangleSweepMagnitudeWords];
 4487        GetTripleProductMagnitude(
 4488            directionsDot,
 4489            firstDotDifference,
 4490            secondDotDifference,
 4491            mixedCorrection);
 4492        DoubleMagnitude(mixedCorrection);
 4493        Span<ulong> secondCorrection = stackalloc ulong[TriangleSweepMagnitudeWords];
 4494        GetTripleProductMagnitude(
 4495            firstSquared,
 4496            secondDotDifference,
 4497            secondDotDifference,
 4498            secondCorrection);
 499
 4500        Span<ulong> correction = stackalloc ulong[TriangleSweepMagnitudeWords];
 4501        Span<ulong> correctionScratch = stackalloc ulong[TriangleSweepMagnitudeWords];
 4502        CombineSignedMagnitudes(
 4503            firstCorrection,
 4504            1,
 4505            mixedCorrection,
 4506            -(directionsDot.Sign
 4507                * firstDotDifference.Sign
 4508                * secondDotDifference.Sign),
 4509            correctionScratch,
 4510            out int correctionSign);
 4511        CombineSignedMagnitudes(
 4512            correctionScratch,
 4513            correctionSign,
 4514            secondCorrection,
 4515            1,
 4516            correction,
 4517            out _);
 518
 4519        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 520        // An interior/interior closest pair has a strictly positive projected
 521        // correction. A zero parameter is classified as a cap before reaching
 522        // this branch.
 4523        WideArithmetic.SubtractEqualMagnitudes(relationTerm, correction, left);
 524
 4525        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 4526        GetRadiusThreshold(
 4527            radius,
 4528            relationDenominator,
 4529            determinant,
 4530            right);
 4531        int comparison = WideArithmetic.CompareMagnitudeEqualLength(left, right);
 4532        return strict ? comparison < 0 : comparison <= 0;
 533    }
 534
 535    private static bool IsRigidPointLineWithinRadius(
 536        Signed576 relationX,
 537        Signed576 relationY,
 538        Signed576 relationZ,
 539        Signed576 axisSquared,
 540        Signed704 axisDotDifference,
 541        Signed576 relationDenominator,
 542        Signed192 radius,
 543        bool strict)
 544    {
 26545        Span<ulong> relationSquared = stackalloc ulong[13];
 26546        GetSquaredMagnitude(
 26547            relationX,
 26548            relationY,
 26549            relationZ,
 26550            relationSquared);
 26551        Span<ulong> axisSquaredMagnitude = stackalloc ulong[9];
 26552        WideArithmetic.GetMagnitude(axisSquared, axisSquaredMagnitude);
 26553        Span<ulong> relationTerm = stackalloc ulong[TriangleSweepMagnitudeWords];
 26554        WideArithmetic.MultiplyMagnitudes(
 26555            relationSquared,
 26556            axisSquaredMagnitude,
 26557            relationTerm);
 26558        Span<ulong> dotMagnitude = stackalloc ulong[11];
 26559        WideArithmetic.GetMagnitude(axisDotDifference, dotMagnitude);
 26560        Span<ulong> dotSquared = stackalloc ulong[TriangleSweepMagnitudeWords];
 26561        WideArithmetic.MultiplyMagnitudes(dotMagnitude, dotMagnitude, dotSquared);
 26562        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 26563        WideArithmetic.SubtractEqualMagnitudes(relationTerm, dotSquared, left);
 564
 26565        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 26566        GetRadiusThreshold(
 26567            radius,
 26568            relationDenominator,
 26569            axisSquaredMagnitude,
 26570            right);
 26571        int comparison = WideArithmetic.CompareMagnitudeEqualLength(left, right);
 26572        return strict ? comparison < 0 : comparison <= 0;
 573    }
 574
 575    private static bool IsRigidPointWithinRadius(
 576        Signed576 relationX,
 577        Signed576 relationY,
 578        Signed576 relationZ,
 579        Signed576 relationDenominator,
 580        Signed192 radius,
 581        bool strict)
 582    {
 25583        Span<ulong> left = stackalloc ulong[TriangleSweepMagnitudeWords];
 25584        left.Clear();
 25585        GetSquaredMagnitude(
 25586            relationX,
 25587            relationY,
 25588            relationZ,
 25589            left);
 25590        Span<ulong> right = stackalloc ulong[TriangleSweepMagnitudeWords];
 25591        GetRadiusThreshold(
 25592            radius,
 25593            relationDenominator,
 25594            ReadOnlySpan<ulong>.Empty,
 25595            right);
 25596        int comparison = WideArithmetic.CompareMagnitudeEqualLength(left, right);
 25597        return strict ? comparison < 0 : comparison <= 0;
 598    }
 599
 600    private static void GetRadiusThreshold(
 601        Signed192 radius,
 602        Signed576 relationDenominator,
 603        ReadOnlySpan<ulong> factor,
 604        Span<ulong> result)
 605    {
 55606        Span<ulong> radiusMagnitude = stackalloc ulong[3];
 55607        Span<ulong> denominatorMagnitude = stackalloc ulong[9];
 55608        WideArithmetic.GetMagnitude(
 55609            radius,
 55610            out radiusMagnitude[2],
 55611            out radiusMagnitude[1],
 55612            out radiusMagnitude[0]);
 55613        WideArithmetic.GetMagnitude(
 55614            relationDenominator,
 55615            denominatorMagnitude);
 55616        Span<ulong> radiusSquared = stackalloc ulong[6];
 55617        Span<ulong> denominatorSquared = stackalloc ulong[18];
 55618        WideArithmetic.MultiplyMagnitudes(radiusMagnitude, radiusMagnitude, radiusSquared);
 55619        WideArithmetic.MultiplyMagnitudes(
 55620            denominatorMagnitude,
 55621            denominatorMagnitude,
 55622            denominatorSquared);
 55623        Span<ulong> baseThreshold = stackalloc ulong[TriangleSweepMagnitudeWords];
 55624        WideArithmetic.MultiplyMagnitudes(
 55625            radiusSquared,
 55626            denominatorSquared,
 55627            baseThreshold);
 55628        if (factor.IsEmpty)
 629        {
 25630            baseThreshold.CopyTo(result);
 25631            return;
 632        }
 633
 30634        WideArithmetic.MultiplyMagnitudes(baseThreshold, factor, result);
 30635    }
 636
 637    private static void GetSquaredMagnitude(
 638        Signed576 x,
 639        Signed576 y,
 640        Signed576 z,
 641        Span<ulong> result)
 642    {
 55643        Signed832 squared = WideArithmetic.AddSigned832(
 55644            WideArithmetic.AddSigned832(
 55645                WideArithmetic.MultiplySigned576ToSigned832(x, x),
 55646                WideArithmetic.MultiplySigned576ToSigned832(y, y)),
 55647            WideArithmetic.MultiplySigned576ToSigned832(z, z));
 55648        WideArithmetic.GetMagnitude(squared, result);
 55649    }
 650
 651    private static void GetTripleProductMagnitude(
 652        Signed576 first,
 653        Signed704 second,
 654        Signed704 third,
 655        Span<ulong> result)
 656    {
 12657        Span<ulong> firstMagnitude = stackalloc ulong[9];
 12658        Span<ulong> secondMagnitude = stackalloc ulong[11];
 12659        Span<ulong> thirdMagnitude = stackalloc ulong[11];
 12660        WideArithmetic.GetMagnitude(first, firstMagnitude);
 12661        WideArithmetic.GetMagnitude(second, secondMagnitude);
 12662        WideArithmetic.GetMagnitude(third, thirdMagnitude);
 12663        Span<ulong> firstProduct = stackalloc ulong[20];
 12664        WideArithmetic.MultiplyMagnitudes(
 12665            firstMagnitude,
 12666            secondMagnitude,
 12667            firstProduct);
 12668        WideArithmetic.MultiplyMagnitudes(firstProduct, thirdMagnitude, result);
 12669    }
 670
 671    private static void GetProductDifference(
 672        Signed576 firstLeft,
 673        Signed576 firstRight,
 674        Signed576 secondLeft,
 675        Signed576 secondRight,
 676        Span<ulong> result,
 677        out int sign)
 678    {
 55679        Span<ulong> firstLeftMagnitude = stackalloc ulong[9];
 55680        Span<ulong> firstRightMagnitude = stackalloc ulong[9];
 55681        Span<ulong> secondLeftMagnitude = stackalloc ulong[9];
 55682        Span<ulong> secondRightMagnitude = stackalloc ulong[9];
 55683        WideArithmetic.GetMagnitude(firstLeft, firstLeftMagnitude);
 55684        WideArithmetic.GetMagnitude(firstRight, firstRightMagnitude);
 55685        WideArithmetic.GetMagnitude(secondLeft, secondLeftMagnitude);
 55686        WideArithmetic.GetMagnitude(secondRight, secondRightMagnitude);
 55687        Span<ulong> first = stackalloc ulong[TriangleSweepMagnitudeWords];
 55688        Span<ulong> second = stackalloc ulong[TriangleSweepMagnitudeWords];
 55689        WideArithmetic.MultiplyMagnitudes(
 55690            firstLeftMagnitude,
 55691            firstRightMagnitude,
 55692            first);
 55693        WideArithmetic.MultiplyMagnitudes(
 55694            secondLeftMagnitude,
 55695            secondRightMagnitude,
 55696            second);
 55697        CombineSignedMagnitudes(
 55698            first,
 55699            firstLeft.Sign * firstRight.Sign,
 55700            second,
 55701            -(secondLeft.Sign * secondRight.Sign),
 55702            result,
 55703            out sign);
 55704    }
 705
 706    private static void GetProductDifference(
 707        Signed576 firstLeft,
 708        Signed704 firstRight,
 709        Signed576 secondLeft,
 710        Signed704 secondRight,
 711        Span<ulong> result,
 712        out int sign)
 713    {
 56714        Span<ulong> firstLeftMagnitude = stackalloc ulong[9];
 56715        Span<ulong> firstRightMagnitude = stackalloc ulong[11];
 56716        Span<ulong> secondLeftMagnitude = stackalloc ulong[9];
 56717        Span<ulong> secondRightMagnitude = stackalloc ulong[11];
 56718        WideArithmetic.GetMagnitude(firstLeft, firstLeftMagnitude);
 56719        WideArithmetic.GetMagnitude(firstRight, firstRightMagnitude);
 56720        WideArithmetic.GetMagnitude(secondLeft, secondLeftMagnitude);
 56721        WideArithmetic.GetMagnitude(secondRight, secondRightMagnitude);
 56722        Span<ulong> first = stackalloc ulong[TriangleSweepMagnitudeWords];
 56723        Span<ulong> second = stackalloc ulong[TriangleSweepMagnitudeWords];
 56724        WideArithmetic.MultiplyMagnitudes(
 56725            firstLeftMagnitude,
 56726            firstRightMagnitude,
 56727            first);
 56728        WideArithmetic.MultiplyMagnitudes(
 56729            secondLeftMagnitude,
 56730            secondRightMagnitude,
 56731            second);
 56732        CombineSignedMagnitudes(
 56733            first,
 56734            firstLeft.Sign * firstRight.Sign,
 56735            second,
 56736            -(secondLeft.Sign * secondRight.Sign),
 56737            result,
 56738            out sign);
 56739    }
 740
 741    private static void DoubleMagnitude(Span<ulong> value)
 742    {
 4743        ulong carry = 0UL;
 304744        for (int index = 0; index < value.Length; index++)
 745        {
 148746            ulong nextCarry = value[index] >> 63;
 148747            value[index] = (value[index] << 1) | carry;
 148748            carry = nextCarry;
 749        }
 4750    }
 751
 752    private static Signed704 DoubleProduct(
 753        Signed576 value,
 754        Signed320 factor)
 755    {
 24756        Signed704 product =
 24757            WideArithmetic.MultiplySigned576ToSigned704(value, factor);
 24758        return WideArithmetic.AddSigned704(product, product);
 759    }
 760
 761    private static void GetRigidSegmentLowerDifference(
 762        Vector3d firstCenter,
 763        RigidSegmentAxis firstAxis,
 764        Vector3d secondCenter,
 765        RigidSegmentAxis secondAxis,
 766        Signed576 relationDenominator,
 767        out Signed576 x,
 768        out Signed576 y,
 769        out Signed576 z)
 770    {
 55771        x = GetRigidSegmentLowerDifference(
 55772            firstCenter.X,
 55773            firstAxis.X,
 55774            firstAxis.Denominator,
 55775            secondCenter.X,
 55776            secondAxis.X,
 55777            secondAxis.Denominator,
 55778            relationDenominator);
 55779        y = GetRigidSegmentLowerDifference(
 55780            firstCenter.Y,
 55781            firstAxis.Y,
 55782            firstAxis.Denominator,
 55783            secondCenter.Y,
 55784            secondAxis.Y,
 55785            secondAxis.Denominator,
 55786            relationDenominator);
 55787        z = GetRigidSegmentLowerDifference(
 55788            firstCenter.Z,
 55789            firstAxis.Z,
 55790            firstAxis.Denominator,
 55791            secondCenter.Z,
 55792            secondAxis.Z,
 55793            secondAxis.Denominator,
 55794            relationDenominator);
 55795    }
 796
 797    private static Signed576 GetRigidSegmentLowerDifference(
 798        Fixed64 firstCenter,
 799        Signed320 firstAxis,
 800        Signed320 firstDenominator,
 801        Fixed64 secondCenter,
 802        Signed320 secondAxis,
 803        Signed320 secondDenominator,
 804        Signed576 relationDenominator)
 805    {
 165806        Signed576 centerTerm = WideArithmetic.MultiplySigned576(
 165807            relationDenominator,
 165808            WideArithmetic.SubtractSigned192(
 165809                Signed192.Raw(firstCenter),
 165810                Signed192.Raw(secondCenter)));
 165811        Signed576 firstEndpoint = WideArithmetic.MultiplySigned320(
 165812            firstAxis,
 165813            secondDenominator);
 165814        Signed576 secondEndpoint = WideArithmetic.MultiplySigned320(
 165815            secondAxis,
 165816            firstDenominator);
 165817        return WideArithmetic.AddSigned576(
 165818            WideArithmetic.SubtractSigned576(
 165819                centerTerm,
 165820                firstEndpoint),
 165821            secondEndpoint);
 822    }
 823
 824    private static void AddRigidSegmentDisplacement(
 825        ref Signed576 relation,
 826        Signed320 axis,
 827        Signed320 otherDenominator)
 828    {
 60829        Signed576 displacement = WideArithmetic.MultiplySigned320(
 60830            axis,
 60831            otherDenominator);
 60832        relation = WideArithmetic.AddSigned576(
 60833            relation,
 60834            WideArithmetic.AddSigned576(displacement, displacement));
 60835    }
 836
 837    private static void SubtractRigidSegmentDisplacement(
 838        ref Signed576 relation,
 839        Signed320 axis,
 840        Signed320 otherDenominator)
 841    {
 36842        Signed576 displacement = WideArithmetic.MultiplySigned320(
 36843            axis,
 36844            otherDenominator);
 36845        relation = WideArithmetic.SubtractSigned576(
 36846            relation,
 36847            WideArithmetic.AddSigned576(displacement, displacement));
 36848    }
 849
 850    private static Signed576 Dot(
 851        RigidSegmentAxis first,
 852        RigidSegmentAxis second) =>
 165853        WideArithmetic.AddSigned576(
 165854            WideArithmetic.AddSigned576(
 165855                WideArithmetic.MultiplySigned320(first.X, second.X),
 165856                WideArithmetic.MultiplySigned320(first.Y, second.Y)),
 165857            WideArithmetic.MultiplySigned320(first.Z, second.Z));
 858
 859    private static Signed704 Dot(
 860        RigidSegmentAxis axis,
 861        Signed576 x,
 862        Signed576 y,
 863        Signed576 z) =>
 136864        WideArithmetic.AddSigned704(
 136865            WideArithmetic.AddSigned704(
 136866                WideArithmetic.MultiplySigned576ToSigned704(x, axis.X),
 136867                WideArithmetic.MultiplySigned576ToSigned704(y, axis.Y)),
 136868            WideArithmetic.MultiplySigned576ToSigned704(z, axis.Z));
 869}

/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.ScaledHull.cs

#LineLine coverage
 1//=======================================================================
 2// WideOrientedBox.ScaledHull.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
 13
 14
 15
 16
 17
 18/// <content>Authored-frame SAT ingress retaining scale residuals through axis and interval selection.</content>
 19internal static partial class WideOrientedBox
 20{
 62221    internal static ReadOnlySpan<int> BoxHullTriangles => new int[]
 62222        { 0,2,3, 0,3,1, 4,5,7, 4,7,6, 0,1,5, 0,5,4, 2,6,7, 2,7,3, 0,4,6, 0,6,2, 1,3,7, 1,7,5 };
 223    internal static ReadOnlySpan<int> BoxHullEdges => new int[]
 224        { 0,1, 0,2, 0,4, 1,3, 1,5, 2,3, 2,6, 3,7, 4,5, 4,6, 5,7, 6,7 };
 25
 26    internal static void GetBoxHullVertices(Vector3d halfExtents, Span<Vector3d> vertices)
 27    {
 115228        for (int index = 0; index < 8; index++)
 51229            vertices[index] = new Vector3d((index & 1) == 0 ? -halfExtents.X : halfExtents.X,
 51230                (index & 2) == 0 ? -halfExtents.Y : halfExtents.Y,
 51231                (index & 4) == 0 ? -halfExtents.Z : halfExtents.Z);
 6432    }
 33
 34    internal static bool TryGetConvexHullContact(Vector3d boxCenter, FixedQuaternion boxRotation,
 35        Vector3d boxHalfExtents, in ScaledRigidFrame3d hullFrame, Vector3d hullAnchorOrigin,
 36        ReadOnlySpan<Vector3d> hullPoints, ReadOnlySpan<int> triangles, ReadOnlySpan<int> edges,
 37        out FixedContactAnchors contact)
 38    {
 339        if (hullFrame.IsRigid)
 140            return TryGetConvexHullContact(boxCenter, boxRotation, boxHalfExtents,
 141                hullFrame.RigidOrigin, hullFrame.Rotation, hullPoints, triangles, edges, out contact);
 242        Span<Vector3d> vertices = stackalloc Vector3d[8];
 243        GetBoxHullVertices(boxHalfExtents, vertices);
 244        return TryGetConvexHullContact(ScaledRigidFrame3d.Rigid(boxCenter, boxRotation), boxCenter,
 245            vertices, BoxHullTriangles, BoxHullEdges, hullFrame, hullAnchorOrigin, hullPoints,
 246            triangles, edges, out contact);
 47    }
 48
 49    internal static bool TryGetConvexHullContact(
 50        in ScaledRigidFrame3d firstFrame, Vector3d firstAnchorOrigin, ReadOnlySpan<Vector3d> firstPoints,
 51        ReadOnlySpan<int> firstTriangles, ReadOnlySpan<int> firstEdges,
 52        in ScaledRigidFrame3d secondFrame, Vector3d secondAnchorOrigin, ReadOnlySpan<Vector3d> secondPoints,
 53        ReadOnlySpan<int> secondTriangles, ReadOnlySpan<int> secondEdges, out FixedContactAnchors contact)
 54    {
 555        contact = default;
 556        if (!TryGetConvexHullPenetration(firstFrame, firstPoints, firstTriangles, firstEdges,
 657                secondFrame, secondPoints, secondTriangles, secondEdges, out var best)) return false;
 458        WideDirection3d axis = best.Negate ? -best.Axis : best.Axis;
 459        Signed832 firstSupport = GetScaledHullSupport(firstFrame, firstPoints, axis, true);
 460        Signed832 secondSupport = GetScaledHullSupport(secondFrame, secondPoints, axis, false);
 861        Vector3d firstLocal = default, secondLocal = default;
 862        bool firstFound = false, secondFound = false;
 1863        foreach (Vector3d vertex in firstPoints)
 64        {
 765            RationalPoint3d point = firstFrame.GetPoint(vertex);
 766            if (!IsScaledHullSupport(point, axis, firstSupport)) continue;
 467            firstFound = point.TryGetLocalPointIn(firstAnchorOrigin, FixedQuaternion.Identity, out firstLocal);
 468            break;
 69        }
 1470        foreach (Vector3d vertex in secondPoints)
 71        {
 572            RationalPoint3d point = secondFrame.GetPoint(vertex);
 573            if (!IsScaledHullSupport(point, axis, secondSupport)) continue;
 474            secondFound = point.TryGetLocalPointIn(secondAnchorOrigin, FixedQuaternion.Identity, out secondLocal);
 475            break;
 76        }
 677        if (!firstFound || !secondFound) return false;
 278        Fixed64 depth = best.GetRoundedDepth(out bool clamped);
 279        contact = new FixedContactAnchors(new FixedPointAnchor(firstAnchorOrigin, FixedQuaternion.Identity, firstLocal),
 280            new FixedPointAnchor(secondAnchorOrigin, FixedQuaternion.Identity, secondLocal), best.GetNormal(), depth, cl
 281        return true;
 82    }
 83
 84    internal static int VisitConvexHullContacts<TState>(
 85        in ScaledRigidFrame3d firstFrame, Vector3d firstAnchorOrigin, ReadOnlySpan<Vector3d> firstPoints,
 86        ReadOnlySpan<int> firstTriangles, ReadOnlySpan<int> firstEdges,
 87        in ScaledRigidFrame3d secondFrame, Vector3d secondAnchorOrigin, ReadOnlySpan<Vector3d> secondPoints,
 88        ReadOnlySpan<int> secondTriangles, ReadOnlySpan<int> secondEdges,
 89        in WideScaledHullPenetration penetration, TState state, Action<TState, FixedContactAnchors> visitor,
 90        IScaledConvexHullContactDomain? domain = null, bool admissionOnly = false)
 91 =>
 2292        VisitConvexHullContacts<ScaledRigidFrame3d, ScaledRigidFrame3d, TState>(firstFrame, firstAnchorOrigin, firstPoin
 2293            firstTriangles, firstEdges, secondFrame, secondAnchorOrigin, secondPoints, secondTriangles, secondEdges,
 2294            penetration, state, visitor, domain, admissionOnly);
 95
 96    internal static int VisitConvexHullContacts<TFirstFrame, TSecondFrame, TState>(
 97        in TFirstFrame firstFrame, Vector3d firstAnchorOrigin, ReadOnlySpan<Vector3d> firstPoints,
 98        ReadOnlySpan<int> firstTriangles, ReadOnlySpan<int> firstEdges,
 99        in TSecondFrame secondFrame, Vector3d secondAnchorOrigin, ReadOnlySpan<Vector3d> secondPoints,
 100        ReadOnlySpan<int> secondTriangles, ReadOnlySpan<int> secondEdges,
 101        in WideScaledHullPenetration penetration, TState state, Action<TState, FixedContactAnchors> visitor,
 102        IScaledConvexHullContactDomain? domain = null, bool admissionOnly = false)
 103        where TFirstFrame : struct, IForwardHullFrame3d
 104        where TSecondFrame : struct, IForwardHullFrame3d
 105    {
 25106        WideDirection3d axis = penetration.Negate ? -penetration.Axis : penetration.Axis;
 25107        Vector3d normal = admissionOnly ? default : axis.GetNormal(false);
 25108        bool clamped = false;
 25109        Fixed64 depth = admissionOnly ? default : penetration.GetRoundedDepth(out clamped);
 25110        int count = VisitScaledHullSide(firstFrame, firstAnchorOrigin, firstPoints, firstEdges,
 25111            secondFrame, secondAnchorOrigin, secondPoints, secondTriangles, secondEdges, axis,
 25112            normal, depth, clamped, state, visitor, domain, admissionOnly, false, out bool complete);
 31113        if (complete || admissionOnly && count != 0) return count;
 19114        count += VisitScaledHullSide(secondFrame, secondAnchorOrigin, secondPoints, secondEdges,
 19115            firstFrame, firstAnchorOrigin, firstPoints, firstTriangles, firstEdges, axis,
 19116            normal, depth, clamped, state, visitor, domain, admissionOnly, true, out _);
 117
 22118        if (count != 0) return count;
 16119        Signed832 firstSupport = GetScaledHullSupport(firstFrame, firstPoints, axis, true);
 16120        Signed832 secondSupport = GetScaledHullSupport(secondFrame, secondPoints, axis, false);
 121        const int parameterWords = 27;
 32122        Span<ulong> parameters = stackalloc ulong[8 * parameterWords]; Span<int> parameterSigns = stackalloc int[8];
 16123        var firstN = ContactQuadratic.At(parameters, parameterSigns, 0, parameterWords);
 16124        var firstD = ContactQuadratic.At(parameters, parameterSigns, 1, parameterWords);
 16125        var secondN = ContactQuadratic.At(parameters, parameterSigns, 2, parameterWords);
 16126        var secondD = ContactQuadratic.At(parameters, parameterSigns, 3, parameterWords);
 260127        for (int firstEdge = 0; firstEdge < firstEdges.Length; firstEdge += 2)
 128        {
 232129            int ia = firstEdges[firstEdge], ib = firstEdges[firstEdge + 1];
 232130            Vector3d a = firstPoints[ia], b = firstPoints[ib];
 116131            if (!IsScaledHullSupport(firstFrame.GetPoint(a), axis, firstSupport)
 116132                || !IsScaledHullSupport(firstFrame.GetPoint(b), axis, firstSupport)) continue;
 884133            for (int secondEdge = 0; secondEdge < secondEdges.Length; secondEdge += 2)
 134            {
 808135                int ic = secondEdges[secondEdge], id = secondEdges[secondEdge + 1];
 808136                Vector3d c = secondPoints[ic], d = secondPoints[id];
 404137                if (!IsScaledHullSupport(secondFrame.GetPoint(c), axis, secondSupport)
 404138                    || !IsScaledHullSupport(secondFrame.GetPoint(d), axis, secondSupport)) continue;
 272139                var firstSegment = new FixedSegment(a, b); var secondSegment = new FixedSegment(c, d);
 136140                if (!WideTriangleRelations.TryGetClosestNonparallelSegmentParameters(firstFrame.GetPoint(a), firstFrame.
 136141                        secondFrame.GetPoint(c), secondFrame.GetPoint(d), firstN, firstD, secondN, secondD)) continue;
 24142                if (domain != null && (!domain.ContainsPoint(true, ia, ib, firstN, firstD, axis)
 24143                    || !domain.ContainsPoint(false, ic, id, secondN, secondD, axis))) continue;
 5144                if (admissionOnly) return 1;
 3145                if (!WideTriangleRelations.TryGetSegmentPointAnchor(firstFrame, firstSegment, firstN, firstD,
 3146                        firstAnchorOrigin, out FixedPointAnchor firstAnchor)
 3147                    || !WideTriangleRelations.TryGetSegmentPointAnchor(secondFrame, secondSegment, secondN, secondD,
 3148                        secondAnchorOrigin, out FixedPointAnchor secondAnchor)) continue;
 1149                visitor(state, new FixedContactAnchors(firstAnchor, secondAnchor, normal, depth, clamped));
 1150                return 1;
 151            }
 152        }
 14153        return 0;
 154    }
 155
 156    /// <summary>Visits one selected hull support against a retained finite extrusion side.</summary>
 157    /// <remarks>
 158    /// A/B share local Y and A/C share local X/Z. The rectangle must lie on
 159    /// the second shape's selected support plane; the original full hull and
 160    /// full-solid penetration remain unchanged. Tangent cuts are never rounded.
 161    /// </remarks>
 162    internal static int VisitProjectedHullRectangleContacts<TSourceFrame, TRectangleFrame, TState>(
 163        in TSourceFrame sourceFrame, Vector3d sourceOrigin, ReadOnlySpan<Vector3d> sourcePoints,
 164        ReadOnlySpan<int> sourceTriangles, ReadOnlySpan<int> sourceEdges,
 165        in TRectangleFrame rectangleFrame, Vector3d rectangleOrigin, in FixedTriangle rectangleBasis,
 166        in RationalSegmentInterval tangentClip, in WideScaledHullPenetration penetration,
 167        TState state, Action<TState, FixedContactAnchors> visitor, bool admissionOnly = false)
 168        where TSourceFrame : struct, IForwardHullFrame3d
 169        where TRectangleFrame : struct, IForwardHullFrame3d
 170    {
 146171        WideDirection3d axis = penetration.Negate ? -penetration.Axis : penetration.Axis;
 146172        WideDirection3d faceNormal = rectangleFrame.GetFaceNormal(rectangleBasis);
 162173        if (faceNormal.IsZero || !WideDirection3d.AreParallel(axis, faceNormal)) return 0;
 130174        Signed832 support = GetScaledHullSupport(sourceFrame, sourcePoints, axis, true);
 130175        Vector3d normal = admissionOnly ? default : axis.GetNormal(false);
 130176        bool clamped = false;
 130177        Fixed64 depth = admissionOnly ? default : penetration.GetRoundedDepth(out clamped);
 178        const int words = 32;
 260179        Span<ulong> values = stackalloc ulong[10 * words]; Span<int> signs = stackalloc int[10];
 130180        var lowerN = ContactQuadratic.At(values, signs, 0, words);
 130181        var lowerD = ContactQuadratic.At(values, signs, 1, words);
 130182        var upperN = ContactQuadratic.At(values, signs, 2, words);
 130183        var upperD = ContactQuadratic.At(values, signs, 3, words);
 260184        var one = ContactQuadratic.At(values, signs, 4, words); one.Set(Signed576.ExtendValue(Signed192.Signed(1)));
 260185        int count = 0, supportVertices = 0;
 2198186        foreach (Vector3d vertex in sourcePoints)
 187        {
 974188            RationalPoint3d point = sourceFrame.GetPoint(vertex);
 974189            if (!IsScaledHullSupport(point, axis, support)) continue;
 494190            supportVertices++;
 494191            if (!WideTriangleRelations.TryGetProjectedRectangleInterval(rectangleBasis, rectangleFrame,
 494192                    point, point, tangentClip, lowerN, lowerD, upperN, upperD)) continue;
 60193            if (admissionOnly) return 1;
 40194            if (!point.TryGetLocalPointIn(sourceOrigin, FixedQuaternion.Identity, out Vector3d local)
 40195                || !WideTriangleRelations.TryGetProjectedPlanePointAnchor(rectangleBasis, rectangleFrame, point,
 40196                    rectangleOrigin, out FixedPointAnchor target)) continue;
 32197            visitor(state, new(new FixedPointAnchor(sourceOrigin, FixedQuaternion.Identity, local), target, normal, dept
 32198            count++;
 199        }
 126200        if (count != 0 && count == supportVertices) return count;
 2656201        for (int edge = 0; edge < sourceEdges.Length; edge += 2)
 202        {
 1228203            RationalPoint3d first = sourceFrame.GetPoint(sourcePoints[sourceEdges[edge]]),
 1228204                second = sourceFrame.GetPoint(sourcePoints[sourceEdges[edge + 1]]);
 1228205            if (!IsScaledHullSupport(first, axis, support) || !IsScaledHullSupport(second, axis, support)
 1228206                || !WideTriangleRelations.TryGetProjectedRectangleInterval(rectangleBasis, rectangleFrame,
 1228207                    first, second, tangentClip, lowerN, lowerD, upperN, upperD)) continue;
 72208            if (admissionOnly) return 1;
 264209            for (int endpoint = 0; endpoint < 2; endpoint++)
 210            {
 176211                var n = endpoint == 0 ? lowerN : upperN; var d = endpoint == 0 ? lowerD : upperD;
 88212                if (n.Signs[0] == 0 || ContactQuadratic.CompareRatios(n, d, ReadOnlySpan<ulong>.Empty,
 88213                        one, one, ReadOnlySpan<ulong>.Empty) == 0) continue;
 56214                if (!WideTriangleRelations.TryGetProjectedRectangleFaceAnchors(rectangleBasis, rectangleFrame,
 56215                        first, second, n, d, sourceOrigin, rectangleOrigin, out FixedPointAnchor source, out FixedPointA
 96216                visitor(state, new(source, target, normal, depth, clamped)); count++;
 217            }
 218        }
 219        // A small rectangle can lie wholly inside the projected hull face.
 220        // Its original horizontal edges supply exact rational cut corners.
 100221        Span<Vector3d> corners = stackalloc Vector3d[4]
 100222        {
 100223            rectangleBasis.A, rectangleBasis.B, rectangleBasis.C,
 100224            new(rectangleBasis.B.X, rectangleBasis.C.Y, rectangleBasis.B.Z)
 100225        };
 728226        for (int edge = 0; edge < 4; edge++)
 227        {
 298228            bool horizontal = edge < 2;
 298229            if (!horizontal && tangentClip.IsClipped)
 230            {
 80231                Signed832 endpoint = edge == 2 ? default : Signed832.ExtendValue(Signed192.Signed(1));
 80232                Signed832 divisor = Signed832.ExtendValue(Signed192.Signed(1));
 80233                if (RationalSegmentInterval.CompareParameters(endpoint, divisor,
 80234                        tangentClip.WideLowerNumerator, tangentClip.WideLowerDenominator) < 0
 80235                    || RationalSegmentInterval.CompareParameters(endpoint, divisor,
 80236                        tangentClip.WideUpperNumerator, tangentClip.WideUpperDenominator) > 0) continue;
 237            }
 500238            int a = edge < 2 ? 2 * edge : edge - 2, b = edge < 2 ? 2 * edge + 1 : edge;
 500239            RationalPoint3d first = rectangleFrame.GetPoint(corners[a]), second = rectangleFrame.GetPoint(corners[b]);
 5692240            for (int triangle = 0; triangle < sourceTriangles.Length; triangle += 3)
 241            {
 7890242                int ia = sourceTriangles[triangle], ib = sourceTriangles[triangle + 1], ic = sourceTriangles[triangle + 
 7890243                Vector3d x = sourcePoints[ia], y = sourcePoints[ib], z = sourcePoints[ic];
 2630244                if (!IsScaledHullSupport(sourceFrame.GetPoint(x), axis, support)
 2630245                    || !IsScaledHullSupport(sourceFrame.GetPoint(y), axis, support)
 2630246                    || !IsScaledHullSupport(sourceFrame.GetPoint(z), axis, support)) continue;
 470247                var face = new FixedTriangle(x, y, z);
 470248                if (!WideTriangleRelations.TryGetProjectedSegmentInterval(face, sourceFrame, first, second,
 470249                        out Signed832 ln, out Signed832 ld, out Signed832 un, out Signed832 ud)
 470250                    || horizontal && !IntersectScaledHullInterval(tangentClip, ref ln, ref ld, ref un, ref ud)) continue
 288251                if (admissionOnly) return 1;
 220252                int mask = (HasScaledHullEdge(ib, ic, sourceEdges) ? 1 : 0)
 220253                    | (HasScaledHullEdge(ic, ia, sourceEdges) ? 2 : 0) | (HasScaledHullEdge(ia, ib, sourceEdges) ? 4 : 0
 1320254                for (int endpoint = 0; endpoint < 2; endpoint++)
 255                {
 880256                    Signed832 n = endpoint == 0 ? ln : un, d = endpoint == 0 ? ld : ud;
 440257                    bool corner = n.IsZero || WideArithmetic.SubtractSigned832(d, n).IsZero
 440258                        || horizontal && tangentClip.IsClipped && (RationalSegmentInterval.CompareParameters(n, d,
 440259                            tangentClip.WideLowerNumerator, tangentClip.WideLowerDenominator) == 0
 440260                            || RationalSegmentInterval.CompareParameters(n, d, tangentClip.WideUpperNumerator,
 440261                                tangentClip.WideUpperDenominator) == 0);
 440262                    if (!WideTriangleRelations.TryGetProjectedFrameSegmentFaceAnchors(face, sourceFrame, first, second, 
 440263                            rectangleOrigin, sourceOrigin, mask, out FixedPointAnchor target, out FixedPointAnchor sourc
 440264                            requirePhysicalTargetBoundary: !corner)) continue;
 608265                    visitor(state, new(source, target, normal, depth, clamped)); count++;
 266                }
 267            }
 268        }
 66269        return count;
 270    }
 271
 272    private static int VisitScaledHullSide<TSourceFrame, TTargetFrame, TState>(
 273        in TSourceFrame sourceFrame, Vector3d sourceOrigin, ReadOnlySpan<Vector3d> sourcePoints, ReadOnlySpan<int> sourc
 274        in TTargetFrame targetFrame, Vector3d targetOrigin, ReadOnlySpan<Vector3d> targetPoints,
 275        ReadOnlySpan<int> targetTriangles, ReadOnlySpan<int> targetEdges, in WideDirection3d axis,
 276        Vector3d normal, Fixed64 depth, bool clamped, TState state, Action<TState, FixedContactAnchors> visitor,
 277        IScaledConvexHullContactDomain? domain, bool admissionOnly, bool reverse, out bool allVerticesAdmitted)
 278        where TSourceFrame : struct, IForwardHullFrame3d
 279        where TTargetFrame : struct, IForwardHullFrame3d
 280    {
 44281        allVerticesAdmitted = false;
 44282        int count = 0;
 44283        Signed832 sourceSupport = GetScaledHullSupport(sourceFrame, sourcePoints, axis, !reverse);
 44284        Signed832 targetSupport = GetScaledHullSupport(targetFrame, targetPoints, axis, reverse);
 88285        int supportVertices = 0, admittedVertices = 0;
 618286        for (int vertex = 0; vertex < sourcePoints.Length; vertex++)
 287        {
 266288            RationalPoint3d point = sourceFrame.GetPoint(sourcePoints[vertex]);
 266289            if (!IsScaledHullSupport(point, axis, sourceSupport)) continue;
 141290            supportVertices++;
 2606291            for (int triangle = 0; triangle < targetTriangles.Length; triangle += 3)
 292            {
 2406293                Vector3d a = targetPoints[targetTriangles[triangle]], b = targetPoints[targetTriangles[triangle + 1]],
 1203294                    c = targetPoints[targetTriangles[triangle + 2]];
 1203295                if (!IsScaledHullSupport(targetFrame.GetPoint(a), axis, targetSupport)
 1203296                    || !IsScaledHullSupport(targetFrame.GetPoint(b), axis, targetSupport)
 1203297                    || !IsScaledHullSupport(targetFrame.GetPoint(c), axis, targetSupport)) continue;
 187298                var face = new FixedTriangle(a, b, c);
 187299                if (!WideTriangleRelations.ContainsProjection(face, targetFrame, point)) continue;
 41300                if (domain != null && !domain.ContainsPoint(!reverse, vertex, vertex, default,
 41301                        Signed832.ExtendValue(Signed192.One), axis)) break;
 22302                if (admissionOnly) return 1;
 20303                if (!point.TryGetLocalPointIn(sourceOrigin, FixedQuaternion.Identity, out Vector3d local)
 20304                    || !WideTriangleRelations.TryGetProjectedPointAnchor(face, targetFrame, point, targetOrigin,
 20305                        out FixedPointAnchor target)) continue;
 20306                var source = new FixedPointAnchor(sourceOrigin, FixedQuaternion.Identity, local);
 20307                visitor(state, reverse ? new FixedContactAnchors(target, source, normal, depth, clamped)
 20308                    : new FixedContactAnchors(source, target, normal, depth, clamped));
 40309                count++; admittedVertices++;
 20310                break;
 311            }
 312        }
 43313        if (!reverse && supportVertices != 0 && supportVertices == admittedVertices)
 8314        { allVerticesAdmitted = true; return count; }
 704315        for (int edge = 0; edge < sourceEdges.Length; edge += 2)
 316        {
 628317            int first = sourceEdges[edge], second = sourceEdges[edge + 1];
 628318            RationalPoint3d start = sourceFrame.GetPoint(sourcePoints[first]), end = sourceFrame.GetPoint(sourcePoints[s
 314319            if (!IsScaledHullSupport(start, axis, sourceSupport) || !IsScaledHullSupport(end, axis, sourceSupport)) cont
 105320            ReadOnlySpan<RationalSegmentInterval> intervals = domain == null ? default : domain.GetEdgeIntervals(!revers
 105321            if (domain != null && intervals.IsEmpty) continue;
 1538322            for (int triangle = 0; triangle < targetTriangles.Length; triangle += 3)
 323            {
 2091324                int ia = targetTriangles[triangle], ib = targetTriangles[triangle + 1], ic = targetTriangles[triangle + 
 2091325                Vector3d a = targetPoints[ia], b = targetPoints[ib], c = targetPoints[ic];
 697326                if (!IsScaledHullSupport(targetFrame.GetPoint(a), axis, targetSupport)
 697327                    || !IsScaledHullSupport(targetFrame.GetPoint(b), axis, targetSupport)
 697328                    || !IsScaledHullSupport(targetFrame.GetPoint(c), axis, targetSupport)) continue;
 113329                var face = new FixedTriangle(a, b, c);
 113330                if (!WideTriangleRelations.TryGetProjectedSegmentInterval(face, targetFrame, start, end,
 113331                        out Signed832 lowerN, out Signed832 lowerD, out Signed832 upperN, out Signed832 upperD)) continu
 57332                int mask = (HasScaledHullEdge(ib, ic, targetEdges) ? 1 : 0)
 57333                    | (HasScaledHullEdge(ic, ia, targetEdges) ? 2 : 0) | (HasScaledHullEdge(ia, ib, targetEdges) ? 4 : 0
 226334                for (int clipIndex = 0; clipIndex < (domain == null ? 1 : intervals.Length); clipIndex++)
 335                {
 57336                    RationalSegmentInterval clip = domain == null ? default : intervals[clipIndex];
 228337                    Signed832 ln = lowerN, ld = lowerD, un = upperN, ud = upperD;
 57338                    if (!IntersectScaledHullInterval(clip, ref ln, ref ld, ref un, ref ud)) continue;
 314339                    for (int endpoint = 0; endpoint < 2; endpoint++)
 340                    {
 210341                        Signed832 n = endpoint == 0 ? ln : un, d = endpoint == 0 ? ld : ud;
 105342                        if (n.IsZero || WideArithmetic.SubtractSigned832(d, n).IsZero
 105343                            || domain != null && !domain.ContainsPoint(!reverse, first, second, n, d, axis)) continue;
 25344                        bool clipEnd = clip.IsClipped && (RationalSegmentInterval.CompareParameters(n, d,
 25345                            clip.WideLowerNumerator, clip.WideLowerDenominator) == 0
 25346                            || RationalSegmentInterval.CompareParameters(n, d, clip.WideUpperNumerator, clip.WideUpperDe
 25347                        if (!WideTriangleRelations.TryGetProjectedFrameSegmentFaceAnchors(face, targetFrame, start, end,
 25348                                sourceOrigin, targetOrigin, mask, out FixedPointAnchor source, out FixedPointAnchor targ
 25349                                requirePhysicalTargetBoundary: !clipEnd, materialize: !admissionOnly)) continue;
 18350                        if (admissionOnly) return 1;
 16351                        visitor(state, reverse ? new FixedContactAnchors(target, source, normal, depth, clamped)
 16352                            : new FixedContactAnchors(source, target, normal, depth, clamped));
 16353                        count++;
 354                    }
 355                }
 356            }
 357        }
 38358            return count;
 359    }
 360
 361    private static bool HasScaledHullEdge(int first, int second, ReadOnlySpan<int> edges)
 362    {
 11220363        for (int edge = 0; edge < edges.Length; edge += 2)
 5887364            if (edges[edge] == first && edges[edge + 1] == second || edges[edge] == second && edges[edge + 1] == first) 
 277365        return false;
 366    }
 367
 368    internal static Signed832 GetScaledHullSupport<TFrame>(in TFrame frame, ReadOnlySpan<Vector3d> points,
 369        in WideDirection3d axis, bool maximize) where TFrame : struct, IForwardHullFrame3d
 370    {
 258371        Signed832 best = ProjectScaledHullPoint(frame.GetPoint(points[0]), axis, Signed192.One);
 3648372        for (int vertex = 1; vertex < points.Length; vertex++)
 373        {
 1566374            Signed832 candidate = ProjectScaledHullPoint(frame.GetPoint(points[vertex]), axis, Signed192.One);
 1566375            int comparison = WideArithmetic.SubtractSigned832(candidate, best).Sign;
 1606376            if (maximize ? comparison > 0 : comparison < 0) best = candidate;
 377        }
 258378        return best;
 379    }
 380
 381    internal static bool IsScaledHullSupport(in RationalPoint3d point, in WideDirection3d axis, Signed832 support) =>
 13665382        WideArithmetic.SubtractSigned832(ProjectScaledHullPoint(point, axis, Signed192.One), support).IsZero;
 383
 384    private static bool IntersectScaledHullInterval(in RationalSegmentInterval interval,
 385        ref Signed832 ln, ref Signed832 ld, ref Signed832 un, ref Signed832 ud)
 386    {
 442387        if (!interval.IsClipped) return true;
 148388        if (RationalSegmentInterval.CompareParameters(interval.WideLowerNumerator, interval.WideLowerDenominator, ln, ld
 148389        { ln = interval.WideLowerNumerator; ld = interval.WideLowerDenominator; }
 148390        if (RationalSegmentInterval.CompareParameters(interval.WideUpperNumerator, interval.WideUpperDenominator, un, ud
 140391        { un = interval.WideUpperNumerator; ud = interval.WideUpperDenominator; }
 148392        return RationalSegmentInterval.CompareParameters(ln, ld, un, ud) <= 0;
 393    }
 394
 395    /// <summary>
 396    /// Tests convex authored point spans whose centered exact scaled reach is at
 397    /// most 4096. The existing rigid ingress remains the scalar fast path.
 398    /// </summary>
 399    internal static bool TryGetConvexHullPenetration(
 400        in ScaledRigidFrame3d firstFrame, ReadOnlySpan<Vector3d> firstPoints,
 401        ReadOnlySpan<int> firstTriangles, ReadOnlySpan<int> firstEdges,
 402        in ScaledRigidFrame3d secondFrame, ReadOnlySpan<Vector3d> secondPoints,
 403        ReadOnlySpan<int> secondTriangles, ReadOnlySpan<int> secondEdges,
 404        out WideScaledHullPenetration best, bool skipParallelDirections = false,
 405        ScaledHullPenetrationAdmission? admission = null, bool planarPair = false)
 406 =>
 26407        TryGetConvexHullPenetration<ScaledRigidFrame3d, ScaledRigidFrame3d>(firstFrame, firstPoints, firstTriangles, fir
 26408            secondFrame, secondPoints, secondTriangles, secondEdges, out best, skipParallelDirections, admission, planar
 409
 410    internal static bool TryGetConvexHullPenetration<TFirstFrame, TSecondFrame>(
 411        in TFirstFrame firstFrame, ReadOnlySpan<Vector3d> firstPoints,
 412        ReadOnlySpan<int> firstTriangles, ReadOnlySpan<int> firstEdges,
 413        in TSecondFrame secondFrame, ReadOnlySpan<Vector3d> secondPoints,
 414        ReadOnlySpan<int> secondTriangles, ReadOnlySpan<int> secondEdges,
 415        out WideScaledHullPenetration best, bool skipParallelDirections = false,
 416        ScaledHullPenetrationAdmission? admission = null, bool planarPair = false)
 417        where TFirstFrame : struct, IForwardHullFrame3d
 418        where TSecondFrame : struct, IForwardHullFrame3d
 419    {
 83420        best = default;
 83421        bool hasAxis = false;
 83422        Signed576 commonD = WideArithmetic.MultiplySigned320(firstFrame.Denominator, secondFrame.RotationDenominator);
 83423        if (!TryKeepScaledHullFaceAxes(firstFrame, firstPoints, firstTriangles, firstEdges,
 83424                firstFrame, firstPoints, secondFrame, secondPoints, commonD, ref best, ref hasAxis,
 83425                skipParallelDirections, admission, planarPair)
 83426            || !TryKeepScaledHullFaceAxes(secondFrame, secondPoints, secondTriangles, secondEdges,
 83427                firstFrame, firstPoints, secondFrame, secondPoints, commonD, ref best, ref hasAxis,
 89428                skipParallelDirections, admission, planarPair)) return false;
 1842429        for (int firstEdge = 0; firstEdge < firstEdges.Length; firstEdge += 2)
 430        {
 845431            if (skipParallelDirections && !IsFirstHullEdgeDirection(firstPoints, firstEdges, firstEdge)) continue;
 774432            WideDirection3d a = firstFrame.GetEdgeDirection(firstPoints[firstEdges[firstEdge]], firstPoints[firstEdges[f
 19760433            for (int secondEdge = 0; secondEdge < secondEdges.Length; secondEdge += 2)
 434            {
 9107435                if (skipParallelDirections && !IsFirstHullEdgeDirection(secondPoints, secondEdges, secondEdge)) continue
 8902436                WideDirection3d b = secondFrame.GetEdgeDirection(secondPoints[secondEdges[secondEdge]], secondPoints[sec
 8902437                if (!TryKeepScaledHullAxis(WideDirection3d.Cross(a, b), firstFrame, firstPoints,
 8902438                        secondFrame, secondPoints, commonD, ref best, ref hasAxis, admission))
 2439                { best = default; return false; }
 440            }
 441        }
 76442        return admission == null ? best.HasValue : hasAxis;
 443    }
 444
 445    private static bool TryKeepScaledHullFaceAxes<TFrame, TFirstFrame, TSecondFrame>(
 446        in TFrame frame, ReadOnlySpan<Vector3d> points, ReadOnlySpan<int> triangles, ReadOnlySpan<int> edges,
 447        in TFirstFrame firstFrame, ReadOnlySpan<Vector3d> firstPoints,
 448        in TSecondFrame secondFrame, ReadOnlySpan<Vector3d> secondPoints, Signed576 commonD,
 449        ref WideScaledHullPenetration best, ref bool hasAxis, bool skipParallelDirections,
 450        ScaledHullPenetrationAdmission? admission, bool planarPair)
 451        where TFrame : struct, IForwardHullFrame3d
 452        where TFirstFrame : struct, IForwardHullFrame3d
 453        where TSecondFrame : struct, IForwardHullFrame3d
 454    {
 160455        FixedTriangle plane = default;
 3702456        for (int triangle = 0; triangle < triangles.Length; triangle += 3)
 457        {
 1696458            var face = new FixedTriangle(points[triangles[triangle]], points[triangles[triangle + 1]], points[triangles[
 1696459            WideDirection3d normal = frame.GetFaceNormal(face);
 1696460            if (normal.IsZero) continue;
 1672461            bool duplicate = false;
 462            // Exact world face normals remain below 284 bits, so the
 463            // parallel cross stays within Signed576 for both frame charts.
 4784464            for (int previous = 0; skipParallelDirections && previous < triangle; previous += 3)
 866465                if (WideDirection3d.Cross(normal, frame.GetFaceNormal(new(points[triangles[previous]],
 866466                        points[triangles[previous + 1]], points[triangles[previous + 2]]))).IsZero)
 292467                { duplicate = true; break; }
 1672468            if (duplicate) continue;
 1526469            plane = face;
 1526470            if (!TryKeepScaledHullAxis(normal, firstFrame, firstPoints, secondFrame, secondPoints,
 1536471                    commonD, ref best, ref hasAxis, admission)) { best = default; return false; }
 472        }
 155473        if (planarPair)
 132474            for (int edge = 0; edge < edges.Length; edge += 2)
 475            {
 52476                if (skipParallelDirections && !IsFirstHullEdgeDirection(points, edges, edge)) continue;
 36477                WideDirection3d axis = frame.GetInwardAxis(plane, points[edges[edge]], points[edges[edge + 1]]);
 36478                if (!TryKeepScaledHullAxis(axis, firstFrame, firstPoints, secondFrame, secondPoints,
 38479                        commonD, ref best, ref hasAxis, admission)) { best = default; return false; }
 480            }
 154481        return true;
 482    }
 483
 484    private static bool TryKeepScaledHullAxis<TFirstFrame, TSecondFrame>(in WideDirection3d axis,
 485        in TFirstFrame firstFrame, ReadOnlySpan<Vector3d> firstPoints,
 486        in TSecondFrame secondFrame, ReadOnlySpan<Vector3d> secondPoints, Signed576 commonD,
 487        ref WideScaledHullPenetration best, ref bool hasAxis, ScaledHullPenetrationAdmission? admission)
 488        where TFirstFrame : struct, IForwardHullFrame3d
 489        where TSecondFrame : struct, IForwardHullFrame3d
 490    {
 13416491        if (axis.IsZero) return true;
 7512492        hasAxis = true;
 7512493        GetScaledHullProjection(firstFrame, firstPoints, axis, secondFrame.RotationDenominator,
 7512494            out Signed832 firstMin, out Signed832 firstMax);
 7512495        GetScaledHullProjection(secondFrame, secondPoints, axis, firstFrame.RotationDenominator,
 7512496            out Signed832 secondMin, out Signed832 secondMax);
 7512497        Signed832 negative = WideArithmetic.SubtractSigned832(firstMax, secondMin);
 7512498        Signed832 positive = WideArithmetic.SubtractSigned832(secondMax, firstMin);
 7519499        if (negative.Sign < 0 || positive.Sign < 0) return false;
 7505500        Signed832 squared = axis.SquaredLength;
 7505501        bool negate = WideArithmetic.SubtractSigned832(positive, negative).Sign < 0;
 7505502        Keep(negate ? positive : negative, negate, axis, squared, commonD, ref best, admission);
 7539503        if (admission != null) Keep(negate ? negative : positive, !negate, axis, squared, commonD, ref best, admission);
 7505504        return true;
 505
 506        static void Keep(Signed832 overlap, bool negate, in WideDirection3d direction, Signed832 squared,
 507            Signed576 denominator, ref WideScaledHullPenetration best, ScaledHullPenetrationAdmission? admission)
 508        {
 509            if (!best.ShouldReplace(overlap, squared, denominator)) return;
 510            var candidate = new WideScaledHullPenetration(direction, negate, overlap, squared, denominator);
 511            if (admission == null || admission(candidate)) best = candidate;
 512        }
 513    }
 514
 515    private static void GetScaledHullProjection<TFrame>(in TFrame frame, ReadOnlySpan<Vector3d> points,
 516        in WideDirection3d axis, Signed192 otherRotationDenominator, out Signed832 minimum, out Signed832 maximum)
 517        where TFrame : struct, IForwardHullFrame3d
 518    {
 15024519        minimum = maximum = ProjectScaledHullPoint(frame.GetPoint(points[0]), axis, otherRotationDenominator);
 238476520        for (int index = 1; index < points.Length; index++)
 521        {
 104214522            Signed832 projection = ProjectScaledHullPoint(frame.GetPoint(points[index]), axis, otherRotationDenominator)
 112260523            if (WideArithmetic.SubtractSigned832(projection, minimum).Sign < 0) minimum = projection;
 112075524            if (WideArithmetic.SubtractSigned832(projection, maximum).Sign > 0) maximum = projection;
 525        }
 15024526    }
 527
 528    internal static Signed832 ProjectScaledHullPoint(in RationalPoint3d point, in WideDirection3d axis,
 134727529        Signed192 otherRotationDenominator) => WideArithmetic.AddSigned832(WideArithmetic.AddSigned832(
 134727530            WideArithmetic.MultiplySigned576ToSigned832(axis.X, WideArithmetic.MultiplySigned320(point.X, otherRotationD
 134727531            WideArithmetic.MultiplySigned576ToSigned832(axis.Y, WideArithmetic.MultiplySigned320(point.Y, otherRotationD
 134727532            WideArithmetic.MultiplySigned576ToSigned832(axis.Z, WideArithmetic.MultiplySigned320(point.Z, otherRotationD
 533}

/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 DoesSpherePenetrate(
 17        Vector3d center, FixedQuaternion orientation, Vector3d halfExtents,
 18        Vector3d sphereCenter, Fixed64 sphereRadius)
 19    {
 19420        WideRationalBasis3d basis = new(orientation);
 19421        GetPointProjections(sphereCenter, center, basis,
 19422            out Signed320 x, out Signed320 y, out Signed320 z);
 19423        Signed320 gapX = WideArithmetic.SubtractSigned320(
 19424            GetMagnitude(x), GetExtentNumerator(halfExtents.X, basis.Denominator));
 19425        Signed320 gapY = WideArithmetic.SubtractSigned320(
 19426            GetMagnitude(y), GetExtentNumerator(halfExtents.Y, basis.Denominator));
 19427        Signed320 gapZ = WideArithmetic.SubtractSigned320(
 19428            GetMagnitude(z), GetExtentNumerator(halfExtents.Z, basis.Denominator));
 19429        if (sphereRadius == Fixed64.Zero)
 4630            return gapX.Sign < 0 && gapY.Sign < 0 && gapZ.Sign < 0;
 31
 22032        if (gapX.Sign < 0) gapX = default;
 21833        if (gapY.Sign < 0) gapY = default;
 23634        if (gapZ.Sign < 0) gapZ = default;
 35        // The rational quaternion basis is orthogonal with common scale D.
 36        // Compare squared local distance against (radius * D)^2, without
 37        // materializing a world witness, normal, square root or rounded depth.
 38        // A raw coordinate difference times D uses fewer than 134 bits;
 39        // its squared sum fits Signed576 throughout the Fixed64 domain.
 14840        Signed576 distanceSquared = WideArithmetic.AddSigned576(
 14841            WideArithmetic.AddSigned576(
 14842                WideArithmetic.MultiplySigned320(gapX, gapX),
 14843                WideArithmetic.MultiplySigned320(gapY, gapY)),
 14844            WideArithmetic.MultiplySigned320(gapZ, gapZ));
 14845        Signed320 radius = GetExtentNumerator(sphereRadius, basis.Denominator);
 14846        return WideArithmetic.SubtractSigned576(
 14847            distanceSquared, WideArithmetic.MultiplySigned320(radius, radius)).Sign < 0;
 48    }
 49
 50    internal static bool TryGetSweptSphereIntersectionDistance(
 51        Vector3d center,
 52        FixedQuaternion orientation,
 53        Vector3d halfExtents,
 54        FixedSegment query,
 55        Fixed64 sphericalExpansion,
 56        Fixed64 segmentLength,
 57        out Fixed64 distance)
 58    {
 4759        WideRationalBasis3d basis = new(orientation);
 4760        GetPointProjections(
 4761            query.Start,
 4762            center,
 4763            basis,
 4764            out Signed320 startX,
 4765            out Signed320 startY,
 4766            out Signed320 startZ);
 4767        GetPointProjections(
 4768            query.End,
 4769            center,
 4770            basis,
 4771            out Signed320 endX,
 4772            out Signed320 endY,
 4773            out Signed320 endZ);
 4774        Signed192 narrowStartX = Signed192.NarrowValue(startX);
 4775        Signed192 narrowStartY = Signed192.NarrowValue(startY);
 4776        Signed192 narrowStartZ = Signed192.NarrowValue(startZ);
 4777        Signed192 narrowEndX = Signed192.NarrowValue(endX);
 4778        Signed192 narrowEndY = Signed192.NarrowValue(endY);
 4779        Signed192 narrowEndZ = Signed192.NarrowValue(endZ);
 4780        Signed192 extentX = Signed192.NarrowValue(
 4781            GetExtentNumerator(halfExtents.X, basis.Denominator));
 4782        Signed192 extentY = Signed192.NarrowValue(
 4783            GetExtentNumerator(halfExtents.Y, basis.Denominator));
 4784        Signed192 extentZ = Signed192.NarrowValue(
 4785            GetExtentNumerator(halfExtents.Z, basis.Denominator));
 86
 4787        return Geometry.WideFiniteAxisIntersection
 4788            .TryGetSphericallyExpandedProjectedBoxFirstDistance(
 4789                narrowStartX,
 4790                narrowStartY,
 4791                narrowStartZ,
 4792                narrowEndX,
 4793                narrowEndY,
 4794                narrowEndZ,
 4795                extentX,
 4796                extentY,
 4797                extentZ,
 4798                basis.Denominator,
 4799                sphericalExpansion,
 47100                segmentLength,
 47101                out distance);
 102    }
 103
 104    internal static bool TryGetSphereContact(
 105        Vector3d center,
 106        FixedQuaternion orientation,
 107        Vector3d halfExtents,
 108        Vector3d sphereCenter,
 109        FixedQuaternion sphereRotation,
 110        Fixed64 sphereRadius,
 111        out FixedContactAnchors contact)
 112    {
 19113        WideRationalBasis3d basis = new(orientation);
 19114        GetPointProjections(
 19115            sphereCenter,
 19116            center,
 19117            basis,
 19118            out Signed320 localX,
 19119            out Signed320 localY,
 19120            out Signed320 localZ);
 19121        Signed320 xExtent = GetExtentNumerator(halfExtents.X, basis.Denominator);
 19122        Signed320 yExtent = GetExtentNumerator(halfExtents.Y, basis.Denominator);
 19123        Signed320 zExtent = GetExtentNumerator(halfExtents.Z, basis.Denominator);
 19124        bool outsideX = WideArithmetic.CompareMagnitude(localX, xExtent) > 0;
 19125        bool outsideY = WideArithmetic.CompareMagnitude(localY, yExtent) > 0;
 19126        bool outsideZ = WideArithmetic.CompareMagnitude(localZ, zExtent) > 0;
 127
 19128        Signed320 boxLocalX = GetClampedNumerator(localX, xExtent, outsideX);
 19129        Signed320 boxLocalY = GetClampedNumerator(localY, yExtent, outsideY);
 19130        Signed320 boxLocalZ = GetClampedNumerator(localZ, zExtent, outsideZ);
 19131        if (!(outsideX || outsideY || outsideZ))
 132        {
 11133            return TryGetContainedSphereContact(
 11134                center,
 11135                orientation,
 11136                basis,
 11137                sphereCenter,
 11138                sphereRotation,
 11139                sphereRadius,
 11140                localX,
 11141                localY,
 11142                localZ,
 11143                xExtent,
 11144                yExtent,
 11145                zExtent,
 11146                boxLocalX,
 11147                boxLocalY,
 11148                boxLocalZ,
 11149                out contact);
 150        }
 151
 8152        Signed320 denominatorSquared = WideArithmetic.MultiplySigned192(
 8153            basis.Denominator,
 8154            basis.Denominator);
 8155        GetRationalLocalOffsetNumerators(
 8156            basis,
 8157            boxLocalX,
 8158            boxLocalY,
 8159            boxLocalZ,
 8160            out Signed576 boxOffsetX,
 8161            out Signed576 boxOffsetY,
 8162            out Signed576 boxOffsetZ);
 8163        Signed576 deltaX = GetOriginRelativeNumerator(
 8164            sphereCenter.X,
 8165            center.X,
 8166            denominatorSquared,
 8167            boxOffsetX);
 8168        Signed576 deltaY = GetOriginRelativeNumerator(
 8169            sphereCenter.Y,
 8170            center.Y,
 8171            denominatorSquared,
 8172            boxOffsetY);
 8173        Signed576 deltaZ = GetOriginRelativeNumerator(
 8174            sphereCenter.Z,
 8175            center.Z,
 8176            denominatorSquared,
 8177            boxOffsetZ);
 8178        Signed832 squaredDistance = SumSquares(deltaX, deltaY, deltaZ);
 8179        Signed576 scaledRadius = WideArithmetic.MultiplySigned320(
 8180            Signed320.ExtendValue(Signed192.Raw(sphereRadius)),
 8181            denominatorSquared);
 8182        Signed832 squaredRadius = WideArithmetic.MultiplySigned576ToSigned832(
 8183            scaledRadius,
 8184            scaledRadius);
 8185        if (WideArithmetic.SubtractSigned832(squaredDistance, squaredRadius).Sign > 0)
 186        {
 1187            contact = default;
 1188            return false;
 189        }
 190
 7191        Vector3d normal = WideNormalization.GetNormalized(deltaX, deltaY, deltaZ);
 7192        Vector3d boxLocalPoint = GetRationalLocalPoint(
 7193            basis,
 7194            boxLocalX,
 7195            boxLocalY,
 7196            boxLocalZ);
 7197        FixedPointAnchor sphereAnchor = GetSphereSurfaceAnchor(
 7198            sphereCenter,
 7199            sphereRotation,
 7200            sphereRadius,
 7201            deltaX,
 7202            deltaY,
 7203            deltaZ,
 7204            true);
 7205        Fixed64 depth = GetRoundedRadialDepth(
 7206            sphereRadius,
 7207            squaredDistance,
 7208            denominatorSquared);
 7209        contact = new FixedContactAnchors(
 7210            new FixedPointAnchor(
 7211                center,
 7212                orientation,
 7213                boxLocalPoint),
 7214            sphereAnchor,
 7215            normal,
 7216            depth,
 7217            false);
 7218        return true;
 219    }
 220
 221    private static bool TryGetContainedSphereContact(
 222        Vector3d center,
 223        FixedQuaternion orientation,
 224        WideRationalBasis3d basis,
 225        Vector3d sphereCenter,
 226        FixedQuaternion sphereRotation,
 227        Fixed64 sphereRadius,
 228        Signed320 localX,
 229        Signed320 localY,
 230        Signed320 localZ,
 231        Signed320 xExtent,
 232        Signed320 yExtent,
 233        Signed320 zExtent,
 234        Signed320 boxLocalX,
 235        Signed320 boxLocalY,
 236        Signed320 boxLocalZ,
 237        out FixedContactAnchors contact)
 238    {
 11239        Signed320 xClearance = WideArithmetic.SubtractSigned320(
 11240            xExtent,
 11241            GetMagnitude(localX));
 11242        Signed320 yClearance = WideArithmetic.SubtractSigned320(
 11243            yExtent,
 11244            GetMagnitude(localY));
 11245        Signed320 zClearance = WideArithmetic.SubtractSigned320(
 11246            zExtent,
 11247            GetMagnitude(localZ));
 248        int axis;
 249        bool negative;
 11250        if (WideArithmetic.CompareMagnitude(xClearance, yClearance) <= 0
 11251            && WideArithmetic.CompareMagnitude(xClearance, zClearance) <= 0)
 252        {
 7253            axis = 0;
 7254            negative = localX.Sign < 0;
 7255            boxLocalX = negative
 7256                ? WideArithmetic.SubtractSigned320(default, xExtent)
 7257                : xExtent;
 258        }
 4259        else if (WideArithmetic.CompareMagnitude(yClearance, zClearance) <= 0)
 260        {
 2261            axis = 1;
 2262            negative = localY.Sign < 0;
 2263            boxLocalY = negative
 2264                ? WideArithmetic.SubtractSigned320(default, yExtent)
 2265                : yExtent;
 266        }
 267        else
 268        {
 2269            axis = 2;
 2270            negative = localZ.Sign < 0;
 2271            boxLocalZ = negative
 2272                ? WideArithmetic.SubtractSigned320(default, zExtent)
 2273                : zExtent;
 274        }
 275
 11276        Vector3d boxLocalPoint = GetRationalLocalPoint(
 11277            basis,
 11278            boxLocalX,
 11279            boxLocalY,
 11280            boxLocalZ);
 281
 11282        Vector3d normal = axis switch
 11283        {
 7284            0 => GetAxis(
 7285                basis.Xx,
 7286                basis.Xy,
 7287                basis.Xz,
 7288                basis.Denominator,
 7289                negative),
 2290            1 => GetAxis(
 2291                basis.Yx,
 2292                basis.Yy,
 2293                basis.Yz,
 2294                basis.Denominator,
 2295                negative),
 2296            _ => GetAxis(
 2297                basis.Zx,
 2298                basis.Zy,
 2299                basis.Zz,
 2300                basis.Denominator,
 2301                negative),
 11302        };
 11303        FixedPointAnchor sphereAnchor = axis switch
 11304        {
 7305            0 => GetSphereSurfaceAnchor(
 7306                sphereCenter,
 7307                sphereRotation,
 7308                sphereRadius,
 7309                ToSigned576(basis.Xx),
 7310                ToSigned576(basis.Xy),
 7311                ToSigned576(basis.Xz),
 7312                !negative),
 2313            1 => GetSphereSurfaceAnchor(
 2314                sphereCenter,
 2315                sphereRotation,
 2316                sphereRadius,
 2317                ToSigned576(basis.Yx),
 2318                ToSigned576(basis.Yy),
 2319                ToSigned576(basis.Yz),
 2320                !negative),
 2321            _ => GetSphereSurfaceAnchor(
 2322                sphereCenter,
 2323                sphereRotation,
 2324                sphereRadius,
 2325                ToSigned576(basis.Zx),
 2326                ToSigned576(basis.Zy),
 2327                ToSigned576(basis.Zz),
 2328                !negative),
 11329        };
 11330        Signed320 clearance = axis switch
 11331        {
 7332            0 => xClearance,
 2333            1 => yClearance,
 2334            _ => zClearance,
 11335        };
 11336        Signed320 depthNumerator = WideArithmetic.AddSigned320(
 11337            WideArithmetic.MultiplySigned192(
 11338                Signed192.Raw(sphereRadius),
 11339                basis.Denominator),
 11340            clearance);
 11341        Signed320 maximumNumerator = WideArithmetic.MultiplySigned192(
 11342            Signed192.Raw(Fixed64.MaxValue),
 11343            basis.Denominator);
 11344        bool depthIsClamped = CompareSigned(
 11345            depthNumerator,
 11346            maximumNumerator) > 0;
 347        Fixed64 depth;
 11348        if (depthIsClamped)
 349        {
 1350            depth = Fixed64.MaxValue;
 351        }
 352        else
 353        {
 10354            _ = Fixed64.TryGetSignedRawRatio(
 10355                Signed576.ExtendValue(depthNumerator),
 10356                ToSigned576(basis.Denominator),
 10357                out depth);
 358        }
 359
 11360        contact = new FixedContactAnchors(
 11361            new FixedPointAnchor(
 11362                center,
 11363                orientation,
 11364                boxLocalPoint),
 11365            sphereAnchor,
 11366            normal,
 11367            depth,
 11368            depthIsClamped);
 11369        return true;
 370    }
 371
 372    private static FixedPointAnchor GetSphereSurfaceAnchor(
 373        Vector3d sphereCenter,
 374        FixedQuaternion rotation,
 375        Fixed64 radius,
 376        Signed576 directionX,
 377        Signed576 directionY,
 378        Signed576 directionZ,
 379        bool negate)
 380    {
 18381        if (negate)
 382        {
 15383            directionX = WideArithmetic.SubtractSigned576(
 15384                default,
 15385                directionX);
 15386            directionY = WideArithmetic.SubtractSigned576(
 15387                default,
 15388                directionY);
 15389            directionZ = WideArithmetic.SubtractSigned576(
 15390                default,
 15391                directionZ);
 392        }
 393
 18394        WideRationalBasis3d basis = new(rotation);
 18395        Signed576 localX = GetProjectionNumerator(
 18396            directionX,
 18397            directionY,
 18398            directionZ,
 18399            basis.Xx,
 18400            basis.Xy,
 18401            basis.Xz);
 18402        Signed576 localY = GetProjectionNumerator(
 18403            directionX,
 18404            directionY,
 18405            directionZ,
 18406            basis.Yx,
 18407            basis.Yy,
 18408            basis.Yz);
 18409        Signed576 localZ = GetProjectionNumerator(
 18410            directionX,
 18411            directionY,
 18412            directionZ,
 18413            basis.Zx,
 18414            basis.Zy,
 18415            basis.Zz);
 18416        Vector3d localDirection = WideNormalization.GetNormalized(
 18417            localX,
 18418            localY,
 18419            localZ);
 18420        Vector3d roundedOffset = localDirection * radius;
 18421        FixedPointAnchorTerm3d exactTerm =
 18422            FixedPointAnchorTerm3d.CreateRadialSupport(
 18423                localDirection,
 18424                radius,
 18425                roundedOffset);
 18426        return new FixedPointAnchor(
 18427            sphereCenter,
 18428            rotation,
 18429            Vector3d.Zero,
 18430            roundedOffset,
 18431            exactTerm);
 432    }
 433
 434    private static Signed576 GetProjectionNumerator(
 435        Signed576 directionX,
 436        Signed576 directionY,
 437        Signed576 directionZ,
 438        Signed192 axisX,
 439        Signed192 axisY,
 440        Signed192 axisZ) =>
 54441        WideArithmetic.AddSigned576(
 54442            WideArithmetic.AddSigned576(
 54443                WideArithmetic.MultiplySigned576(directionX, axisX),
 54444                WideArithmetic.MultiplySigned576(directionY, axisY)),
 54445            WideArithmetic.MultiplySigned576(directionZ, axisZ));
 446
 447    private static void GetRationalLocalOffsetNumerators(
 448        WideRationalBasis3d basis,
 449        Signed320 localX,
 450        Signed320 localY,
 451        Signed320 localZ,
 452        out Signed576 x,
 453        out Signed576 y,
 454        out Signed576 z)
 455    {
 8456        x = GetRationalLocalOffsetNumerator(
 8457            basis.Xx,
 8458            basis.Yx,
 8459            basis.Zx,
 8460            localX,
 8461            localY,
 8462            localZ);
 8463        y = GetRationalLocalOffsetNumerator(
 8464            basis.Xy,
 8465            basis.Yy,
 8466            basis.Zy,
 8467            localX,
 8468            localY,
 8469            localZ);
 8470        z = GetRationalLocalOffsetNumerator(
 8471            basis.Xz,
 8472            basis.Yz,
 8473            basis.Zz,
 8474            localX,
 8475            localY,
 8476            localZ);
 8477    }
 478
 479    private static Signed576 GetRationalLocalOffsetNumerator(
 480        Signed192 axisX,
 481        Signed192 axisY,
 482        Signed192 axisZ,
 483        Signed320 localX,
 484        Signed320 localY,
 485        Signed320 localZ) =>
 24486        WideArithmetic.AddSigned576(
 24487            WideArithmetic.AddSigned576(
 24488                WideArithmetic.MultiplySigned320(
 24489                    localX,
 24490                    Signed320.ExtendValue(axisX)),
 24491                WideArithmetic.MultiplySigned320(
 24492                    localY,
 24493                    Signed320.ExtendValue(axisY))),
 24494            WideArithmetic.MultiplySigned320(
 24495                localZ,
 24496                Signed320.ExtendValue(axisZ)));
 497
 498    private static Signed576 GetOriginRelativeNumerator(
 499        Fixed64 point,
 500        Fixed64 origin,
 501        Signed320 denominatorSquared,
 502        Signed576 offsetNumerator) =>
 24503        WideArithmetic.SubtractSigned576(
 24504            WideArithmetic.MultiplySigned320(
 24505                Signed320.ExtendValue(
 24506                    WideArithmetic.SubtractSigned192(Signed192.Raw(point), Signed192.Raw(origin))),
 24507                denominatorSquared),
 24508            offsetNumerator);
 509
 510    private static Signed832 SumSquares(
 511        Signed576 x,
 512        Signed576 y,
 513        Signed576 z) =>
 8514        WideArithmetic.AddSigned832(
 8515            WideArithmetic.AddSigned832(
 8516                WideArithmetic.MultiplySigned576ToSigned832(x, x),
 8517                WideArithmetic.MultiplySigned576ToSigned832(y, y)),
 8518            WideArithmetic.MultiplySigned576ToSigned832(z, z));
 519
 520    private static Fixed64 GetRoundedRadialDepth(
 521        Fixed64 radius,
 522        Signed832 squaredDistance,
 523        Signed320 denominator)
 524    {
 7525        Signed576 root = WideArithmetic.GetFloorSquareRootOfProduct(
 7526            squaredDistance,
 7527            Signed192.Signed(1L));
 7528        _ = Fixed64.TryGetSignedRawRatio(
 7529            root,
 7530            Signed576.ExtendValue(denominator),
 7531            out Fixed64 roundedDistance);
 7532        Fixed64 depth = radius - roundedDistance;
 7533        CorrectRoundedRadialDepth(
 7534            radius,
 7535            squaredDistance,
 7536            denominator,
 7537            ref depth);
 7538        return depth;
 539    }
 540
 541    private static void CorrectRoundedRadialDepth(
 542        Fixed64 radius,
 543        Signed832 squaredDistance,
 544        Signed320 denominator,
 545        ref Fixed64 depth)
 546    {
 7547        if (depth > Fixed64.Zero)
 548        {
 6549            Signed192 lowerMidpoint = WideArithmetic.SubtractSigned192(
 6550                WideArithmetic.AddSigned192(Signed192.Raw(depth), Signed192.Raw(depth)),
 6551                Signed192.Signed(1L));
 6552            int comparison = CompareRadialDepthToTwiceRaw(
 6553                radius,
 6554                squaredDistance,
 6555                denominator,
 6556                lowerMidpoint);
 6557            depth = Fixed64.FromRaw(
 6558                depth.m_rawValue
 6559                - GetLowerMidpointAdjustment(
 6560                    comparison,
 6561                    depth.m_rawValue));
 562        }
 563
 7564        Signed192 upperMidpoint = WideArithmetic.AddSigned192(
 7565            WideArithmetic.AddSigned192(Signed192.Raw(depth), Signed192.Raw(depth)),
 7566            Signed192.Signed(1L));
 7567        int upperComparison = CompareRadialDepthToTwiceRaw(
 7568            radius,
 7569            squaredDistance,
 7570            denominator,
 7571            upperMidpoint);
 7572        long remainingRaw = radius.m_rawValue - depth.m_rawValue;
 7573        long hasRoom =
 7574            (long)((ulong)(remainingRaw | -remainingRaw) >> 63);
 7575        depth = Fixed64.FromRaw(
 7576            depth.m_rawValue
 7577            + (GetUpperMidpointAdjustment(
 7578                upperComparison,
 7579                depth.m_rawValue) & hasRoom));
 7580    }
 581
 582    private static long GetLowerMidpointAdjustment(
 583        int comparison,
 584        long depthRaw)
 585    {
 6586        int negative = (int)((uint)comparison >> 31);
 6587        int nonzero = (int)((uint)(comparison | -comparison) >> 31);
 6588        int zero = nonzero ^ 1;
 6589        int oddTie = zero & (int)(depthRaw & 1L);
 6590        return negative | oddTie;
 591    }
 592
 593    private static long GetUpperMidpointAdjustment(
 594        int comparison,
 595        long depthRaw)
 596    {
 7597        int positive = (int)((uint)-comparison >> 31);
 7598        int nonzero = (int)((uint)(comparison | -comparison) >> 31);
 7599        int zero = nonzero ^ 1;
 7600        int oddTie = zero & (int)(depthRaw & 1L);
 7601        return positive | oddTie;
 602    }
 603
 604    private static int CompareRadialDepthToTwiceRaw(
 605        Fixed64 radius,
 606        Signed832 squaredDistance,
 607        Signed320 denominator,
 608        Signed192 twiceRaw)
 609    {
 13610        Signed192 twiceRadius = WideArithmetic.AddSigned192(
 13611            Signed192.Raw(radius),
 13612            Signed192.Raw(radius));
 13613        Signed192 remaining = WideArithmetic.SubtractSigned192(
 13614            twiceRadius,
 13615            twiceRaw);
 13616        Signed576 threshold = WideArithmetic.MultiplySigned320(
 13617            Signed320.ExtendValue(remaining),
 13618            denominator);
 13619        Signed832 thresholdSquared =
 13620            WideArithmetic.MultiplySigned576ToSigned832(threshold, threshold);
 13621        Signed832 fourSquaredDistance = WideArithmetic.AddSigned832(
 13622            WideArithmetic.AddSigned832(squaredDistance, squaredDistance),
 13623            WideArithmetic.AddSigned832(squaredDistance, squaredDistance));
 13624        return WideArithmetic.SubtractSigned832(
 13625            thresholdSquared,
 13626            fourSquaredDistance).Sign;
 627    }
 628}

/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.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        {
 65435            X = x;
 65436            Y = y;
 65437            Z = z;
 65438            ReferenceYOffset = referenceYOffset;
 65439            LocalPoint = localPoint;
 65440        }
 41
 42        internal TriangleSweepPoint ToSweepPoint(
 43            Signed192 basisDenominator) =>
 184444            new(
 184445                new SweepRationalPoint(
 184446                    Signed576.ExtendValue(X),
 184447                    Signed576.ExtendValue(Z),
 184448                    Signed576.ExtendValue(
 184449                        Signed320.ExtendValue(
 184450                            basisDenominator))),
 184451                ReferenceYOffset,
 184452                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        {
 218067            RationalPoint = rationalPoint;
 218068            ReferenceYOffset = referenceYOffset;
 218069            LocalPoint = localPoint;
 218070        }
 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)
 11287        => TryGetFiniteSlabProjectedCircleSweepCore(
 11288            triangle, triangleOrigin, triangleRotation, circleStart, new SweepTrajectory(direction),
 11289            maximumDistance, circleRadius, slabCenterY, slabHalfThickness, out distance, out triangleContact);
 90
 91    internal static bool TryGetFiniteSlabProjectedCircleSweep(
 92        FixedTriangle triangle,
 93        Vector3d triangleOrigin,
 94        FixedQuaternion triangleRotation,
 95        FixedSegment2d segment,
 96        Fixed64 totalDistance,
 97        Fixed64 circleRadius,
 98        Fixed64 slabCenterY,
 99        Fixed64 slabHalfThickness,
 100        out Fixed64 distance,
 101        out FixedPointAnchor triangleContact)
 106102        => TryGetFiniteSlabProjectedCircleSweepCore(
 106103            triangle, triangleOrigin, triangleRotation, segment.Start, new SweepTrajectory(segment, totalDistance),
 106104            totalDistance, circleRadius, slabCenterY, slabHalfThickness, out distance, out triangleContact);
 105
 106    private static bool TryGetFiniteSlabProjectedCircleSweepCore(
 107        FixedTriangle triangle,
 108        Vector3d triangleOrigin,
 109        FixedQuaternion triangleRotation,
 110        Vector2d circleStart,
 111        in SweepTrajectory trajectory,
 112        Fixed64 maximumDistance,
 113        Fixed64 circleRadius,
 114        Fixed64 slabCenterY,
 115        Fixed64 slabHalfThickness,
 116        out Fixed64 distance,
 117        out FixedPointAnchor triangleContact)
 118    {
 218119        WideRationalBasis3d basis = new(triangleRotation);
 218120        Signed320 referenceYNumerator =
 218121            WideArithmetic.MultiplySigned192(
 218122                Signed192.Raw(slabCenterY),
 218123                basis.Denominator);
 218124        TriangleSweepVertex first = GetTriangleSweepVertex(
 218125            triangleOrigin,
 218126            basis,
 218127            triangle.A,
 218128            referenceYNumerator);
 218129        TriangleSweepVertex second = GetTriangleSweepVertex(
 218130            triangleOrigin,
 218131            basis,
 218132            triangle.B,
 218133            referenceYNumerator);
 218134        TriangleSweepVertex third = GetTriangleSweepVertex(
 218135            triangleOrigin,
 218136            basis,
 218137            triangle.C,
 218138            referenceYNumerator);
 218139        Signed192 lowerY = WideArithmetic.SubtractSigned192(
 218140            Signed192.Raw(slabCenterY),
 218141            Signed192.Raw(slabHalfThickness));
 218142        Signed192 upperY = WideArithmetic.AddSigned192(
 218143            Signed192.Raw(slabCenterY),
 218144            Signed192.Raw(slabHalfThickness));
 218145        Signed320 lowerNumerator =
 218146            WideArithmetic.MultiplySigned192(lowerY, basis.Denominator);
 218147        Signed320 upperNumerator =
 218148            WideArithmetic.MultiplySigned192(upperY, basis.Denominator);
 218149        if (TryGetTriangleProjectionInteriorPoint(
 218150                first,
 218151                second,
 218152                third,
 218153                circleStart,
 218154                lowerNumerator,
 218155                upperNumerator,
 218156                basis.Denominator,
 218157                out Vector3d interiorLocalPoint))
 158        {
 3159            distance = Fixed64.Zero;
 3160            triangleContact = new FixedPointAnchor(
 3161                triangleOrigin,
 3162                triangleRotation,
 3163                interiorLocalPoint);
 3164            return true;
 165        }
 166
 215167        bool found = false;
 215168        Fixed64 bestDistance = default;
 215169        Vector3d bestLocalPoint = default;
 215170        Signed576 bestReferenceYOffset = default;
 215171        bool firstSecondCollapsed =
 215172            AreSameProjectedPoint(first, second);
 215173        bool secondThirdCollapsed =
 215174            AreSameProjectedPoint(second, third);
 215175        bool thirdFirstCollapsed =
 215176            AreSameProjectedPoint(third, first);
 215177        bool allCollapsed =
 215178            firstSecondCollapsed
 215179            && secondThirdCollapsed
 215180            && thirdFirstCollapsed;
 215181        if (allCollapsed || !firstSecondCollapsed)
 182        {
 192183            KeepTriangleEdgeSweep(
 192184                first,
 192185                second,
 192186                lowerNumerator,
 192187                upperNumerator,
 192188                basis.Denominator,
 192189                referenceYNumerator,
 192190                circleStart,
 192191                trajectory,
 192192                maximumDistance,
 192193                circleRadius,
 192194                ref found,
 192195                ref bestDistance,
 192196                ref bestLocalPoint,
 192197                ref bestReferenceYOffset);
 198        }
 215199        if (allCollapsed || !secondThirdCollapsed)
 200        {
 210201            KeepTriangleEdgeSweep(
 210202                second,
 210203                third,
 210204                lowerNumerator,
 210205                upperNumerator,
 210206                basis.Denominator,
 210207                referenceYNumerator,
 210208                circleStart,
 210209                trajectory,
 210210                maximumDistance,
 210211                circleRadius,
 210212                ref found,
 210213                ref bestDistance,
 210214                ref bestLocalPoint,
 210215                ref bestReferenceYOffset);
 216        }
 215217        if (allCollapsed || !thirdFirstCollapsed)
 218        {
 211219            KeepTriangleEdgeSweep(
 211220                third,
 211221                first,
 211222                lowerNumerator,
 211223                upperNumerator,
 211224                basis.Denominator,
 211225                referenceYNumerator,
 211226                circleStart,
 211227                trajectory,
 211228                maximumDistance,
 211229                circleRadius,
 211230                ref found,
 211231                ref bestDistance,
 211232                ref bestLocalPoint,
 211233                ref bestReferenceYOffset);
 234        }
 215235        KeepTrianglePlaneEdgeSweep(
 215236            first,
 215237            second,
 215238            third,
 215239            lowerNumerator,
 215240            basis.Denominator,
 215241            referenceYNumerator,
 215242            circleStart,
 215243            trajectory,
 215244            maximumDistance,
 215245            circleRadius,
 215246            ref found,
 215247            ref bestDistance,
 215248            ref bestLocalPoint,
 215249            ref bestReferenceYOffset);
 215250        if (CompareSigned(lowerNumerator, upperNumerator) != 0)
 251        {
 68252            KeepTrianglePlaneEdgeSweep(
 68253                first,
 68254                second,
 68255                third,
 68256                upperNumerator,
 68257                basis.Denominator,
 68258                referenceYNumerator,
 68259                circleStart,
 68260                trajectory,
 68261                maximumDistance,
 68262                circleRadius,
 68263                ref found,
 68264                ref bestDistance,
 68265                ref bestLocalPoint,
 68266                ref bestReferenceYOffset);
 267        }
 268
 215269        if (!found)
 270        {
 17271            distance = default;
 17272            triangleContact = default;
 17273            return false;
 274        }
 275
 198276        distance = bestDistance;
 198277        triangleContact = new FixedPointAnchor(
 198278            triangleOrigin,
 198279            triangleRotation,
 198280            bestLocalPoint);
 198281        return true;
 282    }
 283
 284    private static bool TryGetTriangleProjectionInteriorPoint(
 285        TriangleSweepVertex first,
 286        TriangleSweepVertex second,
 287        TriangleSweepVertex third,
 288        Vector2d point,
 289        Signed320 lowerY,
 290        Signed320 upperY,
 291        Signed192 basisDenominator,
 292        out Vector3d localPoint)
 293    {
 218294        Signed320 firstEdgeX =
 218295            WideArithmetic.SubtractSigned320(second.X, first.X);
 218296        Signed320 firstEdgeZ =
 218297            WideArithmetic.SubtractSigned320(second.Z, first.Z);
 218298        Signed320 secondEdgeX =
 218299            WideArithmetic.SubtractSigned320(third.X, first.X);
 218300        Signed320 secondEdgeZ =
 218301            WideArithmetic.SubtractSigned320(third.Z, first.Z);
 218302        Signed576 determinant = WideArithmetic.SubtractSigned576(
 218303            WideArithmetic.MultiplySigned320(
 218304                firstEdgeX,
 218305                secondEdgeZ),
 218306            WideArithmetic.MultiplySigned320(
 218307                firstEdgeZ,
 218308                secondEdgeX));
 218309        if (determinant.IsZero)
 310        {
 35311            localPoint = default;
 35312            return false;
 313        }
 314
 183315        Signed320 pointX = WideArithmetic.SubtractSigned320(
 183316            WideArithmetic.MultiplySigned192(
 183317                Signed192.Raw(point.X),
 183318                basisDenominator),
 183319            first.X);
 183320        Signed320 pointZ = WideArithmetic.SubtractSigned320(
 183321            WideArithmetic.MultiplySigned192(
 183322                Signed192.Raw(point.Y),
 183323                basisDenominator),
 183324            first.Z);
 183325        Signed576 firstParameter = WideArithmetic.SubtractSigned576(
 183326            WideArithmetic.MultiplySigned320(
 183327                pointX,
 183328                secondEdgeZ),
 183329            WideArithmetic.MultiplySigned320(
 183330                pointZ,
 183331                secondEdgeX));
 183332        Signed576 secondParameter = WideArithmetic.SubtractSigned576(
 183333            WideArithmetic.MultiplySigned320(
 183334                firstEdgeX,
 183335                pointZ),
 183336            WideArithmetic.MultiplySigned320(
 183337                firstEdgeZ,
 183338                pointX));
 183339        if (determinant.Sign < 0)
 340        {
 155341            determinant =
 155342                WideArithmetic.SubtractSigned576(default, determinant);
 155343            firstParameter =
 155344                WideArithmetic.SubtractSigned576(default, firstParameter);
 155345            secondParameter =
 155346                WideArithmetic.SubtractSigned576(default, secondParameter);
 347        }
 348
 183349        if (firstParameter.Sign < 0
 183350            || secondParameter.Sign < 0
 183351            || WideArithmetic.SubtractSigned576(
 183352                WideArithmetic.AddSigned576(
 183353                    firstParameter,
 183354                    secondParameter),
 183355                determinant).Sign > 0)
 356        {
 178357            localPoint = default;
 178358            return false;
 359        }
 360
 5361        Signed320 firstEdgeY =
 5362            WideArithmetic.SubtractSigned320(second.Y, first.Y);
 5363        Signed320 secondEdgeY =
 5364            WideArithmetic.SubtractSigned320(third.Y, first.Y);
 5365        Signed832 yNumerator = WideArithmetic.AddSigned832(
 5366            WideArithmetic.AddSigned832(
 5367                WideArithmetic.MultiplySigned576ToSigned832(
 5368                    Signed576.ExtendValue(first.Y),
 5369                    determinant),
 5370                WideArithmetic.MultiplySigned576ToSigned832(
 5371                    Signed576.ExtendValue(firstEdgeY),
 5372                    firstParameter)),
 5373            WideArithmetic.MultiplySigned576ToSigned832(
 5374                Signed576.ExtendValue(secondEdgeY),
 5375                secondParameter));
 5376        Signed832 lowerNumerator =
 5377            WideArithmetic.MultiplySigned576ToSigned832(
 5378                Signed576.ExtendValue(lowerY),
 5379                determinant);
 5380        Signed832 upperNumerator =
 5381            WideArithmetic.MultiplySigned576ToSigned832(
 5382                Signed576.ExtendValue(upperY),
 5383                determinant);
 5384        if (WideArithmetic.SubtractSigned832(
 5385                yNumerator,
 5386                lowerNumerator).Sign < 0
 5387            || WideArithmetic.SubtractSigned832(
 5388                yNumerator,
 5389                upperNumerator).Sign > 0)
 390        {
 2391            localPoint = default;
 2392            return false;
 393        }
 394
 3395        Signed320 firstLocalX =
 3396            Signed320.ExtendValue(
 3397                WideArithmetic.SubtractSigned192(
 3398                Signed192.Raw(second.LocalPoint.X),
 3399                Signed192.Raw(first.LocalPoint.X)));
 3400        Signed320 firstLocalY =
 3401            Signed320.ExtendValue(
 3402                WideArithmetic.SubtractSigned192(
 3403                Signed192.Raw(second.LocalPoint.Y),
 3404                Signed192.Raw(first.LocalPoint.Y)));
 3405        Signed320 firstLocalZ =
 3406            Signed320.ExtendValue(
 3407                WideArithmetic.SubtractSigned192(
 3408                Signed192.Raw(second.LocalPoint.Z),
 3409                Signed192.Raw(first.LocalPoint.Z)));
 3410        Signed320 secondLocalX =
 3411            Signed320.ExtendValue(
 3412                WideArithmetic.SubtractSigned192(
 3413                Signed192.Raw(third.LocalPoint.X),
 3414                Signed192.Raw(first.LocalPoint.X)));
 3415        Signed320 secondLocalY =
 3416            Signed320.ExtendValue(
 3417                WideArithmetic.SubtractSigned192(
 3418                Signed192.Raw(third.LocalPoint.Y),
 3419                Signed192.Raw(first.LocalPoint.Y)));
 3420        Signed320 secondLocalZ =
 3421            Signed320.ExtendValue(
 3422                WideArithmetic.SubtractSigned192(
 3423                Signed192.Raw(third.LocalPoint.Z),
 3424                Signed192.Raw(first.LocalPoint.Z)));
 3425        Signed832 denominator =
 3426            Signed832.ExtendValue(determinant);
 427        // A barycentric point lies inside the convex hull of three
 428        // representable local vertices, so every final local component is
 429        // representable by construction.
 3430        _ = TryGetTriangleInteriorLocalCoordinate(
 3431                first.LocalPoint.X,
 3432                firstLocalX,
 3433                secondLocalX,
 3434                firstParameter,
 3435                secondParameter,
 3436                determinant,
 3437                denominator,
 3438                out Fixed64 localX);
 3439        _ = TryGetTriangleInteriorLocalCoordinate(
 3440                first.LocalPoint.Y,
 3441                firstLocalY,
 3442                secondLocalY,
 3443                firstParameter,
 3444                secondParameter,
 3445                determinant,
 3446                denominator,
 3447                out Fixed64 localY);
 3448        _ = TryGetTriangleInteriorLocalCoordinate(
 3449                first.LocalPoint.Z,
 3450                firstLocalZ,
 3451                secondLocalZ,
 3452                firstParameter,
 3453                secondParameter,
 3454                determinant,
 3455                denominator,
 3456                out Fixed64 localZ);
 3457        localPoint = new Vector3d(localX, localY, localZ);
 3458        return true;
 459    }
 460
 461    private static bool TryGetTriangleInteriorLocalCoordinate(
 462        Fixed64 origin,
 463        Signed320 firstEdge,
 464        Signed320 secondEdge,
 465        Signed576 firstParameter,
 466        Signed576 secondParameter,
 467        Signed576 determinant,
 468        Signed832 denominator,
 469        out Fixed64 coordinate)
 470    {
 9471        Signed832 numerator = WideArithmetic.AddSigned832(
 9472            WideArithmetic.AddSigned832(
 9473                WideArithmetic.MultiplySigned576ToSigned832(
 9474                    Signed576.ExtendValue(
 9475                        Signed320.ExtendValue(Signed192.Raw(origin))),
 9476                    determinant),
 9477                WideArithmetic.MultiplySigned576ToSigned832(
 9478                    Signed576.ExtendValue(firstEdge),
 9479                    firstParameter)),
 9480            WideArithmetic.MultiplySigned576ToSigned832(
 9481                Signed576.ExtendValue(secondEdge),
 9482                secondParameter));
 9483        return Fixed64.TryGetSignedRawRatio(
 9484            numerator,
 9485            denominator,
 9486            numeratorLeftShift: 0,
 9487            out coordinate);
 488    }
 489
 490    private static TriangleSweepVertex GetTriangleSweepVertex(
 491        Vector3d origin,
 492        WideRationalBasis3d basis,
 493        Vector3d localPoint,
 494        Signed320 referenceYNumerator)
 495    {
 654496        Signed320 x = WideArithmetic.AddSigned320(
 654497            WideArithmetic.MultiplySigned192(
 654498                Signed192.Raw(origin.X),
 654499                basis.Denominator),
 654500            GetLocalOffsetNumerator(
 654501                basis.Xx,
 654502                basis.Yx,
 654503                basis.Zx,
 654504                localPoint));
 654505        Signed320 y = WideArithmetic.AddSigned320(
 654506            WideArithmetic.MultiplySigned192(
 654507                Signed192.Raw(origin.Y),
 654508                basis.Denominator),
 654509            GetLocalOffsetNumerator(
 654510                basis.Xy,
 654511                basis.Yy,
 654512                basis.Zy,
 654513                localPoint));
 654514        Signed320 z = WideArithmetic.AddSigned320(
 654515            WideArithmetic.MultiplySigned192(
 654516                Signed192.Raw(origin.Z),
 654517                basis.Denominator),
 654518            GetLocalOffsetNumerator(
 654519                basis.Xz,
 654520                basis.Yz,
 654521                basis.Zz,
 654522                localPoint));
 654523        return new TriangleSweepVertex(
 654524            x,
 654525            y,
 654526            z,
 654527            WideArithmetic.SubtractSigned320(
 654528                y,
 654529                referenceYNumerator),
 654530            localPoint);
 531    }
 532
 533    private static bool AreSameProjectedPoint(
 534        TriangleSweepVertex first,
 535        TriangleSweepVertex second) =>
 645536        CompareSigned(first.X, second.X) == 0
 645537        && CompareSigned(first.Z, second.Z) == 0;
 538
 539    private static void KeepTriangleEdgeSweep(
 540        TriangleSweepVertex first,
 541        TriangleSweepVertex second,
 542        Signed320 lowerY,
 543        Signed320 upperY,
 544        Signed192 basisDenominator,
 545        Signed320 referenceYNumerator,
 546        Vector2d circleStart,
 547        in SweepTrajectory trajectory,
 548        Fixed64 maximumDistance,
 549        Fixed64 radius,
 550        ref bool found,
 551        ref Fixed64 bestDistance,
 552        ref Vector3d bestLocalPoint,
 553        ref Signed576 bestReferenceYOffset)
 554    {
 613555        Signed320 minimum = CompareSigned(first.Y, second.Y) <= 0
 613556            ? first.Y
 613557            : second.Y;
 613558        Signed320 maximum = CompareSigned(first.Y, second.Y) <= 0
 613559            ? second.Y
 613560            : first.Y;
 613561        if (CompareSigned(maximum, lowerY) < 0
 613562            || CompareSigned(minimum, upperY) > 0)
 563        {
 57564            return;
 565        }
 566
 556567        TriangleSweepPoint clippedFirst =
 556568            GetClippedTriangleEdgeEndpoint(
 556569                first,
 556570                second,
 556571                lowerY,
 556572                upperY,
 556573                basisDenominator,
 556574                referenceYNumerator);
 556575        TriangleSweepPoint clippedSecond =
 556576            GetClippedTriangleEdgeEndpoint(
 556577                second,
 556578                first,
 556579                lowerY,
 556580                upperY,
 556581                basisDenominator,
 556582                referenceYNumerator);
 556583        KeepTriangleSweepFeature(
 556584            clippedFirst,
 556585            clippedSecond,
 556586            circleStart,
 556587            trajectory,
 556588            maximumDistance,
 556589            radius,
 556590            ref found,
 556591            ref bestDistance,
 556592            ref bestLocalPoint,
 556593            ref bestReferenceYOffset);
 556594    }
 595
 596    private static TriangleSweepPoint GetClippedTriangleEdgeEndpoint(
 597        TriangleSweepVertex endpoint,
 598        TriangleSweepVertex other,
 599        Signed320 lowerY,
 600        Signed320 upperY,
 601        Signed192 basisDenominator,
 602        Signed320 referenceYNumerator)
 603    {
 1112604        if (CompareSigned(endpoint.Y, lowerY) >= 0
 1112605            && CompareSigned(endpoint.Y, upperY) <= 0)
 606        {
 960607            return endpoint.ToSweepPoint(basisDenominator);
 608        }
 609
 152610        Signed320 plane = CompareSigned(endpoint.Y, lowerY) < 0
 152611            ? lowerY
 152612            : upperY;
 152613        return GetTrianglePlaneIntersection(
 152614            endpoint,
 152615            other,
 152616            plane,
 152617            basisDenominator,
 152618            referenceYNumerator);
 619    }
 620
 621    private static void KeepTrianglePlaneEdgeSweep(
 622        TriangleSweepVertex first,
 623        TriangleSweepVertex second,
 624        TriangleSweepVertex third,
 625        Signed320 planeY,
 626        Signed192 basisDenominator,
 627        Signed320 referenceYNumerator,
 628        Vector2d circleStart,
 629        in SweepTrajectory trajectory,
 630        Fixed64 maximumDistance,
 631        Fixed64 radius,
 632        ref bool found,
 633        ref Fixed64 bestDistance,
 634        ref Vector3d bestLocalPoint,
 635        ref Signed576 bestReferenceYOffset)
 636    {
 283637        Span<TriangleSweepPoint> intersections =
 283638            stackalloc TriangleSweepPoint[3];
 283639        int count = 0;
 283640        TryAddTrianglePlaneIntersection(
 283641            first,
 283642            second,
 283643            planeY,
 283644            basisDenominator,
 283645            referenceYNumerator,
 283646            intersections,
 283647            ref count);
 283648        TryAddTrianglePlaneIntersection(
 283649            second,
 283650            third,
 283651            planeY,
 283652            basisDenominator,
 283653            referenceYNumerator,
 283654            intersections,
 283655            ref count);
 283656        TryAddTrianglePlaneIntersection(
 283657            third,
 283658            first,
 283659            planeY,
 283660            basisDenominator,
 283661            referenceYNumerator,
 283662            intersections,
 283663            ref count);
 283664        if (count < 2)
 49665            return;
 666
 234667        KeepTriangleSweepFeature(
 234668            intersections[0],
 234669            intersections[1],
 234670            circleStart,
 234671            trajectory,
 234672            maximumDistance,
 234673            radius,
 234674            ref found,
 234675            ref bestDistance,
 234676            ref bestLocalPoint,
 234677            ref bestReferenceYOffset);
 234678    }
 679
 680    private static void TryAddTrianglePlaneIntersection(
 681        TriangleSweepVertex first,
 682        TriangleSweepVertex second,
 683        Signed320 planeY,
 684        Signed192 basisDenominator,
 685        Signed320 referenceYNumerator,
 686        Span<TriangleSweepPoint> intersections,
 687        ref int count)
 688    {
 849689        int firstSide = CompareSigned(first.Y, planeY);
 849690        int secondSide = CompareSigned(second.Y, planeY);
 849691        if (firstSide == 0)
 692        {
 442693            AddUniqueTriangleSweepPoint(
 442694                first.ToSweepPoint(basisDenominator),
 442695                intersections,
 442696                ref count);
 697        }
 849698        if (secondSide == 0)
 699        {
 442700            AddUniqueTriangleSweepPoint(
 442701                second.ToSweepPoint(basisDenominator),
 442702                intersections,
 442703                ref count);
 704        }
 849705        if (firstSide == 0
 849706            || secondSide == 0
 849707            || (firstSide < 0) == (secondSide < 0))
 708        {
 665709            return;
 710        }
 711
 184712        AddUniqueTriangleSweepPoint(
 184713            GetTrianglePlaneIntersection(
 184714                first,
 184715                second,
 184716                planeY,
 184717                basisDenominator,
 184718                referenceYNumerator),
 184719            intersections,
 184720            ref count);
 184721    }
 722
 723    private static TriangleSweepPoint GetTrianglePlaneIntersection(
 724        TriangleSweepVertex first,
 725        TriangleSweepVertex second,
 726        Signed320 planeY,
 727        Signed192 basisDenominator,
 728        Signed320 referenceYNumerator)
 729    {
 336730        Signed320 deltaY =
 336731            WideArithmetic.SubtractSigned320(second.Y, first.Y);
 336732        Signed320 firstWeight =
 336733            WideArithmetic.SubtractSigned320(second.Y, planeY);
 336734        Signed320 secondWeight =
 336735            WideArithmetic.SubtractSigned320(planeY, first.Y);
 336736        Signed576 x = WideArithmetic.AddSigned576(
 336737            WideArithmetic.MultiplySigned320(first.X, firstWeight),
 336738            WideArithmetic.MultiplySigned320(second.X, secondWeight));
 336739        Signed576 z = WideArithmetic.AddSigned576(
 336740            WideArithmetic.MultiplySigned320(first.Z, firstWeight),
 336741            WideArithmetic.MultiplySigned320(second.Z, secondWeight));
 336742        Signed576 denominator = WideArithmetic.MultiplySigned320(
 336743            Signed320.ExtendValue(basisDenominator),
 336744            deltaY);
 336745        if (denominator.Sign < 0)
 746        {
 169747            x = WideArithmetic.SubtractSigned576(default, x);
 169748            z = WideArithmetic.SubtractSigned576(default, z);
 169749            denominator =
 169750                WideArithmetic.SubtractSigned576(default, denominator);
 169751            firstWeight =
 169752                WideArithmetic.SubtractSigned320(default, firstWeight);
 169753            secondWeight =
 169754                WideArithmetic.SubtractSigned320(default, secondWeight);
 169755            deltaY = WideArithmetic.SubtractSigned320(default, deltaY);
 756        }
 757
 336758        Vector3d localPoint = GetWeightedLocalPoint(
 336759            first.LocalPoint,
 336760            second.LocalPoint,
 336761            secondWeight,
 336762            deltaY);
 336763        return new TriangleSweepPoint(
 336764            new SweepRationalPoint(x, z, denominator),
 336765            WideArithmetic.SubtractSigned320(
 336766                planeY,
 336767                referenceYNumerator),
 336768            localPoint);
 769    }
 770
 771    private static Vector3d GetWeightedLocalPoint(
 772        Vector3d first,
 773        Vector3d second,
 774        Signed320 secondWeight,
 775        Signed320 denominator)
 776    {
 336777        Span<Vector3d> points = stackalloc Vector3d[2]
 336778        {
 336779            first,
 336780            second,
 336781        };
 782        // This ratio is a dimensionless interpolation parameter, so promote
 783        // it to Q32.32 rather than treating the integer quotient as raw.
 336784        _ = Fixed64.TryGetSignedRawRatio(
 336785            Signed832.ExtendValue(
 336786                Signed576.ExtendValue(secondWeight)),
 336787            Signed832.ExtendValue(
 336788                Signed576.ExtendValue(denominator)),
 336789            FixedMath.SHIFT_AMOUNT_I,
 336790            out Fixed64 parameter);
 336791        Span<Fixed64> weights = stackalloc Fixed64[2]
 336792        {
 336793            Fixed64.One - parameter,
 336794            parameter,
 336795        };
 336796        _ = Vector3d.TryGetWeightedAverage(
 336797            points,
 336798            weights,
 336799            out Vector3d localPoint);
 336800        return localPoint;
 801    }
 802
 803    private static void AddUniqueTriangleSweepPoint(
 804        TriangleSweepPoint point,
 805        Span<TriangleSweepPoint> points,
 806        ref int count)
 807    {
 4024808        for (int index = 0; index < count; index++)
 809        {
 1388810            if (AreSameSweepPoint(
 1388811                    points[index].RationalPoint,
 1388812                    point.RationalPoint))
 813            {
 444814                return;
 815            }
 816        }
 817
 624818        points[count++] = point;
 624819    }
 820
 821    private static void KeepTriangleSweepFeature(
 822        TriangleSweepPoint first,
 823        TriangleSweepPoint second,
 824        Vector2d circleStart,
 825        in SweepTrajectory trajectory,
 826        Fixed64 maximumDistance,
 827        Fixed64 radius,
 828        ref bool found,
 829        ref Fixed64 bestDistance,
 830        ref Vector3d bestLocalPoint,
 831        ref Signed576 bestReferenceYOffset)
 832    {
 790833        if (TryGetRationalPointSweepDistance(
 790834                first.RationalPoint,
 790835                circleStart,
 790836                trajectory,
 790837                maximumDistance,
 790838                radius,
 790839                out Fixed64 firstDistance))
 840        {
 211841            KeepTriangleSweepCandidate(
 211842                firstDistance,
 211843                first.LocalPoint,
 211844                ScaleReferenceYOffset(first.ReferenceYOffset),
 211845                ref found,
 211846                ref bestDistance,
 211847                ref bestLocalPoint,
 211848                ref bestReferenceYOffset);
 849        }
 790850        if (!AreSameSweepPoint(
 790851                first.RationalPoint,
 790852                second.RationalPoint)
 790853            && TryGetRationalPointSweepDistance(
 790854                second.RationalPoint,
 790855                circleStart,
 790856                trajectory,
 790857                maximumDistance,
 790858                radius,
 790859                out Fixed64 secondDistance))
 860        {
 175861            KeepTriangleSweepCandidate(
 175862                secondDistance,
 175863                second.LocalPoint,
 175864                ScaleReferenceYOffset(second.ReferenceYOffset),
 175865                ref found,
 175866                ref bestDistance,
 175867                ref bestLocalPoint,
 175868                ref bestReferenceYOffset);
 869        }
 790870        if (!TryGetRationalSegmentSweepDistance(
 790871                first,
 790872                second,
 790873                circleStart,
 790874                trajectory,
 790875                maximumDistance,
 790876                radius,
 790877                out Fixed64 segmentDistance,
 790878                out Vector3d segmentLocalPoint,
 790879                out Signed576 segmentReferenceYOffset))
 880        {
 182881            return;
 882        }
 883
 608884        KeepTriangleSweepCandidate(
 608885            segmentDistance,
 608886            segmentLocalPoint,
 608887            segmentReferenceYOffset,
 608888            ref found,
 608889            ref bestDistance,
 608890            ref bestLocalPoint,
 608891            ref bestReferenceYOffset);
 608892    }
 893
 894    private static void KeepTriangleSweepCandidate(
 895        Fixed64 candidateDistance,
 896        Vector3d candidateLocalPoint,
 897        Signed576 candidateReferenceYOffset,
 898        ref bool found,
 899        ref Fixed64 bestDistance,
 900        ref Vector3d bestLocalPoint,
 901        ref Signed576 bestReferenceYOffset)
 902    {
 994903        if (found)
 904        {
 796905            if (candidateDistance > bestDistance)
 565906                return;
 231907            if ((candidateDistance == bestDistance)
 231908                & (WideArithmetic.CompareNonNegative(
 231909                    GetAbsoluteReferenceYOffset(candidateReferenceYOffset),
 231910                    GetAbsoluteReferenceYOffset(bestReferenceYOffset)) >= 0))
 911            {
 218912                return;
 913            }
 914        }
 915
 211916        found = true;
 211917        bestDistance = candidateDistance;
 211918        bestLocalPoint = candidateLocalPoint;
 211919        bestReferenceYOffset = candidateReferenceYOffset;
 211920    }
 921
 922    private static Signed576 ScaleReferenceYOffset(
 923        Signed320 value) =>
 386924        WideArithmetic.MultiplySigned320(
 386925            value,
 386926            Signed320.ExtendValue(
 386927                Signed192.One));
 928
 929    private static Signed576 GetAbsoluteReferenceYOffset(Signed576 value) =>
 462930        value.Sign < 0
 462931            ? WideArithmetic.SubtractSigned576(default, value)
 462932            : value;
 933    // Exact affine geometry retains the authored frame, while final witnesses
 934    // use a caller-supplied nearby origin rather than a potentially distant host.
 935    internal static bool TryGetFiniteSlabProjectedCircleSweep(in FixedTriangle triangle,
 936        in ScaledRigidFrame3d frame, Vector3d materializationOrigin, in FixedSegment2d segment, Fixed64 length, Fixed64 
 937        Fixed64 slabCenterY, Fixed64 halfThickness, out Fixed64 distance, out FixedPointAnchor contact)
 938    {
 40939        if (frame.IsRigid)
 6940            return TryGetFiniteSlabProjectedCircleSweep(triangle, frame.RigidOrigin, frame.Rotation,
 6941                segment, length, radius, slabCenterY, halfThickness, out distance, out contact);
 34942        Vector3d origin = new(segment.Start.X, slabCenterY, segment.Start.Y);
 34943        Span<WideDirection3d> points = stackalloc WideDirection3d[3];
 34944        Signed320 denominator = frame.Denominator;
 272945        for (int i = 0; i < 3; i++)
 946        {
 102947            frame.GetPoint(i == 0 ? triangle.A : i == 1 ? triangle.B : triangle.C)
 102948                .GetLocalPointNumerators(origin, FixedQuaternion.Identity,
 102949                    out Signed576 x, out Signed576 y, out Signed576 z, out denominator);
 102950            points[i] = new(x, y, z);
 951        }
 952        // All point coordinates share one denominator. Remove only their
 953        // exact common integer factor before forming quadratic products.
 34954        Span<Signed576> reduced = stackalloc Signed576[10];
 578955        for (int i = 0; i < 3; i++) { reduced[3 * i] = points[i].X; reduced[3 * i + 1] = points[i].Y; reduced[3 * i + 2]
 68956        reduced[9] = Signed576.ExtendValue(denominator); WideArithmetic.ReduceCommonScale(reduced);
 34957        denominator = Signed320.NarrowValue(reduced[9]);
 374958        for (int i = 0; i < 3; i++) points[i] = new(reduced[3 * i], reduced[3 * i + 1], reduced[3 * i + 2]);
 34959        if (TryGetAffineSlabSweepInterior(points, denominator, halfThickness, origin,
 50960            materializationOrigin, out contact)) { distance = Fixed64.Zero; return true; }
 26961        Signed192 dx = WideArithmetic.Difference(segment.End.X, segment.Start.X),
 26962            dz = WideArithmetic.Difference(segment.End.Y, segment.Start.Y);
 29963        if (length == Fixed64.Zero) dx = dz = default;
 964        // Admitted local vertices/placements retain <262 coordinate bits and
 965        // <400-bit wall coefficients. Clipped point coefficients are <525 bits;
 966        // edge/face roots and finite witnesses remain <2700 coefficient bits.
 967        // Keep these banks only on the affine path. The ordinary owner retains
 968        // its original fixed-width points, trajectory and compact root banks.
 969        const int words = 64;
 52970        Span<ulong> values = stackalloc ulong[14 * words]; Span<int> signs = stackalloc int[14];
 26971        Span<ulong> bestRoot = stackalloc ulong[2 * words];
 26972        bool found = false;
 26973        WideDirection3d localNormal = WideTriangleRelations.GetScaledTriangleLocalNormal(triangle, frame);
 26974        WideDirection3d normal = ReduceAffineSlabDirection(localNormal.Transform(frame.GeometryBasis));
 26975        Span<WideDirection3d> walls = stackalloc WideDirection3d[3];
 208976        for (int i = 0; i < 3; i++)
 977        {
 78978            FixedSegment edge = triangle.GetEdge(i);
 78979            walls[i] = ReduceAffineSlabDirection(WideDirection3d.Cross(localNormal,
 78980                WideDirection3d.GetLocalEdge(frame, edge.Start, edge.End)).Transform(frame.GeometryBasis));
 981        }
 754982        for (int feature = 0; feature < 14; feature++)
 983        {
 352984            KeepAffineSlabSweepFeature(points, denominator, normal, walls, dx, dz, radius,
 352985                halfThickness, feature, values, signs, bestRoot, ref found);
 986            // Zero time and zero height offset are both global lower bounds.
 352987            if (found && AffineSlabField(values, signs, 0).Sign(bestRoot) == 0
 352988                && AffineSlabField(values, signs, 3).Sign(bestRoot) == 0) break;
 989        }
 52990        distance = default; contact = default;
 37991        if (!found) return false;
 30992        var n = AffineSlabField(values, signs, 0); var d = AffineSlabField(values, signs, 1);
 30993        Span<ulong> workValues = stackalloc ulong[2 * words]; Span<int> workSigns = stackalloc int[2];
 15994        var work = AffineSlabField(workValues, workSigns, 0);
 15995        ContactQuadratic.Scale(n, Signed576.ExtendValue(Signed192.Raw(length)), work);
 15996        distance = ContactQuadratic.RoundRatio(work, d, bestRoot, 0, length.m_rawValue);
 15997        if (!QuadraticPointMaterialization.TryGetPointInFrame(origin, FixedQuaternion.Identity,
 15998                AffineSlabField(values, signs, 2), AffineSlabField(values, signs, 3),
 15999                AffineSlabField(values, signs, 4), AffineSlabField(values, signs, 5), bestRoot,
 161000                materializationOrigin, out Vector3d local)) return false;
 141001        contact = new FixedPointAnchor(materializationOrigin, FixedQuaternion.Identity, local);
 141002        return true;
 1003    }
 1004
 1005    private static ContactQuadratic AffineSlabField(Span<ulong> values, Span<int> signs, int index) =>
 75661006        ContactQuadratic.At(values, signs, index, 64);
 1007
 1008    private static bool TryGetAffineSlabSweepInterior(ReadOnlySpan<WideDirection3d> p,
 1009        Signed320 denominator, Fixed64 halfThickness, Vector3d origin, Vector3d anchorOrigin,
 1010        out FixedPointAnchor contact)
 1011    {
 341012        contact = default;
 681013        WideDirection3d e = AffineSlabDifference(p[1], p[0]), f = AffineSlabDifference(p[2], p[0]);
 341014        Signed832 det = AffineSlabCross(e.X, e.Z, f.X, f.Z);
 491015        if (det.IsZero) return false;
 191016        Signed832 n = AffineSlabCross(WideArithmetic.SubtractSigned576(default, p[0].X),
 191017            WideArithmetic.SubtractSigned576(default, p[0].Z), f.X, f.Z),
 191018            m = AffineSlabCross(e.X, e.Z, WideArithmetic.SubtractSigned576(default, p[0].X),
 191019                WideArithmetic.SubtractSigned576(default, p[0].Z));
 401020        if (det.Sign < 0) { det = AffineSlabNegate(det); n = AffineSlabNegate(n); m = AffineSlabNegate(m); }
 191021        if (n.Sign < 0 || m.Sign < 0 || WideArithmetic.SubtractSigned832(WideArithmetic.AddSigned832(n, m), det).Sign > 
 61022            return false;
 261023        Span<ulong> values = stackalloc ulong[12 * 64]; Span<int> signs = stackalloc int[12];
 261024        var y = AffineSlabField(values, signs, 0); var d = AffineSlabField(values, signs, 1);
 261025        var term = AffineSlabField(values, signs, 2); var query = AffineSlabField(values, signs, 3);
 261026        var zero = AffineSlabField(values, signs, 4); zero.Clear();
 391027        y.Set(det); ContactQuadratic.Scale(y, p[0].Y, query); query.CopyTo(y);
 391028        term.Set(n); ContactQuadratic.Scale(term, e.Y, query); y.Add(query);
 391029        term.Set(m); ContactQuadratic.Scale(term, f.Y, query); y.Add(query);
 261030        term.Set(det); ContactQuadratic.Scale(term, Signed576.ExtendValue(denominator), d);
 131031        ContactQuadratic.Scale(d, Signed576.ExtendValue(Signed192.Raw(halfThickness)), term);
 411032        term.CopyTo(query); query.Add(y, -1); if (query.Signs[0] < 0) return false;
 351033        term.CopyTo(query); query.Add(y); if (query.Signs[0] < 0) return false;
 91034        if (!QuadraticPointMaterialization.TryGetPointInFrame(origin, FixedQuaternion.Identity,
 101035                zero, y, zero, d, ReadOnlySpan<ulong>.Empty, anchorOrigin, out Vector3d point)) return false;
 161036        contact = new FixedPointAnchor(anchorOrigin, FixedQuaternion.Identity, point); return true;
 1037    }
 1038
 1039    private static void KeepAffineSlabSweepFeature(ReadOnlySpan<WideDirection3d> points, Signed320 denominator,
 1040        in WideDirection3d normal, ReadOnlySpan<WideDirection3d> walls, Signed192 dx, Signed192 dz,
 1041        Fixed64 radius, Fixed64 halfThickness, int feature, Span<ulong> bestValues,
 1042        Span<int> bestSigns, Span<ulong> bestRoot, ref bool found)
 1043    {
 1044        const int words = 64;
 7041045        Span<ulong> values = stackalloc ulong[48 * words]; Span<int> signs = stackalloc int[48];
 7041046        var a = AffineSlabField(values, signs, 0); var b = AffineSlabField(values, signs, 1);
 7041047        var c = AffineSlabField(values, signs, 2); var n = AffineSlabField(values, signs, 3);
 7041048        var d = AffineSlabField(values, signs, 4); var work = AffineSlabField(values, signs, 5);
 7041049        var term = AffineSlabField(values, signs, 6); var temporary = AffineSlabField(values, signs, 7);
 7041050        var px = AffineSlabField(values, signs, 8); var py = AffineSlabField(values, signs, 9);
 7041051        var pz = AffineSlabField(values, signs, 10); var pd = AffineSlabField(values, signs, 11);
 7041052        var vx = AffineSlabField(values, signs, 12); var vz = AffineSlabField(values, signs, 13);
 7041053        var tx = AffineSlabField(values, signs, 14); var ty = AffineSlabField(values, signs, 15);
 7041054        var tz = AffineSlabField(values, signs, 16); var td = AffineSlabField(values, signs, 17);
 7041055        var t = AffineSlabField(values, signs, 18); var metric = AffineSlabField(values, signs, 19);
 3521056        WideDirection3d velocity = new(WideArithmetic.MultiplySigned320(denominator, dx), default,
 3521057            WideArithmetic.MultiplySigned320(denominator, dz));
 3521058        int vertex = feature < 3 ? feature : feature < 6 ? feature - 3 : feature < 12 ? (feature - 6) / 2 : 0;
 7041059        WideDirection3d point = points[vertex], edge = AffineSlabDifference(points[(vertex + 1) % 3], point);
 3521060        Signed576 cap = WideArithmetic.MultiplySigned320(denominator, Signed192.Raw(halfThickness));
 17601061        Signed832 ee = default, ev = default, ep = default, planeK = default, planeV = default;
 7041062        bool line = feature is >= 3 and < 6, face = feature >= 12;
 3521063        if (line)
 1064        {
 1681065            ee = AffineSlabDot(edge, edge); if (ee.IsZero) return;
 1141066            ev = AffineSlabDot(edge, velocity); ep = AffineSlabDot(edge, point);
 1711067            Signed832 vv = AffineSlabDot(velocity, velocity), vp = AffineSlabDot(velocity, point), pp = AffineSlabDot(po
 571068            Signed576 expanded = WideArithmetic.MultiplySigned320(denominator, Signed192.Raw(radius));
 571069            Signed832 r2 = WideArithmetic.MultiplySigned576ToSigned832(expanded, expanded);
 1711070            AffineSlabProduct(ee, vv, work, a); AffineSlabProduct(ev, ev, work, term); a.Add(term, -1);
 1711071            AffineSlabProduct(ev, ep, work, b); AffineSlabProduct(ee, vp, work, term); b.Add(term, -1);
 571072            AffineSlabProduct(ee, WideArithmetic.SubtractSigned832(pp, r2), work, c);
 1141073            AffineSlabProduct(ep, ep, work, term); c.Add(term, -1);
 1074        }
 2771075        else if (face)
 1076        {
 1261077            ee = AffineSlabDot(normal, normal); if (ee.IsZero) return;
 241078            Signed576 height = feature == 12 ? WideArithmetic.SubtractSigned576(default, cap) : cap;
 241079            planeK = WideArithmetic.SubtractSigned832(WideDirection3d.Dot(normal, point),
 241080                WideArithmetic.MultiplySigned576ToSigned832(normal.Y, height));
 241081            planeV = AffineSlabDot(normal, velocity);
 241082            Signed576 expanded = WideArithmetic.MultiplySigned320(denominator, Signed192.Raw(radius));
 241083            Signed832 r2 = WideArithmetic.MultiplySigned576ToSigned832(expanded, expanded);
 241084            AffineSlabProduct(planeV, planeV, work, a);
 481085            AffineSlabProduct(planeV, planeK, work, b); b.MultiplySign(-1);
 721086            AffineSlabProduct(planeK, planeK, work, c); AffineSlabProduct(ee, r2, work, term); c.Add(term, -1);
 1087        }
 1088        else
 1089        {
 2271090            if (feature < 3)
 1091            {
 1231092                if (WideArithmetic.SubtractSigned576(point.Y, cap).Sign > 0 || WideArithmetic.AddSigned576(point.Y, cap)
 1241093                px.Set(point.X); py.Set(point.Y); pz.Set(point.Z); pd.Set(Signed576.ExtendValue(denominator));
 1094            }
 1095            else
 1096            {
 1501097                Signed576 height = (feature & 1) == 0 ? WideArithmetic.SubtractSigned576(default, cap) : cap;
 3001098                Signed576 weight = WideArithmetic.SubtractSigned576(height, point.Y), divisor = edge.Y;
 2421099                if (divisor.IsZero) return;
 1221100                if (divisor.Sign < 0) { weight = WideArithmetic.SubtractSigned576(default, weight); divisor = WideArithm
 761101                if (weight.Sign < 0 || WideArithmetic.SubtractSigned576(weight, divisor).Sign > 0) return;
 1201102                pd.Set(divisor); ContactQuadratic.Scale(pd, Signed576.ExtendValue(denominator), work); work.CopyTo(pd);
 1103                // Weight/divisor uses the original edge orientation even after
 1104                // its signs are normalized above.
 801105                px.Set(divisor); ContactQuadratic.Scale(px, point.X, work);
 1601106                temporary.Set(weight); ContactQuadratic.Scale(temporary, edge.X, term); work.Add(term); work.CopyTo(px);
 1201107                py.Set(divisor); ContactQuadratic.Scale(py, height, work); work.CopyTo(py);
 801108                pz.Set(divisor); ContactQuadratic.Scale(pz, point.Z, work);
 1601109                temporary.Set(weight); ContactQuadratic.Scale(temporary, edge.Z, term); work.Add(term); work.CopyTo(pz);
 1110            }
 1421111            ContactQuadratic.Scale(pd, Signed576.ExtendValue(dx), vx); ContactQuadratic.Scale(pd, Signed576.ExtendValue(
 711112            ContactQuadratic.Multiply(vx, vx, ReadOnlySpan<ulong>.Empty, a);
 1421113            ContactQuadratic.Multiply(vz, vz, ReadOnlySpan<ulong>.Empty, term); a.Add(term);
 711114            ContactQuadratic.Multiply(vx, px, ReadOnlySpan<ulong>.Empty, b);
 2131115            ContactQuadratic.Multiply(vz, pz, ReadOnlySpan<ulong>.Empty, term); b.Add(term); b.MultiplySign(-1);
 711116            ContactQuadratic.Multiply(px, px, ReadOnlySpan<ulong>.Empty, c);
 1421117            ContactQuadratic.Multiply(pz, pz, ReadOnlySpan<ulong>.Empty, term); c.Add(term);
 711118            ContactQuadratic.Multiply(pd, pd, ReadOnlySpan<ulong>.Empty, work);
 1421119            ContactQuadratic.Scale(work, Signed576.ExtendValue(Fixed64.GetExactRawProduct(radius, radius)), term); c.Add
 1120        }
 1521121        Span<ulong> root = stackalloc ulong[2 * words];
 12041122        for (int branch = 0; branch < 3; branch++)
 1123        {
 4521124            if (branch == 0)
 1581125            { if (c.Signs[0] > 0) continue; n.Clear(); d.Set(Signed576.ExtendValue(Signed192.Signed(1))); root.Clear(); 
 3001126            else if (!ContactQuadratic.TryGetParameter(a, b, c, branch == 1 ? -1 : 1, root, n, d)) continue;
 1581127            if (n.Sign(root) < 0) continue;
 4501128            d.CopyTo(work); work.Add(n, -1); if (work.Sign(root) < 0) continue;
 1041129            if (line)
 1130            {
 1561131                ContactQuadratic.Scale(n, ev, t); ContactQuadratic.Scale(d, ep, term); t.Add(term, -1);
 521132                if (t.Sign(root) < 0) continue;
 2001133                ContactQuadratic.Scale(d, ee, metric); metric.CopyTo(work); work.Add(t, -1); if (work.Sign(root) < 0) co
 961134                ContactQuadratic.Scale(d, ee, work); ContactQuadratic.Scale(work, point.Y, ty);
 961135                ContactQuadratic.Scale(t, edge.Y, term); ty.Add(term);
 1921136                ContactQuadratic.Scale(metric, cap, work); work.CopyTo(term); term.Add(ty, -1); if (term.Sign(root) < 0)
 1081137                work.CopyTo(term); term.Add(ty); if (term.Sign(root) < 0) continue;
 161138                ContactQuadratic.Scale(metric, Signed576.ExtendValue(denominator), td);
 481139                ContactQuadratic.Scale(metric, point.X, tx); ContactQuadratic.Scale(t, edge.X, term); tx.Add(term);
 481140                ContactQuadratic.Scale(metric, point.Z, tz); ContactQuadratic.Scale(t, edge.Z, term); tz.Add(term);
 1141            }
 521142            else if (face)
 1143            {
 961144                ContactQuadratic.Scale(n, planeV, t); ContactQuadratic.Scale(d, planeK, term); t.Add(term, -1);
 641145                metric.Set(ee); ContactQuadratic.Scale(metric, Signed576.ExtendValue(denominator), work);
 321146                ContactQuadratic.Multiply(work, d, root, td);
 641147                ContactQuadratic.Scale(n, Signed576.ExtendValue(dx), temporary); ContactQuadratic.Multiply(temporary, wo
 641148                ContactQuadratic.Scale(t, normal.X, term); tx.Add(term, -1);
 641149                ContactQuadratic.Scale(n, Signed576.ExtendValue(dz), temporary); ContactQuadratic.Multiply(temporary, wo
 641150                ContactQuadratic.Scale(t, normal.Z, term); tz.Add(term, -1);
 321151                ContactQuadratic.Multiply(metric, d, root, work);
 321152                ContactQuadratic.Scale(work, feature == 12 ? WideArithmetic.SubtractSigned576(default, cap) : cap, ty);
 401153                if (!ContainsAffineSlabSweepFace(walls, points, denominator, tx, ty, tz, td, root, work, term, temporary
 1154            }
 1155            else
 1156            {
 401157                ContactQuadratic.Multiply(px, d, root, tx); ContactQuadratic.Multiply(py, d, root, ty);
 401158                ContactQuadratic.Multiply(pz, d, root, tz); ContactQuadratic.Multiply(pd, d, root, td);
 1159            }
 601160            if (found)
 1161            {
 451162                int order = ContactQuadratic.CompareRatios(n, d, root,
 451163                    AffineSlabField(bestValues, bestSigns, 0), AffineSlabField(bestValues, bestSigns, 1), bestRoot);
 451164                if (order > 0) continue;
 191165                if (order == 0)
 1166                {
 1167                    // As in the rigid owner, equal-time witnesses prefer the
 1168                    // closest height to the slab center. Retain the original
 1169                    // quadratic ratios instead of comparing rounded anchors.
 131170                    ty.CopyTo(work, ty.Sign(root) < 0 ? -1 : 1);
 131171                    var bestY = AffineSlabField(bestValues, bestSigns, 3);
 131172                    bestY.CopyTo(term, bestY.Sign(bestRoot) < 0 ? -1 : 1);
 131173                    if (ContactQuadratic.CompareRatios(work, td, root, term,
 131174                            AffineSlabField(bestValues, bestSigns, 5), bestRoot) >= 0) continue;
 1175                }
 1176            }
 461177            n.CopyTo(AffineSlabField(bestValues, bestSigns, 0)); d.CopyTo(AffineSlabField(bestValues, bestSigns, 1));
 461178            tx.CopyTo(AffineSlabField(bestValues, bestSigns, 2)); ty.CopyTo(AffineSlabField(bestValues, bestSigns, 3));
 461179            tz.CopyTo(AffineSlabField(bestValues, bestSigns, 4)); td.CopyTo(AffineSlabField(bestValues, bestSigns, 5));
 461180            root.CopyTo(bestRoot); found = true;
 251181            if (branch == 0) return;
 1182        }
 1501183    }
 1184
 1185    private static bool ContainsAffineSlabSweepFace(ReadOnlySpan<WideDirection3d> walls,
 1186        ReadOnlySpan<WideDirection3d> points, Signed320 denominator, scoped ContactQuadratic x,
 1187        scoped ContactQuadratic y, scoped ContactQuadratic z, scoped ContactQuadratic d,
 1188        ReadOnlySpan<ulong> root, scoped ContactQuadratic work, scoped ContactQuadratic term,
 1189        scoped ContactQuadratic temporary)
 1190    {
 2161191        for (int i = 0; i < 3; i++)
 1192        {
 841193            WideDirection3d wall = walls[i];
 2521194            ContactQuadratic.Scale(x, wall.X, work); ContactQuadratic.Scale(y, wall.Y, term); work.Add(term);
 1681195            ContactQuadratic.Scale(z, wall.Z, term); work.Add(term);
 841196            ContactQuadratic.Scale(work, Signed576.ExtendValue(denominator), temporary);
 1681197            ContactQuadratic.Scale(d, WideDirection3d.Dot(wall, points[i]), term); temporary.Add(term, -1);
 921198            if (temporary.Sign(root) < 0) return false;
 1199        }
 241200        return true;
 1201    }
 1202
 1203    private static WideDirection3d ReduceAffineSlabDirection(in WideDirection3d value)
 1204    {
 1161205        if (value.IsZero) return value;
 921206        Span<Signed576> components = stackalloc Signed576[3] { value.X, value.Y, value.Z };
 921207        WideArithmetic.ReduceCommonScale(components);
 921208        return new(components[0], components[1], components[2]);
 1209    }
 1210
 1211    private static WideDirection3d AffineSlabDifference(in WideDirection3d a, in WideDirection3d b) =>
 4201212        new(WideArithmetic.SubtractSigned576(a.X, b.X), WideArithmetic.SubtractSigned576(a.Y, b.Y), WideArithmetic.Subtr
 1213    private static Signed832 AffineSlabDot(in WideDirection3d a, in WideDirection3d b) =>
 4341214        WideArithmetic.AddSigned832(WideArithmetic.MultiplySigned576ToSigned832(a.X, b.X), WideArithmetic.MultiplySigned
 1215    private static Signed832 AffineSlabCross(Signed576 ax, Signed576 az, Signed576 bx, Signed576 bz) =>
 721216        WideArithmetic.SubtractSigned832(WideArithmetic.MultiplySigned576ToSigned832(ax, bz), WideArithmetic.MultiplySig
 211217    private static Signed832 AffineSlabNegate(Signed832 value) => WideArithmetic.SubtractSigned832(default, value);
 1218    private static void AffineSlabProduct(Signed832 a, Signed832 b, scoped ContactQuadratic work, scoped ContactQuadrati
 13141219    { work.Set(a); ContactQuadratic.Scale(work, b, result); }
 1220
 1221}

/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)
DoesCenteredCapsulePenetrate(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
.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&,System.Boolean)
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.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedPointAnchor&,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.Boolean&)
GetMatchedCapsuleSupportAnchor(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,System.Int32)
GetMatchedSupportCoordinate(FixedMathSharp.Signed576,FixedMathSharp.Signed320,FixedMathSharp.Fixed64,FixedMathSharp.Signed576,System.Boolean&)
.ctor(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
get_IsZero()
op_UnaryNegation(FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3)
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)
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&,System.Boolean)
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&)
CompareWideCapsuleRadicalToRational(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.Vector2d)
.ctor(FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Fixed64)
get_DoubleTimeScale()
.ctor(FixedMathSharp.Signed576,FixedMathSharp.Signed832)
TryGetCircleSlabSweepDistance(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
TryGetCircleSlabSweepDistance(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
TryGetCircleSlabSweepDistanceCore(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideOrientedBox/SweepTrajectory&,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.Geometry.WideOrientedBox/SweepTrajectory&,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
CompareExpandedEdgeAtHalf(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Fixed64,System.Int64,FixedMathSharp.Geometry.WideOrientedBox/SweepTrajectory&)
CompareExpandedEdgeAt(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Fixed64,FixedMathSharp.Signed192,FixedMathSharp.Signed192)
IsExactEdgeFeatureValid(System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint>,System.Int32,System.Int32,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideOrientedBox/SweepTrajectory&,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Fixed64)
TryGetRationalPointSweepDistance(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideOrientedBox/SweepTrajectory&,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
GetHalfToEvenIncrement(System.Int32,System.Int64)
CompareRationalPointAt(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192,FixedMathSharp.Signed192,System.Boolean)
GetSweepProjection(FixedMathSharp.Geometry.WideOrientedBox/SweepPlanarConstraint,FixedMathSharp.Geometry.WideOrientedBox/SweepTrajectory&)
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&)
DoesConvexHullCenteredCapsuleStrictlyOverlap(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)
TryFindHullCapsuleCandidate(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,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.Boolean,FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate&)
TryGetClosestHullSphereFeature(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Signed192,FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate&)
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&,System.Span`1<System.UInt64>,System.Int32&,System.Span`1<System.UInt64>,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&,System.Boolean)
GetHullTriangleNormal(System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.Int32)
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,FixedMathSharp.Signed576&)
.ctor(FixedMathSharp.Geometry.ScaledRigidFrame3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.RationalPoint3d&,FixedMathSharp.Geometry.RationalPoint3d&)
Point(System.Int32)
Endpoint(System.Boolean)
Relative(FixedMathSharp.Geometry.RationalPoint3d&,FixedMathSharp.Signed192)
Coordinate(FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
TryGetConvexHullCenteredCapsuleContact(FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,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&)
DoesConvexHullCenteredCapsuleStrictlyOverlap(FixedMathSharp.Geometry.ScaledRigidFrame3d&,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)
GetScaledHullCapsuleSupportAnchor(FixedMathSharp.Geometry.WideOrientedBox/ScaledHullCapsuleFrame&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.FixedPointAnchor&,FixedMathSharp.Geometry.FixedPointAnchor&)
IsScaledHullCapsuleSupport(FixedMathSharp.Geometry.WideOrientedBox/ScaledHullCapsuleFrame&,System.Int32,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
FindScaledHullCapsuleCandidate(FixedMathSharp.Geometry.WideOrientedBox/ScaledHullCapsuleFrame&,FixedMathSharp.Fixed64,System.Boolean,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate&)
EvaluateScaledHullCapsuleCandidate(FixedMathSharp.Geometry.WideOrientedBox/ScaledHullCapsuleFrame&,FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.Boolean&)
GetScaledHullCapsuleOverlapSign(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Signed576,FixedMathSharp.Fixed64)
BuildScaledHullCapsuleAxis(FixedMathSharp.Geometry.WideOrientedBox/ScaledHullCapsuleFrame&,FixedMathSharp.Geometry.WideOrientedBox/HullCapsuleCandidate,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
SetScaledHullCross(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
Subtract(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.WideDirection3d&)
CompareScaledHullValues(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
SetScaledHullVectorDot(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
SetScaledHullAxisDot(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
NormalizeScaledHullAxis(FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
.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.Signed704,FixedMathSharp.Signed704,FixedMathSharp.Signed704,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>)
ContainsHullSphereSupportProjection(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.WideRationalBasis3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WideOrientedBox/CapsuleAxis3,FixedMathSharp.Vector3d)
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&,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,System.Boolean,FixedMathSharp.Geometry.FixedPointAnchor&)
KeepHullCapsuleCoreMatch(FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedPointAnchor&,FixedMathSharp.Geometry.FixedPointAnchor&,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Boolean&,FixedMathSharp.Geometry.FixedTriangle&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
IsHullCapsuleSupportPoint(FixedMathSharp.Vector3d,FixedMathSharp.Signed704,FixedMathSharp.Signed704,FixedMathSharp.Signed704,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&)
GetHullCapsuleDepth(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed576,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,System.Boolean&)
CompareHullCapsuleDepthToTwiceRaw(System.ReadOnlySpan`1<System.UInt64>,System.Int32,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed576,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&)
TryGetConvexHullPenetration(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.WidePointSpanPenetration&,System.Boolean,FixedMathSharp.Geometry.PointSpanPenetrationAdmission,System.Boolean)
TryGetConvexHullPenetration(FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.WideRationalBasis3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WidePointSpanPenetration&,System.Boolean,FixedMathSharp.Geometry.PointSpanPenetrationAdmission,System.Boolean)
VisitConvexHullContacts(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.WidePointSpanPenetration&,TState,System.Action`2<TState,FixedMathSharp.Geometry.FixedContactAnchors>,FixedMathSharp.Geometry.IConvexHullContactDomain,System.Boolean)
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&,System.Boolean,System.Boolean&,FixedMathSharp.Geometry.PointSpanPenetrationAdmission)
GetLocalHullFaceAxis(System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.Int32)
IsFirstHullEdgeDirection(System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.Int32)
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&,System.Boolean&,FixedMathSharp.Geometry.PointSpanPenetrationAdmission)
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)
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.CenteredCylinderContactFeature&)
GetCylinderCapFace(FixedMathSharp.Geometry.WideAxis3,FixedMathSharp.Vector3d)
.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.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)
DoesCenteredCylinderPenetrateBox(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d)
DoesCenteredCylinderPenetrateTriangle(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion)
DoesCenteredCylinderPenetrateConvexHull(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.Boolean)
DoesCenteredCylinderPenetrateTriangle(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Geometry.ScaledRigidFrame3d&)
DoesCenteredCylinderPenetrateConvexHull(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.ScaledRigidFrame3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.Boolean)
IsStrictCylinderBoxCoordinateInside(FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Signed192)
IsCylinderCenterStrictlyInsideHull(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.Boolean)
ContainsConvexHullPoint(FixedMathSharp.Geometry.ScaledRigidFrame3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Vector3d,System.Boolean)
DoesCylinderTrianglePenetrate(FixedMathSharp.Geometry.CylinderPolytopeFrame&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&)
IsCylinderAxisInsideTriangleProjection(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320,FixedMathSharp.Signed320)
GetCylinderRadialCross(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&)
DoesCylinderClippedEdgePenetrate(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Geometry.CylinderPolytopeFrame&)
GetCylinderClippedEndpoint(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320,FixedMathSharp.Signed320,FixedMathSharp.Signed192)
GetCylinderRadialPoint(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed192)
GetCylinderPlaneIntersection(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320,FixedMathSharp.Signed192)
DoesCylinderCapSectionPenetrate(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320,FixedMathSharp.Geometry.CylinderPolytopeFrame&)
AddCylinderPlaneIntersection(FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Geometry.WideAxis3&,FixedMathSharp.Signed320,FixedMathSharp.Signed192,System.Span`1<FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint>,System.Int32&)
IsCylinderRadialPointInside(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint&,FixedMathSharp.Signed192)
IsCylinderRadialSegmentInside(FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint&,FixedMathSharp.Geometry.WideOrientedBox/SweepRationalPoint&,FixedMathSharp.Signed192)
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/TriangleSweepPoint,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepPoint,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideOrientedBox/SweepTrajectory&,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Vector3d&,FixedMathSharp.Signed576&)
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)
TryGetExactRationalSegmentWitness(FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepPoint,FixedMathSharp.Geometry.WideOrientedBox/TriangleSweepPoint,FixedMathSharp.Signed832,FixedMathSharp.Signed832,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Signed576,FixedMathSharp.Signed576,System.ReadOnlySpan`1<System.UInt64>,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Geometry.WideOrientedBox/SweepTrajectory&,FixedMathSharp.Fixed64,System.Boolean,FixedMathSharp.Vector3d&,FixedMathSharp.Signed576&)
RoundRationalSegmentCoordinate(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
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,System.Boolean)
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,System.Boolean)
IsRigidPointLineWithinRadius(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed704,FixedMathSharp.Signed576,FixedMathSharp.Signed192,System.Boolean)
IsRigidPointWithinRadius(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed192,System.Boolean)
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)
.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&)
get_BoxHullTriangles()
get_BoxHullEdges()
GetBoxHullVertices(FixedMathSharp.Vector3d,System.Span`1<FixedMathSharp.Vector3d>)
TryGetConvexHullContact(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.FixedContactAnchors&)
TryGetConvexHullContact(FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.FixedContactAnchors&)
VisitConvexHullContacts(FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WideScaledHullPenetration&,TState,System.Action`2<TState,FixedMathSharp.Geometry.FixedContactAnchors>,FixedMathSharp.Geometry.IScaledConvexHullContactDomain,System.Boolean)
VisitConvexHullContacts(TFirstFrame&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,TSecondFrame&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WideScaledHullPenetration&,TState,System.Action`2<TState,FixedMathSharp.Geometry.FixedContactAnchors>,FixedMathSharp.Geometry.IScaledConvexHullContactDomain,System.Boolean)
VisitProjectedHullRectangleContacts(TSourceFrame&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,TRectangleFrame&,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.FixedTriangle&,FixedMathSharp.Geometry.RationalSegmentInterval&,FixedMathSharp.Geometry.WideScaledHullPenetration&,TState,System.Action`2<TState,FixedMathSharp.Geometry.FixedContactAnchors>,System.Boolean)
VisitScaledHullSide(TSourceFrame&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,TTargetFrame&,FixedMathSharp.Vector3d,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Boolean,TState,System.Action`2<TState,FixedMathSharp.Geometry.FixedContactAnchors>,FixedMathSharp.Geometry.IScaledConvexHullContactDomain,System.Boolean,System.Boolean,System.Boolean&)
HasScaledHullEdge(System.Int32,System.Int32,System.ReadOnlySpan`1<System.Int32>)
GetScaledHullSupport(TFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Geometry.WideDirection3d&,System.Boolean)
IsScaledHullSupport(FixedMathSharp.Geometry.RationalPoint3d&,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Signed832)
IntersectScaledHullInterval(FixedMathSharp.Geometry.RationalSegmentInterval&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
TryGetConvexHullPenetration(FixedMathSharp.Geometry.ScaledRigidFrame3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.ScaledRigidFrame3d&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WideScaledHullPenetration&,System.Boolean,FixedMathSharp.Geometry.ScaledHullPenetrationAdmission,System.Boolean)
TryGetConvexHullPenetration(TFirstFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,TSecondFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,FixedMathSharp.Geometry.WideScaledHullPenetration&,System.Boolean,FixedMathSharp.Geometry.ScaledHullPenetrationAdmission,System.Boolean)
TryKeepScaledHullFaceAxes(TFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,System.ReadOnlySpan`1<System.Int32>,System.ReadOnlySpan`1<System.Int32>,TFirstFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,TSecondFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Signed576,FixedMathSharp.Geometry.WideScaledHullPenetration&,System.Boolean&,System.Boolean,FixedMathSharp.Geometry.ScaledHullPenetrationAdmission,System.Boolean)
TryKeepScaledHullAxis(FixedMathSharp.Geometry.WideDirection3d&,TFirstFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,TSecondFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Signed576,FixedMathSharp.Geometry.WideScaledHullPenetration&,System.Boolean&,FixedMathSharp.Geometry.ScaledHullPenetrationAdmission)
GetScaledHullProjection(TFrame&,System.ReadOnlySpan`1<FixedMathSharp.Vector3d>,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Signed192,FixedMathSharp.Signed832&,FixedMathSharp.Signed832&)
ProjectScaledHullPoint(FixedMathSharp.Geometry.RationalPoint3d&,FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Signed192)
DoesSpherePenetrate(FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,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)
.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&)
TryGetFiniteSlabProjectedCircleSweep(FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Geometry.FixedSegment2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Geometry.FixedPointAnchor&)
TryGetFiniteSlabProjectedCircleSweepCore(FixedMathSharp.Geometry.FixedTriangle,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.WideOrientedBox/SweepTrajectory&,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.Geometry.WideOrientedBox/SweepTrajectory&,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.Geometry.WideOrientedBox/SweepTrajectory&,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.Geometry.WideOrientedBox/SweepTrajectory&,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)
TryGetFiniteSlabProjectedCircleSweep(FixedMathSharp.Geometry.FixedTriangle&,FixedMathSharp.Geometry.ScaledRigidFrame3d&,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.FixedSegment2d&,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&,FixedMathSharp.Geometry.FixedPointAnchor&)
AffineSlabField(System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Int32)
TryGetAffineSlabSweepInterior(System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,FixedMathSharp.Signed320,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Geometry.FixedPointAnchor&)
KeepAffineSlabSweepFeature(System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,FixedMathSharp.Signed320,FixedMathSharp.Geometry.WideDirection3d&,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,FixedMathSharp.Signed192,FixedMathSharp.Signed192,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Int32,System.Span`1<System.UInt64>,System.Span`1<System.Int32>,System.Span`1<System.UInt64>,System.Boolean&)
ContainsAffineSlabSweepFace(System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,System.ReadOnlySpan`1<FixedMathSharp.Geometry.WideDirection3d>,FixedMathSharp.Signed320,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,System.ReadOnlySpan`1<System.UInt64>,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
ReduceAffineSlabDirection(FixedMathSharp.Geometry.WideDirection3d&)
AffineSlabDifference(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.WideDirection3d&)
AffineSlabDot(FixedMathSharp.Geometry.WideDirection3d&,FixedMathSharp.Geometry.WideDirection3d&)
AffineSlabCross(FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576,FixedMathSharp.Signed576)
AffineSlabNegate(FixedMathSharp.Signed832)
AffineSlabProduct(FixedMathSharp.Signed832,FixedMathSharp.Signed832,FixedMathSharp.Geometry.ContactQuadratic,FixedMathSharp.Geometry.ContactQuadratic)
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&)