diff --git a/Easing/Easing.cs b/Easing/Easing.cs index ee5233b..96718a4 100644 --- a/Easing/Easing.cs +++ b/Easing/Easing.cs @@ -602,11 +602,12 @@ namespace MoonTools.Core.Easing public static double OutInCirc(double time, double start, double end) => TimeRange(OutInCirc, time, start, end); public static double OutInCirc(double t, double b, double c, double d) => OutIn(OutCirc, InCirc, t, b, c, d); - // IN ELASTIC - + // ELASTIC functions have two optional extra arguments // a: amplitude // p: period + // IN ELASTIC + public static double InElasticNormalized(double t) => InElastic(t, 0, 1, 1); public static double InElasticNormalized(double t, double a) => InElastic(t, 0, 1, 1, a); public static double InElasticNormalized(double t, double a, double p) => InElastic(t, 0, 1, 1, a, p); @@ -679,5 +680,147 @@ namespace MoonTools.Core.Easing return a.Value * Math.Pow(2, -10 * t) * Math.Sin((t * d - s) * (2 * Math.PI) / p.Value) + c + b; } + + // IN OUT ELASTIC + + public static double InOutElasticNormalized(double t) => InOutElastic(t, 0, 1, 1); + public static double InOutElasticNormalized(double t, double a) => InOutElastic(t, 0, 1, 1, a); + public static double InOutElasticNormalized(double t, double a, double p) => InOutElastic(t, 0, 1, 1, a, p); + + public static double InOutElasticTimeRange(double time, double start, double end) => start + (end - start) * InOutElasticNormalized((time - start) / (end - start)); + public static double InOutElasticTimeRange(double time, double start, double end, double a) => start + (end - start) * InOutElasticNormalized((time - start) / (end - start), a); + public static double InOutElasticTimeRange(double time, double start, double end, double a, double p) => start + (end - start) * InOutElasticNormalized((time - start) / (end - start), a, p); + + public static double InOutElastic(double t, double b, double c, double d, double? a = null, double? p = null) + { + CheckTime(t, d); + + if (t == 0) { return b; } + + t = t / d * 2; + + if (t == 2) { return b + c; } + + if (!p.HasValue) { p = d * (0.3 * 1.5); } + if (!a.HasValue) { a = 0; } + + double s; + + if (!a.HasValue || a < Math.Abs(c)) + { + a = c; + s = p.Value / 4; + } + else + { + s = p.Value / (2 * Math.PI) * Math.Asin(c / a.Value); + } + + if (t < 1) + { + t = t - 1; + return -0.5 * (a.Value * Math.Pow(2, 10 * t) * Math.Sin((t * d - s) * (2 * Math.PI) / p.Value)) + b; + } + else + { + t = t - 1; + return a.Value * Math.Pow(2, -10 * t) * Math.Sin((t * d - s) * (2 * Math.PI) / p.Value) * 0.5 + c + b; + } + } + + // OUT IN ELASTIC + + public static double OutInElasticNormalized(double t) => OutInElastic(t, 0, 1, 1); + public static double OutInElasticNormalized(double t, double a) => OutInElastic(t, 0, 1, 1, a); + public static double OutInElasticNormalized(double t, double a, double p) => OutInElastic(t, 0, 1, 1, a, p); + + public static double OutInElasticTimeRange(double time, double start, double end) => start + (end - start) * OutInElasticNormalized((time - start) / (end - start)); + public static double OutInElasticTimeRange(double time, double start, double end, double a) => start + (end - start) * OutInElasticNormalized((time - start) / (end - start), a); + public static double OutInElasticTimeRange(double time, double start, double end, double a, double p) => start + (end - start) * OutInElasticNormalized((time - start) / (end - start), a, p); + + public static double OutInElastic(double t, double b, double c, double d, double? a = null, double? p = null) + { + if (t < d / 2) + { + return OutElastic(t * 2, b, c / 2, d, a, p); + } + else + { + return InElastic((t * 2) - d, b + c / 2, c / 2, d, a, p); + } + } + + // back functions take an optional parameter + // s: size + + // IN BACK + + public static double InBackNormalized(double t) => InBack(t, 0, 1, 1); + public static double InBackNormalized(double t, double s) => InBack(t, 0, 1, 1, s); + public static double InBackTimeRange(double time, double start, double end) => start + (end - start) * InBackNormalized((time - start) / (end - start)); + public static double InBackTimeRange(double time, double start, double end, double s) => start + (end - start) * InBackNormalized((time - start) / (end - start), s); + + public static double InBack(double t, double b, double c, double d, double s = 1.70158) + { + CheckTime(t, d); + t = t / d; + return c * t * t * ((s + 1) * t - s) + b; + } + + // OUT BACK + + public static double OutBackNormalized(double t) => OutBack(t, 0, 1, 1); + public static double OutBackNormalized(double t, double s) => OutBack(t, 0, 1, 1, s); + public static double OutBackTimeRange(double time, double start, double end) => start + (end - start) * OutBackNormalized((time - start) / (end - start)); + public static double OutBackTimeRange(double time, double start, double end, double s) => start + (end - start) * OutBackNormalized((time - start) / (end - start), s); + + public static double OutBack(double t, double b, double c, double d, double s = 1.70158) + { + CheckTime(t, d); + t = t / d - 1; + return c * (t * t * ((s + 1) * t + s) + 1) + b; + } + + // IN OUT BACK + + public static double InOutBackNormalized(double t) => InOutBack(t, 0, 1, 1); + public static double InOutBackNormalized(double t, double s) => InOutBack(t, 0, 1, 1, s); + public static double InOutBackTimeRange(double time, double start, double end) => start + (end - start) * InOutBackNormalized((time - start) / (end - start)); + public static double InOutBackTimeRange(double time, double start, double end, double s) => start + (end - start) * InOutBackNormalized((time - start) / (end - start), s); + + public static double InOutBack(double t, double b, double c, double d, double s = 1.70158) + { + CheckTime(t, d); + s = s * 1.525; + t = t / d * 2; + if (t < 1) + { + return c / 2 * (t * t * ((s + 1) * t - s)) + b; + } + else + { + t = t - 2; + return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b; + } + } + + // OUT IN BACK + + public static double OutInBackNormalized(double t) => OutInBack(t, 0, 1, 1); + public static double OutInBackNormalized(double t, double s) => OutInBack(t, 0, 1, 1, s); + public static double OutInBackTimeRange(double time, double start, double end) => start + (end - start) * OutInBackNormalized((time - start) / (end - start)); + public static double OutInBackTimeRange(double time, double start, double end, double s) => start + (end - start) * OutInBackNormalized((time - start) / (end - start), s); + + public static double OutInBack(double t, double b, double c, double d, double s = 1.70158) + { + if (t < d / 2) + { + return OutBack(t * 2, b, c / 2, d, s); + } + else + { + return InBack((t * 2) - d, b + c / 2, c / 2, d, s); + } + } } } diff --git a/Test/Easing.cs b/Test/Easing.cs index 17cb4ec..e3046a1 100644 --- a/Test/Easing.cs +++ b/Test/Easing.cs @@ -902,7 +902,7 @@ namespace Test Easing.InElasticTimeRange(4, 2, 6).Should().BeApproximately(1.9375, 0.001); Easing.InElasticTimeRange(5, 2, 6).Should().BeApproximately(2.35355339059, 0.001); - CheckDoubleArguments(Easing.InElasticNormalized, Easing.InElasticNormalized); + CheckDoubleArguments(Easing.InElasticNormalized, Easing.InElasticTimeRange); } [Test] @@ -940,7 +940,7 @@ namespace Test Easing.OutElasticTimeRange(4, 2, 6).Should().BeApproximately(6.0625, 0.001); Easing.OutElasticTimeRange(5, 2, 6).Should().BeApproximately(6.02209708691, 0.001); - CheckDoubleArguments(Easing.OutElasticNormalized, Easing.OutElasticNormalized); + CheckDoubleArguments(Easing.OutElasticNormalized, Easing.OutElasticTimeRange); } [Test] @@ -966,6 +966,186 @@ namespace Test Easing.OutElasticTimeRange(4, 2, 6, 10, 0.5).Should().BeApproximately(5.875, 0.001); Easing.OutElasticTimeRange(5, 2, 6, 10, 0.5).Should().BeApproximately(6.02209708691, 0.001); } + + [Test] + public void InOutElasticDefault() + { + Easing.InOutElasticNormalized(0.25).Should().BeApproximately(0.011969444423734, 0.001); + Easing.InOutElasticNormalized(0.5).Should().BeApproximately(0.5, 0.001); + Easing.InOutElasticNormalized(0.75).Should().BeApproximately(0.98803055557627, 0.001); + + Easing.InOutElasticTimeRange(3, 2, 6).Should().BeApproximately(2.0478777777, 0.001); + Easing.InOutElasticTimeRange(4, 2, 6).Should().BeApproximately(4, 0.001); + Easing.InOutElasticTimeRange(5, 2, 6).Should().BeApproximately(5.9521222223, 0.001); + + CheckDoubleArguments(Easing.InOutElasticNormalized, Easing.InOutElasticTimeRange); + } + + [Test] + public void InOutElasticWithA() + { + Easing.InOutElasticNormalized(0.25, 10).Should().BeApproximately(0.11190156885591, 0.001); + Easing.InOutElasticNormalized(0.5, 10).Should().BeApproximately(0.5, 0.001); + Easing.InOutElasticNormalized(0.75, 10).Should().BeApproximately(1.0879626800084, 0.001); + + Easing.InOutElasticTimeRange(3, 2, 6, 10).Should().BeApproximately(2.44760627542, 0.001); + Easing.InOutElasticTimeRange(4, 2, 6, 10).Should().BeApproximately(4, 0.001); + Easing.InOutElasticTimeRange(5, 2, 6, 10).Should().BeApproximately(6.35185072004, 0.001); + } + + [Test] + public void InOutElasticWithAAndP() + { + Easing.InOutElasticNormalized(0.25, 10, 0.5).Should().BeApproximately(0.015625, 0.001); + Easing.InOutElasticNormalized(0.5, 10, 0.5).Should().BeApproximately(0.5, 0.001); + Easing.InOutElasticNormalized(0.75, 10, 0.5).Should().BeApproximately(0.984375, 0.001); + + Easing.InOutElasticTimeRange(3, 2, 6, 10, 0.5).Should().BeApproximately(2.0625, 0.001); + Easing.InOutElasticTimeRange(4, 2, 6, 10, 0.5).Should().BeApproximately(4, 0.001); + Easing.InOutElasticTimeRange(5, 2, 6, 10, 0.5).Should().BeApproximately(5.9375, 0.001); + } + + [Test] + public void OutInElasticDefault() + { + Easing.OutInElasticNormalized(0.25).Should().BeApproximately(0.5078125, 0.001); + Easing.OutInElasticNormalized(0.5).Should().BeApproximately(0.5, 0.001); + Easing.OutInElasticNormalized(0.75).Should().BeApproximately(0.4921875, 0.001); + + Easing.OutInElasticTimeRange(3, 2, 6).Should().BeApproximately(4.03125, 0.001); + Easing.OutInElasticTimeRange(4, 2, 6).Should().BeApproximately(4, 0.001); + Easing.OutInElasticTimeRange(5, 2, 6).Should().BeApproximately(3.96875, 0.001); + + CheckDoubleArguments(Easing.OutInElasticNormalized, Easing.OutInElasticTimeRange); + } + + [Test] + public void OutInElasticWithA() + { + Easing.OutInElasticNormalized(0.25, 10).Should().BeApproximately(0.2375180641874, 0.001); + Easing.OutInElasticNormalized(0.5, 10).Should().BeApproximately(0.5, 0.001); + Easing.OutInElasticNormalized(0.75, 10).Should().BeApproximately(0.2218930641874, 0.001); + + Easing.OutInElasticTimeRange(3, 2, 6, 10).Should().BeApproximately(2.95007225675, 0.001); + Easing.OutInElasticTimeRange(4, 2, 6, 10).Should().BeApproximately(4, 0.001); + Easing.OutInElasticTimeRange(5, 2, 6, 10).Should().BeApproximately(2.88757225675, 0.001); + } + + [Test] + public void OutInElasticWithAAndP() + { + Easing.OutInElasticNormalized(0.25, 10, 0.5).Should().BeApproximately(0.484375, 0.001); + Easing.OutInElasticNormalized(0.5, 10, 0.5).Should().BeApproximately(0.5, 0.001); + Easing.OutInElasticNormalized(0.75, 10, 0.5).Should().BeApproximately(0.515625, 0.001); + + Easing.OutInElasticTimeRange(3, 2, 6, 10, 0.5).Should().BeApproximately(3.9375, 0.001); + Easing.OutInElasticTimeRange(4, 2, 6, 10, 0.5).Should().BeApproximately(4, 0.001); + Easing.OutInElasticTimeRange(5, 2, 6, 10, 0.5).Should().BeApproximately(4.0625, 0.001); + } + + [Test] + public void InBackDefault() + { + Easing.InBackNormalized(0.25).Should().BeApproximately(-0.0641365625, 0.001); + Easing.InBackNormalized(0.5).Should().BeApproximately(-0.0876975, 0.001); + Easing.InBackNormalized(0.75).Should().BeApproximately(0.1825903125, 0.001); + + Easing.InBackTimeRange(3, 2, 6).Should().BeApproximately(1.74345375, 0.001); + Easing.InBackTimeRange(4, 2, 6).Should().BeApproximately(1.64921, 0.001); + Easing.InBackTimeRange(5, 2, 6).Should().BeApproximately(2.73036125, 0.001); + + CheckDoubleArguments(Easing.InBackNormalized, Easing.InBackTimeRange); + } + + [Test] + public void InBackWithSize() + { + Easing.InBackNormalized(0.25, 3).Should().BeApproximately(-0.125, 0.001); + Easing.InBackNormalized(0.5, 3).Should().BeApproximately(-0.25, 0.001); + Easing.InBackNormalized(0.75, 3).Should().BeApproximately(0, 0.001); + + Easing.InBackTimeRange(3, 2, 6, 3).Should().BeApproximately(1.5, 0.001); + Easing.InBackTimeRange(4, 2, 6, 3).Should().BeApproximately(1, 0.001); + Easing.InBackTimeRange(5, 2, 6, 3).Should().BeApproximately(2, 0.001); + } + + [Test] + public void OutBackDefault() + { + Easing.OutBackNormalized(0.25).Should().BeApproximately(0.8174096875, 0.001); + Easing.OutBackNormalized(0.5).Should().BeApproximately(1.0876975, 0.001); + Easing.OutBackNormalized(0.75).Should().BeApproximately(1.0641365625, 0.001); + + Easing.OutBackTimeRange(3, 2, 6).Should().BeApproximately(5.26963875, 0.001); + Easing.OutBackTimeRange(4, 2, 6).Should().BeApproximately(6.35079, 0.001); + Easing.OutBackTimeRange(5, 2, 6).Should().BeApproximately(6.25654625, 0.001); + + CheckDoubleArguments(Easing.OutBackNormalized, Easing.OutBackTimeRange); + } + + [Test] + public void OutBackWithSize() + { + Easing.OutBackNormalized(0.25, 3).Should().BeApproximately(1, 0.001); + Easing.OutBackNormalized(0.5, 3).Should().BeApproximately(1.25, 0.001); + Easing.OutBackNormalized(0.75, 3).Should().BeApproximately(1.125, 0.001); + + Easing.OutBackTimeRange(3, 2, 6, 3).Should().BeApproximately(6, 0.001); + Easing.OutBackTimeRange(4, 2, 6, 3).Should().BeApproximately(7, 0.001); + Easing.OutBackTimeRange(5, 2, 6, 3).Should().BeApproximately(6.5, 0.001); + } + + [Test] + public void InOutBackDefault() + { + Easing.InOutBackNormalized(0.25).Should().BeApproximately(-0.09968184375, 0.001); + Easing.InOutBackNormalized(0.5).Should().BeApproximately(0.5, 0.001); + Easing.InOutBackNormalized(0.75).Should().BeApproximately(1.09968184375, 0.001); + + Easing.InOutBackTimeRange(3, 2, 6).Should().BeApproximately(1.601272625, 0.001); + Easing.InOutBackTimeRange(4, 2, 6).Should().BeApproximately(4, 0.001); + Easing.InOutBackTimeRange(5, 2, 6).Should().BeApproximately(6.398727375, 0.001); + + CheckDoubleArguments(Easing.InOutBackNormalized, Easing.InOutBackTimeRange); + } + + [Test] + public void InOutBackWithSize() + { + Easing.InOutBackNormalized(0.25, 3).Should().BeApproximately(-0.2234375, 0.001); + Easing.InOutBackNormalized(0.5, 3).Should().BeApproximately(0.5, 0.001); + Easing.InOutBackNormalized(0.75, 3).Should().BeApproximately(1.2234375, 0.001); + + Easing.InOutBackTimeRange(3, 2, 6, 3).Should().BeApproximately(1.10625, 0.001); + Easing.InOutBackTimeRange(4, 2, 6, 3).Should().BeApproximately(4, 0.001); + Easing.InOutBackTimeRange(5, 2, 6, 3).Should().BeApproximately(6.89375, 0.001); + } + + [Test] + public void OutInBackDefault() + { + Easing.OutInBackNormalized(0.25).Should().BeApproximately(0.54384875, 0.001); + Easing.OutInBackNormalized(0.5).Should().BeApproximately(0.5, 0.001); + Easing.OutInBackNormalized(0.75).Should().BeApproximately(0.45615125, 0.001); + + Easing.OutInBackTimeRange(3, 2, 6).Should().BeApproximately(4.175395, 0.001); + Easing.OutInBackTimeRange(4, 2, 6).Should().BeApproximately(4, 0.001); + Easing.OutInBackTimeRange(5, 2, 6).Should().BeApproximately(3.824605, 0.001); + + CheckDoubleArguments(Easing.OutInBackNormalized, Easing.OutInBackTimeRange); + } + + [Test] + public void OutInBackWithSize() + { + Easing.OutInBackNormalized(0.25, 3).Should().BeApproximately(0.625, 0.001); + Easing.OutInBackNormalized(0.5, 3).Should().BeApproximately(0.5, 0.001); + Easing.OutInBackNormalized(0.75, 3).Should().BeApproximately(0.375, 0.001); + + Easing.OutInBackTimeRange(3, 2, 6, 3).Should().BeApproximately(4.5, 0.001); + Easing.OutInBackTimeRange(4, 2, 6, 3).Should().BeApproximately(4, 0.001); + Easing.OutInBackTimeRange(5, 2, 6, 3).Should().BeApproximately(3.5, 0.001); + } } } } \ No newline at end of file