From 7ca206721b114c4b288c184aaa188c166772b929 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Mon, 23 May 2022 10:33:52 +0100 Subject: [PATCH] Add MathUtility.InverseLerp (#60) --- CHANGELOG.md | 1 + X10D.Tests/src/Math/MathUtilityTests.cs | 46 ++++++++++++++++++++++++ X10D/src/Math/MathUtility.cs | 48 +++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 X10D.Tests/src/Math/MathUtilityTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 407ce5b..6a42897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 3.2.0 ### Added +- X10D: Added `MathUtility.InverseLerp(float, float, float)` and `MathUtility.InverseLerp(double, double, double)` - X10D: Added `RoundUpToPowerOf2()` for built-in integer types - X10D: Added `Vector2.Deconstruct()` - X10D: Added `Vector3.Deconstruct()` diff --git a/X10D.Tests/src/Math/MathUtilityTests.cs b/X10D.Tests/src/Math/MathUtilityTests.cs new file mode 100644 index 0000000..7ee327f --- /dev/null +++ b/X10D.Tests/src/Math/MathUtilityTests.cs @@ -0,0 +1,46 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Core; +using X10D.Math; + +namespace X10D.Tests.Math; + +[TestClass] +public class MathUtilityTests +{ + [TestMethod] + public void InverseLerp_ShouldReturn0_5_Given0_5_0_1() + { + double doubleResult = MathUtility.InverseLerp(0.5, 0.0, 1.0); + float floatResult = MathUtility.InverseLerp(0.5f, 0f, 1f); + + Assert.AreEqual(0.5, doubleResult, 1e-6); + Assert.AreEqual(0.5f, floatResult, 1e-6f); + } + + [TestMethod] + public void InverseLerp_ShouldReturn0_5_Given5_0_10() + { + double doubleResult = MathUtility.InverseLerp(5.0, 0.0, 10.0); + float floatResult = MathUtility.InverseLerp(5f, 0f, 10f); + + Assert.AreEqual(0.5, doubleResult, 1e-6); + Assert.AreEqual(0.5f, floatResult, 1e-6f); + } + + [TestMethod] + public void InverseLerp_ShouldReturn0_GivenTwoEqualValues() + { + var random = new Random(); + double doubleA = random.NextDouble(); + double doubleB = random.NextDouble(); + + float floatA = random.NextSingle(); + float floatB = random.NextSingle(); + + double doubleResult = MathUtility.InverseLerp(doubleA, doubleB, doubleB); + float floatResult = MathUtility.InverseLerp(floatA, floatB, floatB); + + Assert.AreEqual(0.0, doubleResult, 1e-6); + Assert.AreEqual(0.0f, floatResult, 1e-6f); + } +} diff --git a/X10D/src/Math/MathUtility.cs b/X10D/src/Math/MathUtility.cs index 8613219..a75cc95 100644 --- a/X10D/src/Math/MathUtility.cs +++ b/X10D/src/Math/MathUtility.cs @@ -8,6 +8,54 @@ namespace X10D.Math; /// public static class MathUtility { + /// + /// Returns the linear interpolation inverse of a value, such that it determines where a value lies between two other + /// values. + /// + /// The value whose lerp inverse is to be found. + /// The start of the range. + /// The end of the range. + /// A value determined by (alpha - start) / (end - start). + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static float InverseLerp(float alpha, float start, float end) + { + if (MathF.Abs(start - end) < float.Epsilon) + { + return 0f; + } + + return (alpha - start) / (end - start); + } + + /// + /// Returns the linear interpolation inverse of a value, such that it determines where a value lies between two other + /// values. + /// + /// The value whose lerp inverse is to be found. + /// The start of the range. + /// The end of the range. + /// A value determined by (alpha - start) / (end - start). + [Pure] +#if NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#else + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] +#endif + public static double InverseLerp(double alpha, double start, double end) + { + if (System.Math.Abs(start - end) < double.Epsilon) + { + return 0.0; + } + + return (alpha - start) / (end - start); + } + /// /// Linearly interpolates from one value to a target using a specified alpha. ///