Merge pull request #76906 from lawnjelly/safe_acos4_2
Make acos and asin safe
This commit is contained in:
commit
fd4a06c515
|
@ -807,8 +807,8 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
|
||||||
z = (rows[1][0] - rows[0][1]) / s;
|
z = (rows[1][0] - rows[0][1]) / s;
|
||||||
|
|
||||||
r_axis = Vector3(x, y, z);
|
r_axis = Vector3(x, y, z);
|
||||||
// CLAMP to avoid NaN if the value passed to acos is not in [0,1].
|
// acos does clamping.
|
||||||
r_angle = Math::acos(CLAMP((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2, (real_t)0.0, (real_t)1.0));
|
r_angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Basis::set_quaternion(const Quaternion &p_quaternion) {
|
void Basis::set_quaternion(const Quaternion &p_quaternion) {
|
||||||
|
|
|
@ -74,11 +74,13 @@ public:
|
||||||
static _ALWAYS_INLINE_ double tanh(double p_x) { return ::tanh(p_x); }
|
static _ALWAYS_INLINE_ double tanh(double p_x) { return ::tanh(p_x); }
|
||||||
static _ALWAYS_INLINE_ float tanh(float p_x) { return ::tanhf(p_x); }
|
static _ALWAYS_INLINE_ float tanh(float p_x) { return ::tanhf(p_x); }
|
||||||
|
|
||||||
static _ALWAYS_INLINE_ double asin(double p_x) { return ::asin(p_x); }
|
// Always does clamping so always safe to use.
|
||||||
static _ALWAYS_INLINE_ float asin(float p_x) { return ::asinf(p_x); }
|
static _ALWAYS_INLINE_ double asin(double p_x) { return p_x < -1 ? (-Math_PI / 2) : (p_x > 1 ? (Math_PI / 2) : ::asin(p_x)); }
|
||||||
|
static _ALWAYS_INLINE_ float asin(float p_x) { return p_x < -1 ? (-Math_PI / 2) : (p_x > 1 ? (Math_PI / 2) : ::asinf(p_x)); }
|
||||||
|
|
||||||
static _ALWAYS_INLINE_ double acos(double p_x) { return ::acos(p_x); }
|
// Always does clamping so always safe to use.
|
||||||
static _ALWAYS_INLINE_ float acos(float p_x) { return ::acosf(p_x); }
|
static _ALWAYS_INLINE_ double acos(double p_x) { return p_x < -1 ? Math_PI : (p_x > 1 ? 0 : ::acos(p_x)); }
|
||||||
|
static _ALWAYS_INLINE_ float acos(float p_x) { return p_x < -1 ? Math_PI : (p_x > 1 ? 0 : ::acosf(p_x)); }
|
||||||
|
|
||||||
static _ALWAYS_INLINE_ double atan(double p_x) { return ::atan(p_x); }
|
static _ALWAYS_INLINE_ double atan(double p_x) { return ::atan(p_x); }
|
||||||
static _ALWAYS_INLINE_ float atan(float p_x) { return ::atanf(p_x); }
|
static _ALWAYS_INLINE_ float atan(float p_x) { return ::atanf(p_x); }
|
||||||
|
|
|
@ -35,7 +35,8 @@
|
||||||
|
|
||||||
real_t Quaternion::angle_to(const Quaternion &p_to) const {
|
real_t Quaternion::angle_to(const Quaternion &p_to) const {
|
||||||
real_t d = dot(p_to);
|
real_t d = dot(p_to);
|
||||||
return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
|
// acos does clamping.
|
||||||
|
return Math::acos(d * d * 2 - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Quaternion::get_euler(EulerOrder p_order) const {
|
Vector3 Quaternion::get_euler(EulerOrder p_order) const {
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<param index="0" name="x" type="float" />
|
<param index="0" name="x" type="float" />
|
||||||
<description>
|
<description>
|
||||||
Returns the arc cosine of [param x] in radians. Use to get the angle of cosine [param x]. [param x] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method acos] will return [constant @GDScript.NAN].
|
Returns the arc cosine of [param x] in radians. Use to get the angle of cosine [param x]. [param x] will be clamped between [code]-1.0[/code] and [code]1.0[/code] (inclusive), in order to prevent [method acos] from returning [constant @GDScript.NAN].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
# c is 0.523599 or 30 degrees if converted with rad_to_deg(c)
|
# c is 0.523599 or 30 degrees if converted with rad_to_deg(c)
|
||||||
var c = acos(0.866025)
|
var c = acos(0.866025)
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<param index="0" name="x" type="float" />
|
<param index="0" name="x" type="float" />
|
||||||
<description>
|
<description>
|
||||||
Returns the arc sine of [param x] in radians. Use to get the angle of sine [param x]. [param x] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method asin] will return [constant @GDScript.NAN].
|
Returns the arc sine of [param x] in radians. Use to get the angle of sine [param x]. [param x] will be clamped between [code]-1.0[/code] and [code]1.0[/code] (inclusive), in order to prevent [method asin] from returning [constant @GDScript.NAN].
|
||||||
[codeblock]
|
[codeblock]
|
||||||
# s is 0.523599 or 30 degrees if converted with rad_to_deg(s)
|
# s is 0.523599 or 30 degrees if converted with rad_to_deg(s)
|
||||||
var s = asin(0.5)
|
var s = asin(0.5)
|
||||||
|
|
|
@ -157,15 +157,15 @@ TEST_CASE_TEMPLATE("[Math] asin/acos/atan", T, float, double) {
|
||||||
CHECK(Math::asin((T)0.1) == doctest::Approx((T)0.1001674212));
|
CHECK(Math::asin((T)0.1) == doctest::Approx((T)0.1001674212));
|
||||||
CHECK(Math::asin((T)0.5) == doctest::Approx((T)0.5235987756));
|
CHECK(Math::asin((T)0.5) == doctest::Approx((T)0.5235987756));
|
||||||
CHECK(Math::asin((T)1.0) == doctest::Approx((T)1.5707963268));
|
CHECK(Math::asin((T)1.0) == doctest::Approx((T)1.5707963268));
|
||||||
CHECK(Math::is_nan(Math::asin((T)1.5)));
|
CHECK(Math::asin((T)2.0) == doctest::Approx((T)1.5707963268));
|
||||||
CHECK(Math::is_nan(Math::asin((T)450.0)));
|
CHECK(Math::asin((T)-2.0) == doctest::Approx((T)-1.5707963268));
|
||||||
|
|
||||||
CHECK(Math::acos((T)-0.1) == doctest::Approx((T)1.670963748));
|
CHECK(Math::acos((T)-0.1) == doctest::Approx((T)1.670963748));
|
||||||
CHECK(Math::acos((T)0.1) == doctest::Approx((T)1.4706289056));
|
CHECK(Math::acos((T)0.1) == doctest::Approx((T)1.4706289056));
|
||||||
CHECK(Math::acos((T)0.5) == doctest::Approx((T)1.0471975512));
|
CHECK(Math::acos((T)0.5) == doctest::Approx((T)1.0471975512));
|
||||||
CHECK(Math::acos((T)1.0) == doctest::Approx((T)0.0));
|
CHECK(Math::acos((T)1.0) == doctest::Approx((T)0.0));
|
||||||
CHECK(Math::is_nan(Math::acos((T)1.5)));
|
CHECK(Math::acos((T)2.0) == doctest::Approx((T)0.0));
|
||||||
CHECK(Math::is_nan(Math::acos((T)450.0)));
|
CHECK(Math::acos((T)-2.0) == doctest::Approx((T)Math_PI));
|
||||||
|
|
||||||
CHECK(Math::atan((T)-0.1) == doctest::Approx((T)-0.0996686525));
|
CHECK(Math::atan((T)-0.1) == doctest::Approx((T)-0.0996686525));
|
||||||
CHECK(Math::atan((T)0.1) == doctest::Approx((T)0.0996686525));
|
CHECK(Math::atan((T)0.1) == doctest::Approx((T)0.0996686525));
|
||||||
|
|
Loading…
Reference in New Issue