diff --git a/Easing/Easing.cs b/Easing/Easing.cs index 6b4e512..27f598c 100644 --- a/Easing/Easing.cs +++ b/Easing/Easing.cs @@ -20,9 +20,43 @@ namespace MoonTools.Core.Easing private static float NormalizedTime(Func easingFunction, float t) => easingFunction(t, 0, 1, 1); private static float TimeRange(Func easingFunction, float time, float start, float end) => start + (end - start) * easingFunction((time - start) / (end - start)); + private static float OutIn(Func outFunc, + Func inFunc, + float t, + float b, + float c, + float d) + { + if (t < d / 2) + { + return outFunc(t * 2, b, c / 2, d); + } + else + { + return inFunc((t * 2) - d, b + c / 2, c / 2, d); + } + } + private static double NormalizedTime(Func easingFunction, double t) => easingFunction(t, 0, 1, 1); private static double TimeRange(Func easingFunction, double time, double start, double end) => start + (end - start) * easingFunction((time - start) / (end - start)); + private static double OutIn(Func outFunc, + Func inFunc, + double t, + double b, + double c, + double d) + { + if (t < d / 2) + { + return outFunc(t * 2, b, c / 2, d); + } + else + { + return inFunc((t * 2) - d, b + c / 2, c / 2, d); + } + } + /********* EASING FUNCTIONS ********/ // LINEAR @@ -129,35 +163,11 @@ namespace MoonTools.Core.Easing public static float OutInQuad(float t) => NormalizedTime(OutInQuad, t); public static float OutInQuad(float time, float start, float end) => TimeRange(OutInQuad, time, start, end); - - public static float OutInQuad(float t, float b, float c, float d) - { - CheckTime(t, d); - if (t < d / 2) - { - return OutQuad(t * 2, b, c / 2, d); - } - else - { - return InQuad((t * 2) - d, b + c / 2, c / 2, d); - } - } + public static float OutInQuad(float t, float b, float c, float d) => OutIn(OutQuad, InQuad, t, b, c, d); public static double OutInQuad(double t) => NormalizedTime(OutInQuad, t); public static double OutInQuad(double time, double start, double end) => TimeRange(OutInQuad, time, start, end); - - public static double OutInQuad(double t, double b, double c, double d) - { - CheckTime(t, d); - if (t < d / 2) - { - return OutQuad(t * 2, b, c / 2, d); - } - else - { - return InQuad((t * 2) - d, b + c / 2, c / 2, d); - } - } + public static double OutInQuad(double t, double b, double c, double d) => OutIn(OutQuad, InQuad, t, b, c, d); // IN CUBIC @@ -247,33 +257,11 @@ namespace MoonTools.Core.Easing public static float OutInCubic(float t) => NormalizedTime(OutInCubic, t); public static float OutInCubic(float time, float start, float end) => TimeRange(OutInCubic, time, start, end); - - public static float OutInCubic(float t, float b, float c, float d) - { - if (t < d / 2) - { - return OutCubic(t * 2, b, c / 2, d); - } - else - { - return InCubic((t * 2) - d, b + c / 2, c / 2, d); - } - } + public static float OutInCubic(float t, float b, float c, float d) => OutIn(OutCubic, InCubic, t, b, c, d); public static double OutInCubic(double t) => NormalizedTime(OutInCubic, t); public static double OutInCubic(double time, double start, double end) => TimeRange(OutInCubic, time, start, end); - - public static double OutInCubic(double t, double b, double c, double d) - { - if (t < d / 2) - { - return OutCubic(t * 2, b, c / 2, d); - } - else - { - return InCubic((t * 2) - d, b + c / 2, c / 2, d); - } - } + public static double OutInCubic(double t, double b, double c, double d) => OutIn(OutCubic, InCubic, t, b, c, d); // IN QUARTIC @@ -361,33 +349,11 @@ namespace MoonTools.Core.Easing public static float OutInQuart(float t) => NormalizedTime(OutInQuart, t); public static float OutInQuart(float time, float start, float end) => TimeRange(OutInQuart, time, start, end); - - public static float OutInQuart(float t, float b, float c, float d) - { - if (t < d / 2) - { - return OutQuart(t * 2, b, c / 2, d); - } - else - { - return InQuart((t * 2) - d, b + c / 2, c / 2, d); - } - } + public static float OutInQuart(float t, float b, float c, float d) => OutIn(OutQuart, InQuart, t, b, c, d); public static double OutInQuart(double t) => NormalizedTime(OutInQuart, t); public static double OutInQuart(double time, double start, double end) => TimeRange(OutInQuart, time, start, end); - - public static double OutInQuart(double t, double b, double c, double d) - { - if (t < d / 2) - { - return OutQuart(t * 2, b, c / 2, d); - } - else - { - return InQuart((t * 2) - d, b + c / 2, c / 2, d); - } - } + public static double OutInQuart(double t, double b, double c, double d) => OutIn(OutQuart, InQuart, t, b, c, d); // IN QUINTIC @@ -475,35 +441,11 @@ namespace MoonTools.Core.Easing public static float OutInQuint(float t) => NormalizedTime(OutInQuint, t); public static float OutInQuint(float time, float start, float end) => TimeRange(OutInQuint, time, start, end); - - public static float OutInQuint(float t, float b, float c, float d) - { - CheckTime(t, d); - if (t < d / 2) - { - return OutQuint(t * 2, b, c / 2, d); - } - else - { - return InQuint((t * 2) - d, b + c / 2, c / 2, d); - } - } + public static float OutInQuint(float t, float b, float c, float d) => OutIn(OutQuint, InQuint, t, b, c, d); public static double OutInQuint(double t) => NormalizedTime(OutInQuint, t); public static double OutInQuint(double time, double start, double end) => TimeRange(OutInQuint, time, start, end); - - public static double OutInQuint(double t, double b, double c, double d) - { - CheckTime(t, d); - if (t < d / 2) - { - return OutQuint(t * 2, b, c / 2, d); - } - else - { - return InQuint((t * 2) - d, b + c / 2, c / 2, d); - } - } + public static double OutInQuint(double t, double b, double c, double d) => OutIn(OutQuint, InQuint, t, b, c, d); // note: no float implementations because trig functions are double precision @@ -544,17 +486,120 @@ namespace MoonTools.Core.Easing public static double OutInSine(double t) => NormalizedTime(OutInSine, t); public static double OutInSine(double time, double start, double end) => TimeRange(OutInSine, time, start, end); + public static double OutInSine(double t, double b, double c, double d) => OutIn(OutSine, InSine, t, b, c, d); - public static double OutInSine(double t, double b, double c, double d) + // IN EXPONENTIAL + + public static double InExpo(double t) => NormalizedTime(InExpo, t); + public static double InExpo(double time, double start, double end) => TimeRange(InExpo, time, start, end); + + public static double InExpo(double t, double b, double c, double d) { - if (t < d / 2) + CheckTime(t, d); + if (t == 0) { - return OutSine(t * 2, b, c / 2, d); + return b; } else { - return InSine((t * 2) - d, b + c / 2, c / 2, d); + return c * Math.Pow(2, 10 * ((t / d) - 1)) + b - c * 0.001; } } + + // OUT EXPONENTIAL + + public static double OutExpo(double t) => NormalizedTime(OutExpo, t); + public static double OutExpo(double time, double start, double end) => TimeRange(OutExpo, time, start, end); + + public static double OutExpo(double t, double b, double c, double d) + { + CheckTime(t, d); + if (t == d) + { + return b + c; + } + else + { + return c * 1.001 * (-Math.Pow(2, -10 * t / d) + 1) + b; + } + } + + // IN OUT EXPONENTIAL + + public static double InOutExpo(double t) => NormalizedTime(InOutExpo, t); + public static double InOutExpo(double time, double start, double end) => TimeRange(InOutExpo, time, start, end); + + public static double InOutExpo(double t, double b, double c, double d) + { + CheckTime(t, d); + if (t == 0) { return b; } + if (t == d) { return b + c; } + t = t / d * 2; + if (t < 1) + { + return c / 2 * Math.Pow(2, 10 * (t - 1)) + b - c * 0.0005; + } + else + { + t = t - 1; + return c / 2 * 1.0005 * (-Math.Pow(2, -10 * t) + 2) + b; + } + } + + // OUT IN EXPONENTIAL + + public static double OutInExpo(double t) => NormalizedTime(OutInExpo, t); + public static double OutInExpo(double time, double start, double end) => TimeRange(OutInExpo, time, start, end); + public static double OutInExpo(double t, double b, double c, double d) => OutIn(OutExpo, InExpo, t, b, c, d); + + // IN CIRCULAR + + public static double InCirc(double t) => NormalizedTime(InCirc, t); + public static double InCirc(double time, double start, double end) => TimeRange(InCirc, time, start, end); + + public static double InCirc(double t, double b, double c, double d) + { + CheckTime(t, d); + t = t / d; + return -c * (Math.Sqrt(1 - (t * t)) - 1) + b; + } + + // OUT CIRCULAR + + public static double OutCirc(double t) => NormalizedTime(OutCirc, t); + public static double OutCirc(double time, double start, double end) => TimeRange(OutCirc, time, start, end); + + public static double OutCirc(double t, double b, double c, double d) + { + CheckTime(t, d); + t = t / d - 1; + return c * Math.Sqrt(1 - (t * t)) + b; + } + + // IN OUT CIRCULAR + + public static double InOutCirc(double t) => NormalizedTime(InOutCirc, t); + public static double InOutCirc(double time, double start, double end) => TimeRange(InOutCirc, time, start, end); + + public static double InOutCirc(double t, double b, double c, double d) + { + CheckTime(t, d); + t = t / d * 2; + if (t < 1) + { + return -c / 2 * (Math.Sqrt(1 - (t * t)) - 1) + b; + } + else + { + t = t - 2; + return c / 2 * (Math.Sqrt(1 - (t * t)) + 1) + b; + } + } + + // OUT IN CIRCULAR + + public static double OutInCirc(double t) => NormalizedTime(OutInCirc, t); + 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); } } diff --git a/Test/Easing.cs b/Test/Easing.cs index 0401510..480cad9 100644 --- a/Test/Easing.cs +++ b/Test/Easing.cs @@ -337,6 +337,150 @@ namespace Test invalidTime = () => Easing.OutSine(7f, 2, 6); invalidTime.Should().Throw(); } + + [Test] + public void InExpo() + { + Easing.InExpo(0.25f).Should().BeApproximately(0.0045242717280199f, 0.0001f); + Easing.InExpo(0.5f).Should().BeApproximately(0.03025f, 0.0001f); + Easing.InExpo(0.75f).Should().BeApproximately(0.17577669529664f, 0.0001f); + + Easing.InExpo(3f, 2, 6).Should().BeApproximately(2.0180970869121f, 0.0001f); + Easing.InExpo(4f, 2, 6).Should().BeApproximately(2.121f, 0.0001f); + Easing.InExpo(5f, 2, 6).Should().BeApproximately(2.703106781187f, 0.0001f); + + Action invalidTime = () => Easing.InExpo(1.5f); + invalidTime.Should().Throw(); + + invalidTime = () => Easing.InExpo(7f, 2, 6); + invalidTime.Should().Throw(); + } + + [Test] + public void OutExpo() + { + Easing.OutExpo(0.25f).Should().BeApproximately(0.82404652800807f, 0.0001f); + Easing.OutExpo(0.5f).Should().BeApproximately(0.96971875f, 0.0001f); + Easing.OutExpo(0.75f).Should().BeApproximately(0.99547020400025f, 0.0001f); + + Easing.OutExpo(3f, 2, 6).Should().BeApproximately(5.29618611203f, 0.0001f); + Easing.OutExpo(4f, 2, 6).Should().BeApproximately(5.878875f, 0.0001f); + Easing.OutExpo(5f, 2, 6).Should().BeApproximately(5.981880816f, 0.0001f); + + Action invalidTime = () => Easing.OutExpo(1.5f); + invalidTime.Should().Throw(); + + invalidTime = () => Easing.OutExpo(7f, 2, 6); + invalidTime.Should().Throw(); + } + + [Test] + public void InOutExpo() + { + Easing.InOutExpo(0.25f).Should().BeApproximately(0.015125f, 0.001f); + Easing.InOutExpo(0.5f).Should().BeApproximately(0.5f, 0.001f); + Easing.InOutExpo(0.75f).Should().BeApproximately(0.9848671875f, 0.001f); + + Easing.InOutExpo(3f, 2, 6).Should().BeApproximately(2.0605f, 0.001f); + Easing.InOutExpo(4f, 2, 6).Should().BeApproximately(4f, 0.001f); + Easing.InOutExpo(5f, 2, 6).Should().BeApproximately(5.93946875f, 0.001f); + + Action invalidTime = () => Easing.InOutExpo(1.5f); + invalidTime.Should().Throw(); + + invalidTime = () => Easing.InOutExpo(7f, 2, 6); + invalidTime.Should().Throw(); + } + + [Test] + public void OutInExpo() + { + Easing.OutInExpo(0.25f).Should().BeApproximately(0.484859375f, 0.001f); + Easing.OutInExpo(0.5f).Should().BeApproximately(0.5f, 0.001f); + Easing.OutInExpo(0.75f).Should().BeApproximately(0.515125f, 0.001f); + + Easing.OutInExpo(3f, 2, 6).Should().BeApproximately(3.9394375f, 0.001f); + Easing.OutInExpo(4f, 2, 6).Should().BeApproximately(4f, 0.001f); + Easing.OutInExpo(5f, 2, 6).Should().BeApproximately(4.0605f, 0.001f); + + Action invalidTime = () => Easing.OutInExpo(1.5f); + invalidTime.Should().Throw(); + + invalidTime = () => Easing.OutInExpo(7f, 2, 6); + invalidTime.Should().Throw(); + } + + [Test] + public void InCircular() + { + Easing.InCirc(0.25f).Should().BeApproximately(0.031754163448146f, 0.001f); + Easing.InCirc(0.5f).Should().BeApproximately(0.13397459621556f, 0.001f); + Easing.InCirc(0.75f).Should().BeApproximately(0.33856217223385f, 0.001f); + + Easing.InCirc(3f, 2, 6).Should().BeApproximately(2.127016653793f, 0.001f); + Easing.InCirc(4f, 2, 6).Should().BeApproximately(2.535898384862f, 0.001f); + Easing.InCirc(5f, 2, 6).Should().BeApproximately(3.35424868894f, 0.001f); + + Action invalidTime = () => Easing.InCirc(1.5f); + invalidTime.Should().Throw(); + + invalidTime = () => Easing.InCirc(7f, 2, 6); + invalidTime.Should().Throw(); + } + + [Test] + public void OutCircular() + { + Easing.OutCirc(0.25f).Should().BeApproximately(0.66143782776615f, 0.001f); + Easing.OutCirc(0.5f).Should().BeApproximately(0.86602540378444f, 0.001f); + Easing.OutCirc(0.75f).Should().BeApproximately(0.96824583655185f, 0.001f); + + Easing.OutCirc(3f, 2, 6).Should().BeApproximately(4.64575131107f, 0.001f); + Easing.OutCirc(4f, 2, 6).Should().BeApproximately(5.46410161514f, 0.001f); + Easing.OutCirc(5f, 2, 6).Should().BeApproximately(5.87298334621f, 0.001f); + + Action invalidTime = () => Easing.OutCirc(1.5f); + invalidTime.Should().Throw(); + + invalidTime = () => Easing.OutCirc(7f, 2, 6); + invalidTime.Should().Throw(); + } + + [Test] + public void InOutCircular() + { + Easing.InOutCirc(0.25f).Should().BeApproximately(0.066987298107781f, 0.001f); + Easing.InOutCirc(0.5f).Should().BeApproximately(0.5f, 0.001f); + Easing.InOutCirc(0.75f).Should().BeApproximately(0.93301270189222f, 0.001f); + + Easing.InOutCirc(3f, 2, 6).Should().BeApproximately(2.267949192431f, 0.001f); + Easing.InOutCirc(4f, 2, 6).Should().BeApproximately(4f, 0.001f); + Easing.InOutCirc(5f, 2, 6).Should().BeApproximately(5.73205080757f, 0.001f); + + Action invalidTime = () => Easing.InOutCirc(1.5f); + invalidTime.Should().Throw(); + + invalidTime = () => Easing.InOutCirc(7f, 2, 6); + invalidTime.Should().Throw(); + } + + [Test] + public void OutInCircular() + { + Easing.OutInCirc(0.25f).Should().BeApproximately(0.43301270189222f, 0.001f); + Easing.OutInCirc(0.5f).Should().BeApproximately(0.5f, 0.001f); + Easing.OutInCirc(0.75f).Should().BeApproximately(0.56698729810778f, 0.001f); + + Easing.OutInCirc(3f, 2, 6).Should().BeApproximately(3.73205080757f, 0.001f); + Easing.OutInCirc(4f, 2, 6).Should().BeApproximately(4f, 0.001f); + Easing.OutInCirc(5f, 2, 6).Should().BeApproximately(4.26794919243f, 0.001f); + + Action invalidTime = () => Easing.OutInCirc(1.5f); + invalidTime.Should().Throw(); + + invalidTime = () => Easing.OutInCirc(7f, 2, 6); + invalidTime.Should().Throw(); + } } public class DoubleTests @@ -634,6 +778,118 @@ namespace Test CheckDoubleArguments(Easing.OutInSine, Easing.OutInSine); } + + [Test] + public void InExpo() + { + Easing.InExpo(0.25).Should().BeApproximately(0.0045242717280199, 0.0001); + Easing.InExpo(0.5).Should().BeApproximately(0.03025, 0.0001); + Easing.InExpo(0.75).Should().BeApproximately(0.17577669529664, 0.0001); + + Easing.InExpo(3, 2, 6).Should().BeApproximately(2.0180970869121, 0.0001); + Easing.InExpo(4, 2, 6).Should().BeApproximately(2.121, 0.0001); + Easing.InExpo(5, 2, 6).Should().BeApproximately(2.703106781187, 0.0001); + + CheckDoubleArguments(Easing.InExpo, Easing.InExpo); + } + + [Test] + public void OutExpo() + { + Easing.OutExpo(0.25).Should().BeApproximately(0.82404652800807, 0.0001); + Easing.OutExpo(0.5).Should().BeApproximately(0.96971875, 0.0001); + Easing.OutExpo(0.75).Should().BeApproximately(0.99547020400025, 0.0001); + + Easing.OutExpo(3, 2, 6).Should().BeApproximately(5.29618611203, 0.0001); + Easing.OutExpo(4, 2, 6).Should().BeApproximately(5.878875, 0.0001); + Easing.OutExpo(5, 2, 6).Should().BeApproximately(5.981880816, 0.0001); + + CheckDoubleArguments(Easing.OutExpo, Easing.OutExpo); + } + + [Test] + public void InOutExpo() + { + Easing.InOutExpo(0.25).Should().BeApproximately(0.015125, 0.001); + Easing.InOutExpo(0.5).Should().BeApproximately(0.5, 0.001); + Easing.InOutExpo(0.75).Should().BeApproximately(0.9848671875, 0.001); + + Easing.InOutExpo(3, 2, 6).Should().BeApproximately(2.0605, 0.001); + Easing.InOutExpo(4, 2, 6).Should().BeApproximately(4, 0.001); + Easing.InOutExpo(5, 2, 6).Should().BeApproximately(5.93946875, 0.001); + + CheckDoubleArguments(Easing.InOutExpo, Easing.InOutExpo); + } + + [Test] + public void OutInExpo() + { + Easing.OutInExpo(0.25).Should().BeApproximately(0.484859375, 0.001); + Easing.OutInExpo(0.5).Should().BeApproximately(0.5, 0.001); + Easing.OutInExpo(0.75).Should().BeApproximately(0.515125, 0.001); + + Easing.OutInExpo(3, 2, 6).Should().BeApproximately(3.9394375, 0.001); + Easing.OutInExpo(4, 2, 6).Should().BeApproximately(4, 0.001); + Easing.OutInExpo(5, 2, 6).Should().BeApproximately(4.0605, 0.001); + + CheckDoubleArguments(Easing.OutInExpo, Easing.OutInExpo); + } + + [Test] + public void InCircular() + { + Easing.InCirc(0.25).Should().BeApproximately(0.031754163448146, 0.001); + Easing.InCirc(0.5).Should().BeApproximately(0.13397459621556, 0.001); + Easing.InCirc(0.75).Should().BeApproximately(0.33856217223385, 0.001); + + Easing.InCirc(3, 2, 6).Should().BeApproximately(2.127016653793, 0.001); + Easing.InCirc(4, 2, 6).Should().BeApproximately(2.535898384862, 0.001); + Easing.InCirc(5, 2, 6).Should().BeApproximately(3.35424868894, 0.001); + + CheckDoubleArguments(Easing.InCirc, Easing.InCirc); + } + + [Test] + public void OutCircular() + { + Easing.OutCirc(0.25).Should().BeApproximately(0.66143782776615, 0.001); + Easing.OutCirc(0.5).Should().BeApproximately(0.86602540378444, 0.001); + Easing.OutCirc(0.75).Should().BeApproximately(0.96824583655185, 0.001); + + Easing.OutCirc(3, 2, 6).Should().BeApproximately(4.64575131107, 0.001); + Easing.OutCirc(4, 2, 6).Should().BeApproximately(5.46410161514, 0.001); + Easing.OutCirc(5, 2, 6).Should().BeApproximately(5.87298334621, 0.001); + + CheckDoubleArguments(Easing.OutCirc, Easing.OutCirc); + } + + [Test] + public void InOutCircular() + { + Easing.InOutCirc(0.25).Should().BeApproximately(0.066987298107781, 0.001); + Easing.InOutCirc(0.5).Should().BeApproximately(0.5, 0.001); + Easing.InOutCirc(0.75).Should().BeApproximately(0.93301270189222, 0.001); + + Easing.InOutCirc(3, 2, 6).Should().BeApproximately(2.267949192431, 0.001); + Easing.InOutCirc(4, 2, 6).Should().BeApproximately(4, 0.001); + Easing.InOutCirc(5, 2, 6).Should().BeApproximately(5.73205080757, 0.001); + + CheckDoubleArguments(Easing.InOutCirc, Easing.InOutCirc); + } + + [Test] + public void OutInCircular() + { + Easing.OutInCirc(0.25).Should().BeApproximately(0.43301270189222, 0.001); + Easing.OutInCirc(0.5).Should().BeApproximately(0.5, 0.001); + Easing.OutInCirc(0.75).Should().BeApproximately(0.56698729810778, 0.001); + + Easing.OutInCirc(3, 2, 6).Should().BeApproximately(3.73205080757, 0.001); + Easing.OutInCirc(4, 2, 6).Should().BeApproximately(4, 0.001); + Easing.OutInCirc(5, 2, 6).Should().BeApproximately(4.26794919243, 0.001); + + CheckDoubleArguments(Easing.OutInCirc, Easing.OutInCirc); + } } } } \ No newline at end of file