diff --git a/Source/Engine/Core/Math/Mathd.cs b/Source/Engine/Core/Math/Mathd.cs
index 29bcc9420..48db547df 100644
--- a/Source/Engine/Core/Math/Mathd.cs
+++ b/Source/Engine/Core/Math/Mathd.cs
@@ -876,38 +876,54 @@ namespace FlaxEngine
///
/// Given a heading which may be outside the +/- PI range, 'unwind' it back into that range.
///
+ /// Optimized version of that is it faster and has fixed cost but with large angle values (100 for example) starts to lose accuracy floating point problem.
/// Angle in radians to unwind.
/// Valid angle in radians.
public static double UnwindRadians(double angle)
{
- // TODO: make it faster?
+ var a = angle - Math.Floor(angle / TwoPi) * TwoPi; // Loop function between 0 and TwoPi
+ return a > Pi ? a - TwoPi : a; // Change range so it become Pi and -Pi
+ }
+
+ ///
+ /// The same as but is more computation intensive with large and has better accuracy with large .
+ ///
cost of this function is %
+ ///
+ /// Angle in radians to unwind.
+ /// Valid angle in radians.
+ public static double UnwindRadiansAccurate(double angle)
+ {
while (angle > Pi)
- {
angle -= TwoPi;
- }
while (angle < -Pi)
- {
angle += TwoPi;
- }
return angle;
}
///
- /// Utility to ensure angle is between +/- 180 degrees by unwinding
+ /// Utility to ensure angle is between +/- 180 degrees by unwinding.
///
+ /// Optimized version of that is it faster and has fixed cost but with large angle values (100 for example) starts to lose accuracy floating point problem.
/// Angle in degrees to unwind.
/// Valid angle in degrees.
public static double UnwindDegrees(double angle)
{
- // TODO: make it faster?
- while (angle > 180.0f)
- {
- angle -= 360.0f;
- }
- while (angle < -180.0f)
- {
- angle += 360.0f;
- }
+ var a = angle - Math.Floor(angle / 360.0) * 360.0; // Loop function between 0 and 360
+ return a > 180 ? a - 360.0 : a; // Change range so it become 180 and -180
+ }
+
+ ///
+ /// The same as but is more computation intensive with large and has better accuracy with large .
+ ///
cost of this function is % 180.0f
+ ///
+ /// Angle in radians to unwind.
+ /// Valid angle in radians.
+ public static double UnwindDegreesAccurate(double angle)
+ {
+ while (angle > 180.0)
+ angle -= 360.0;
+ while (angle < -180.0)
+ angle += 360.0;
return angle;
}
@@ -927,8 +943,9 @@ namespace FlaxEngine
/// Interpolates between two values using a linear function by a given amount.
///
///
- /// See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and
- /// http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
+ /// See:
+ ///
+ ///
///
/// Value to interpolate from.
/// Value to interpolate to.
@@ -944,7 +961,8 @@ namespace FlaxEngine
/// Performs smooth (cubic Hermite) interpolation between 0 and 1.
///
///
- /// See https://en.wikipedia.org/wiki/Smoothstep
+ /// See:
+ ///
///
/// Value between 0 and 1 indicating interpolation amount.
public static double SmoothStep(double amount)
@@ -956,7 +974,8 @@ namespace FlaxEngine
/// Performs a smooth(er) interpolation between 0 and 1 with 1st and 2nd order derivatives of zero at endpoints.
///
///
- /// See https://en.wikipedia.org/wiki/Smoothstep
+ /// See:
+ ///
///
/// Value between 0 and 1 indicating interpolation amount.
public static double SmootherStep(double amount)
@@ -1013,7 +1032,7 @@ namespace FlaxEngine
///
/// Gauss function.
- /// http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function
+ ///
///
/// Curve amplitude.
/// Position X.
diff --git a/Source/Engine/Core/Math/Mathf.cs b/Source/Engine/Core/Math/Mathf.cs
index 9463c13cb..cea81a779 100644
--- a/Source/Engine/Core/Math/Mathf.cs
+++ b/Source/Engine/Core/Math/Mathf.cs
@@ -1176,38 +1176,54 @@ namespace FlaxEngine
///
/// Given a heading which may be outside the +/- PI range, 'unwind' it back into that range.
///
+ /// Optimized version of that is it faster and has fixed cost but with large angle values (100 for example) starts to lose accuracy floating point problem.
/// Angle in radians to unwind.
/// Valid angle in radians.
public static float UnwindRadians(float angle)
{
- // TODO: make it faster?
+ var a = angle - (float)Math.Floor(angle / TwoPi) * TwoPi; // Loop function between 0 and TwoPi
+ return a > Pi ? a - TwoPi : a; // Change range so it become Pi and -Pi
+ }
+
+ ///
+ /// The same as but is more computation intensive with large and has better accuracy with large .
+ ///
cost of this function is %
+ ///
+ /// Angle in radians to unwind.
+ /// Valid angle in radians.
+ public static float UnwindRadiansAccurate(float angle)
+ {
while (angle > Pi)
- {
angle -= TwoPi;
- }
while (angle < -Pi)
- {
angle += TwoPi;
- }
return angle;
}
///
- /// Utility to ensure angle is between +/- 180 degrees by unwinding
+ /// Utility to ensure angle is between +/- 180 degrees by unwinding.
///
+ /// Optimized version of that is it faster and has fixed cost but with large angle values (100 for example) starts to lose accuracy floating point problem.
/// Angle in degrees to unwind.
/// Valid angle in degrees.
public static float UnwindDegrees(float angle)
{
- // TODO: make it faster?
+ var a = angle - (float)Math.Floor(angle / 360.0f) * 360.0f; // Loop function between 0 and 360
+ return a > 180 ? a - 360.0f : a; // Change range so it become 180 and -180
+ }
+
+ ///
+ /// The same as but is more computation intensive with large and has better accuracy with large .
+ ///
cost of this function is % 180.0f
+ ///
+ /// Angle in radians to unwind.
+ /// Valid angle in radians.
+ public static float UnwindDegreesAccurate(float angle)
+ {
while (angle > 180.0f)
- {
angle -= 360.0f;
- }
while (angle < -180.0f)
- {
angle += 360.0f;
- }
return angle;
}
@@ -1299,8 +1315,12 @@ namespace FlaxEngine
///
/// Interpolates between two values using a linear function by a given amount.
///
- /// See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
- /// Value to interpolate from.
+ ///
+ /// See:
+ ///
+ ///
+ ///
+ /// /// Value to interpolate from.
/// Value to interpolate to.
/// Interpolation amount.
/// The result of linear interpolation of values based on the amount.
@@ -1312,8 +1332,12 @@ namespace FlaxEngine
///
/// Interpolates between two values using a linear function by a given amount.
///
- /// See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
- /// Value to interpolate from.
+ ///
+ /// See:
+ ///
+ ///
+ ///
+ /// /// Value to interpolate from.
/// Value to interpolate to.
/// Interpolation amount.
/// The result of linear interpolation of values based on the amount.
@@ -1325,8 +1349,12 @@ namespace FlaxEngine
///
/// Interpolates between two values using a linear function by a given amount.
///
- /// See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
- /// Value to interpolate from.
+ ///
+ /// See:
+ ///
+ ///
+ ///
+ /// /// Value to interpolate from.
/// Value to interpolate to.
/// Interpolation amount.
/// The result of linear interpolation of values based on the amount.
@@ -1338,7 +1366,10 @@ namespace FlaxEngine
///
/// Performs smooth (cubic Hermite) interpolation between 0 and 1.
///
- /// See https://en.wikipedia.org/wiki/Smoothstep
+ ///
+ /// See:
+ ///
+ ///
/// Value between 0 and 1 indicating interpolation amount.
public static float SmoothStep(float amount)
{
@@ -1348,7 +1379,10 @@ namespace FlaxEngine
///
/// Performs smooth (cubic Hermite) interpolation between 0 and 1.
///
- /// See https://en.wikipedia.org/wiki/Smoothstep
+ ///
+ /// See:
+ ///
+ ///
/// Value between 0 and 1 indicating interpolation amount.
public static double SmoothStep(double amount)
{
@@ -1358,7 +1392,10 @@ namespace FlaxEngine
///
/// Performs a smooth(er) interpolation between 0 and 1 with 1st and 2nd order derivatives of zero at endpoints.
///
- /// See https://en.wikipedia.org/wiki/Smoothstep
+ ///
+ /// See:
+ ///
+ ///
/// Value between 0 and 1 indicating interpolation amount.
public static float SmootherStep(float amount)
{
@@ -1368,7 +1405,10 @@ namespace FlaxEngine
///
/// Performs a smooth(er) interpolation between 0 and 1 with 1st and 2nd order derivatives of zero at endpoints.
///
- /// See https://en.wikipedia.org/wiki/Smoothstep
+ ///
+ /// See:
+ ///
+ ///
/// Value between 0 and 1 indicating interpolation amount.
public static double SmootherStep(double amount)
{
@@ -1446,7 +1486,7 @@ namespace FlaxEngine
///
/// Gauss function.
- /// http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function
+ ///
///
/// Curve amplitude.
/// Position X.
@@ -1463,7 +1503,7 @@ namespace FlaxEngine
///
/// Gauss function.
- /// http://en.wikipedia.org/wiki/Gaussian_function#Two-dimensional_Gaussian_function
+ ///
///
/// Curve amplitude.
/// Position X.
diff --git a/Source/Engine/Tests/TestMath.cs b/Source/Engine/Tests/TestMath.cs
new file mode 100644
index 000000000..bc1bc1a8d
--- /dev/null
+++ b/Source/Engine/Tests/TestMath.cs
@@ -0,0 +1,47 @@
+// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+
+#if FLAX_TESTS
+using NUnit.Framework;
+
+namespace FlaxEngine.Tests
+{
+ ///
+ /// Tests for and .
+ ///
+ [TestFixture]
+ public class TestMath
+ {
+ ///
+ /// Test unwinding angles.
+ ///
+ [Test]
+ public void TestUnwind()
+ {
+ Assert.AreEqual(0.0f, Mathf.UnwindDegreesAccurate(0.0f));
+ Assert.AreEqual(45.0f, Mathf.UnwindDegreesAccurate(45.0f));
+ Assert.AreEqual(90.0f, Mathf.UnwindDegreesAccurate(90.0f));
+ Assert.AreEqual(180.0f, Mathf.UnwindDegreesAccurate(180.0f));
+ Assert.AreEqual(0.0f, Mathf.UnwindDegreesAccurate(360.0f));
+ Assert.AreEqual(0.0f, Mathf.UnwindDegrees(0.0f));
+ Assert.AreEqual(45.0f, Mathf.UnwindDegrees(45.0f));
+ Assert.AreEqual(90.0f, Mathf.UnwindDegrees(90.0f));
+ Assert.AreEqual(180.0f, Mathf.UnwindDegrees(180.0f));
+ Assert.AreEqual(0.0f, Mathf.UnwindDegrees(360.0f));
+ var fError = 0.001f;
+ var dError = 0.00001;
+ for (float f = -400.0f; f <= 400.0f; f += 0.1f)
+ {
+ var f1 = Mathf.UnwindDegreesAccurate(f);
+ var f2 = Mathf.UnwindDegrees(f);
+ if (Mathf.Abs(f1 - f2) >= fError)
+ throw new Exception($"Failed on angle={f}, {f1} != {f2}");
+ var d = (double)f;
+ var d1 = Mathd.UnwindDegreesAccurate(d);
+ var d2 = Mathd.UnwindDegrees(d);
+ if (Mathd.Abs(d1 - d2) >= dError)
+ throw new Exception($"Failed on angle={d}, {d1} != {d2}");
+ }
+ }
+ }
+}
+#endif