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