using System.Numerics; using AcDream.Core.Physics; using AcDream.Core.Physics.Motion; using Xunit; namespace AcDream.Core.Tests.Physics.Motion; /// /// R4-V1 — Position::cylinder_distance, the pure-math shape per /// r4-moveto-decomp.md §5a (MoveToManager::GetCurrentDistance, /// 005291b0): edge-to-edge distance between two vertical cylinders /// (own radius/height, target radius/height, both positions). Object moves /// (use_spheres set on the wire) use this; position moves use plain /// Euclidean Position::distance (§5a: "position moves use center /// distance" — is the object-move /// variant only; center distance is Vector3.Distance, already /// available, not re-ported here). /// /// /// The exact branch structure is visible at named-retail /// Position::cylinder_distance @ 0x005A97F0 and independently matches /// ACE Physics.Common.Position.CylinderDistance. It uses full 3D center /// distance, both radii, both heights, and returns signed overlap. /// /// public sealed class MoveToMathCylinderDistanceTests { [Fact] public void TwoCylinders_HorizontallySeparated_SubtractsBothRadii() { // centers 10 units apart on X, radii 1 and 2 → edge distance = 10-1-2=7 float d = MoveToMath.CylinderDistance( ownRadius: 1f, ownHeight: 2f, ownPos: Vector3.Zero, targetRadius: 2f, targetHeight: 2f, targetPos: new Vector3(10f, 0f, 0f)); Assert.Equal(7f, d, 3); } [Fact] public void TwoCylinders_Overlapping_ReturnsSignedThreeDimensionalOverlap() { // radial gap = 1 - 10 = -9; vertical gap = 0 - 2 = -2. float d = MoveToMath.CylinderDistance( ownRadius: 5f, ownHeight: 2f, ownPos: Vector3.Zero, targetRadius: 5f, targetHeight: 2f, targetPos: new Vector3(1f, 0f, 0f)); Assert.Equal(-MathF.Sqrt(85f), d, 3); } [Fact] public void TwoCylinders_ZeroRadii_ReducesToCenterDistance() { float d = MoveToMath.CylinderDistance( ownRadius: 0f, ownHeight: 2f, ownPos: Vector3.Zero, targetRadius: 0f, targetHeight: 2f, targetPos: new Vector3(3f, 4f, 0f)); Assert.Equal(5f, d, 3); // 3-4-5 triangle } [Fact] public void TwoCylinders_VerticallyAndRadiallySeparated_CombinesBothGaps() { // full center gap = 5, radial gap = 3; vertical gap = 4 - 2 = 2. float d = MoveToMath.CylinderDistance( ownRadius: 1f, ownHeight: 2f, ownPos: Vector3.Zero, targetRadius: 1f, targetHeight: 2f, targetPos: new Vector3(3f, 0f, 4f)); Assert.Equal(MathF.Sqrt(13f), d, 3); } [Fact] public void SamePosition_ReturnsSignedOverlap() { float d = MoveToMath.CylinderDistance( ownRadius: 0.5f, ownHeight: 2f, ownPos: Vector3.Zero, targetRadius: 0.5f, targetHeight: 2f, targetPos: Vector3.Zero); Assert.Equal(-MathF.Sqrt(5f), d, 3); } [Fact] public void OppositeGapSigns_ReturnsRadialGapVerbatim() { float d = MoveToMath.CylinderDistance( ownRadius: 5f, ownHeight: 1f, ownPos: Vector3.Zero, targetRadius: 5f, targetHeight: 1f, targetPos: new Vector3(0f, 0f, 3f)); Assert.Equal(-7f, d, 3); } }