diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index f96d3a909fb..934c75b5d3a 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -88,6 +88,17 @@ public: static _ALWAYS_INLINE_ double atan2(double p_y, double p_x) { return ::atan2(p_y, p_x); } static _ALWAYS_INLINE_ float atan2(float p_y, float p_x) { return ::atan2f(p_y, p_x); } + static _ALWAYS_INLINE_ double asinh(double p_x) { return ::asinh(p_x); } + static _ALWAYS_INLINE_ float asinh(float p_x) { return ::asinhf(p_x); } + + // Always does clamping so always safe to use. + static _ALWAYS_INLINE_ double acosh(double p_x) { return p_x < 1 ? 0 : ::acosh(p_x); } + static _ALWAYS_INLINE_ float acosh(float p_x) { return p_x < 1 ? 0 : ::acoshf(p_x); } + + // Always does clamping so always safe to use. + static _ALWAYS_INLINE_ double atanh(double p_x) { return p_x <= -1 ? -INFINITY : (p_x >= 1 ? INFINITY : ::atanh(p_x)); } + static _ALWAYS_INLINE_ float atanh(float p_x) { return p_x <= -1 ? -INFINITY : (p_x >= 1 ? INFINITY : ::atanhf(p_x)); } + static _ALWAYS_INLINE_ double sqrt(double p_x) { return ::sqrt(p_x); } static _ALWAYS_INLINE_ float sqrt(float p_x) { return ::sqrtf(p_x); } diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 4f6bcb58b32..b51df89becd 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -81,6 +81,18 @@ double VariantUtilityFunctions::atan2(double y, double x) { return Math::atan2(y, x); } +double VariantUtilityFunctions::asinh(double arg) { + return Math::asinh(arg); +} + +double VariantUtilityFunctions::acosh(double arg) { + return Math::acosh(arg); +} + +double VariantUtilityFunctions::atanh(double arg) { + return Math::atanh(arg); +} + double VariantUtilityFunctions::sqrt(double x) { return Math::sqrt(x); } @@ -1502,6 +1514,10 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(atan2, sarray("y", "x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(asinh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(acosh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(atanh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(sqrt, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH); diff --git a/core/variant/variant_utility.h b/core/variant/variant_utility.h index 78f66987cba..66883fb1404 100644 --- a/core/variant/variant_utility.h +++ b/core/variant/variant_utility.h @@ -45,6 +45,9 @@ struct VariantUtilityFunctions { static double acos(double arg); static double atan(double arg); static double atan2(double y, double x); + static double asinh(double arg); + static double acosh(double arg); + static double atanh(double arg); static double sqrt(double x); static double fmod(double b, double r); static double fposmod(double b, double r); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index ae40051d954..fa3f6e434e2 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -72,6 +72,19 @@ [/codeblock] + + + + + Returns the hyperbolic arc (also called inverse) cosine of [param x], returning a value in radians. Use it to get the angle from an angle's cosine in hyperbolic space if [param x] is larger or equal to 1. For values of [param x] lower than 1, it will return 0, in order to prevent [method acosh] from returning [constant @GDScript.NAN]. + [codeblock] + var a = acosh(2) # Returns 1.31695789692482 + cosh(a) # Returns 2 + + var b = acosh(-1) # Returns 0 + [/codeblock] + + @@ -83,6 +96,17 @@ [/codeblock] + + + + + Returns the hyperbolic arc (also called inverse) sine of [param x], returning a value in radians. Use it to get the angle from an angle's sine in hyperbolic space. + [codeblock] + var a = asinh(0.9) # Returns 0.8088669356527824 + sinh(a) # Returns 0.9 + [/codeblock] + + @@ -107,6 +131,21 @@ [/codeblock] + + + + + Returns the hyperbolic arc (also called inverse) tangent of [param x], returning a value in radians. Use it to get the angle from an angle's tangent in hyperbolic space if [param x] is between -1 and 1 (non-inclusive). + In mathematics, the inverse hyperbolic tangent is only defined for -1 < [param x] < 1 in the real set, so values equal or lower to -1 for [param x] return negative [constant @GDScript.INF] and values equal or higher than 1 return positive [constant @GDScript.INF] in order to prevent [method atanh] from returning [constant @GDScript.NAN]. + [codeblock] + var a = atanh(0.9) # Returns 1.47221948958322 + tanh(a) # Returns 0.9 + + var b = atanh(-2) # Returns -inf + tanh(b) # Returns -1 + [/codeblock] + + diff --git a/tests/core/math/test_math_funcs.h b/tests/core/math/test_math_funcs.h index b6cb9620f1b..e3504ef1e51 100644 --- a/tests/core/math/test_math_funcs.h +++ b/tests/core/math/test_math_funcs.h @@ -175,6 +175,37 @@ TEST_CASE_TEMPLATE("[Math] asin/acos/atan", T, float, double) { CHECK(Math::atan((T)450.0) == doctest::Approx((T)1.5685741082)); } +TEST_CASE_TEMPLATE("[Math] asinh/acosh/atanh", T, float, double) { + CHECK(Math::asinh((T)-2.0) == doctest::Approx((T)-1.4436354751)); + CHECK(Math::asinh((T)-0.1) == doctest::Approx((T)-0.0998340788)); + CHECK(Math::asinh((T)0.1) == doctest::Approx((T)0.0998340788)); + CHECK(Math::asinh((T)0.5) == doctest::Approx((T)0.4812118250)); + CHECK(Math::asinh((T)1.0) == doctest::Approx((T)0.8813735870)); + CHECK(Math::asinh((T)2.0) == doctest::Approx((T)1.4436354751)); + + CHECK(Math::acosh((T)-2.0) == doctest::Approx((T)0.0)); + CHECK(Math::acosh((T)-0.1) == doctest::Approx((T)0.0)); + CHECK(Math::acosh((T)0.1) == doctest::Approx((T)0.0)); + CHECK(Math::acosh((T)0.5) == doctest::Approx((T)0.0)); + CHECK(Math::acosh((T)1.0) == doctest::Approx((T)0.0)); + CHECK(Math::acosh((T)2.0) == doctest::Approx((T)1.3169578969)); + CHECK(Math::acosh((T)450.0) == doctest::Approx((T)6.8023935287)); + + CHECK(Math::is_inf(Math::atanh((T)-2.0))); + CHECK(Math::atanh((T)-2.0) < (T)0.0); + CHECK(Math::is_inf(Math::atanh((T)-1.0))); + CHECK(Math::atanh((T)-1.0) < (T)0.0); + CHECK(Math::atanh((T)-0.1) == doctest::Approx((T)-0.1003353477)); + CHECK(Math::atanh((T)0.1) == doctest::Approx((T)0.1003353477)); + CHECK(Math::atanh((T)0.5) == doctest::Approx((T)0.5493061443)); + CHECK(Math::is_inf(Math::atanh((T)1.0))); + CHECK(Math::atanh((T)1.0) > (T)0.0); + CHECK(Math::is_inf(Math::atanh((T)1.5))); + CHECK(Math::atanh((T)1.5) > (T)0.0); + CHECK(Math::is_inf(Math::atanh((T)450.0))); + CHECK(Math::atanh((T)450.0) > (T)0.0); +} + TEST_CASE_TEMPLATE("[Math] sinc/sincn/atan2", T, float, double) { CHECK(Math::sinc((T)-0.1) == doctest::Approx((T)0.9983341665)); CHECK(Math::sinc((T)0.1) == doctest::Approx((T)0.9983341665));