using XFEExtension.NetCore.XUnit.Attributes; using XFEEDToolBox.Core.Galaxy; namespace XFEEDToolBox.Test; [TestFixture] public class GalaxyOriginalCameraSmoothingTests { static void Near(double expected, double actual, double tolerance = 1e-9) => Check.That(Math.Abs(expected - actual) <= tolerance, $"Expected {expected}, actual {actual}"); [Test] public void OriginalNormalUpdateUsesFourIndependentChannelsAndGeometricZoom() { var actual = new GalaxyCameraPose(new(100, -2, 300), -.5, .25, 10); var target = new GalaxyCameraPose(new(120, 3, 260), .5, -.75, 320); var next = GalaxyOriginalCameraControls.Smooth(actual, target); Near(106.00000023841858, next.Focus.X); Near(-.4999999403953552, next.Focus.Y); Near(287.99999952316284, next.Focus.Z); Near(-.29999999701976776, next.Yaw); Near(.04999999701976776, next.Pitch); Near(20.00000020657396, next.Distance, 1e-8); Check.That(next.Distance < 30); // Arithmetic-distance interpolation would be 72. } [Test] public void TargetFloorSettlesWhileActualHeightRemainsContinuous() { var actual = new GalaxyCameraPose(new(4, 2.75, 6), 0, 0, 20); var target = GalaxyOriginalCameraControls.PrepareTarget(actual, false, 0); Near(3, target.Focus.Y); var next = GalaxyOriginalCameraControls.Smooth(actual, target); Near(2.8250000029802322, next.Focus.Y); Check.That(next.Focus.Y != target.Focus.Y); Check.That(GalaxyOriginalCameraControls.PrepareTarget(actual, true, 0).Focus == actual.Focus); Check.That(GalaxyOriginalCameraControls.PrepareTarget(actual, false, -.01).Focus == actual.Focus); } [Test] public void OriginalDegreeMetadataClampsPitchAndLightYearDistanceOnlyOnTarget() { var high = GalaxyOriginalCameraControls.PrepareTarget(new(new(1, 0, 2), 100, 2, 100000), false, 0); var low = GalaxyOriginalCameraControls.PrepareTarget(new(new(1, 0, 2), -100, -2, .1), false, 0); Near((double)(80f * .01745329238474369f), high.Pitch); Near(-high.Pitch, low.Pitch); Near(25000, high.Distance); Near(6, low.Distance); Near(100, high.Yaw); Near(-100, low.Yaw); Near((double)(45f * .01745329238474369f), GalaxyOriginalCameraControls.DefaultPitch); } [Test] public void YawFollowsOriginalUnwrappedDeltaAndCallerToleranceIsExplicit() { var actual = new GalaxyCameraPose(new(0, 0, 0), 6, 0, 20); var target = new GalaxyCameraPose(new(1, 0, 0), 0, 1, 21); var next = GalaxyOriginalCameraControls.Smooth(actual, target); Near(4.799999982118607, next.Yaw); Check.That(next.Focus != target.Focus && next.Distance != target.Distance); Check.That(GalaxyOriginalCameraControls.Smooth(actual, target, new(1, 7, 2)) == target); Check.That(GalaxyOriginalCameraControls.Smooth(target, target) == target); } [Test] public void MultipleUpdatesApplyPerTickFactorsWithoutElapsedTimeScaling() { var actual = new GalaxyCameraPose(new(0, 0, 0), 0, 0, 10); var target = new GalaxyCameraPose(new(100, 0, 0), 1, 1, 1000); for (var index = 0; index < 5; index++) actual = GalaxyOriginalCameraControls.Smooth(actual, target); Near(100 * (1 - Math.Pow(1 - (double).3f, 5)), actual.Focus.X); var angular = 1 - Math.Pow(1 - (double).2f, 5); Near(angular, actual.Yaw); Near(angular, actual.Pitch); Near(10 * Math.Pow(100, angular), actual.Distance, 1e-8); } [Test] public void InvalidPoseAndInventedNegativeStopThresholdCannotEnterCameraState() { var valid = new GalaxyCameraPose(new(0, 0, 0), 0, 0, 10); Check.Throws(() => GalaxyOriginalCameraControls.Smooth(default, valid)); Check.Throws(() => GalaxyOriginalCameraControls.Smooth(valid, valid with { Distance = 0 })); Check.Throws(() => GalaxyOriginalCameraControls.Smooth(valid, valid with { Pitch = double.NaN })); Check.Throws(() => GalaxyOriginalCameraControls.Smooth(valid, valid, new(-1, 0, 0))); Check.Throws(() => GalaxyOriginalCameraControls.PrepareTarget(valid, false, double.NaN)); } }