summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2022-10-11 09:25:46 +0200
committerRémi Verschelde <rverschelde@gmail.com>2022-10-11 09:25:46 +0200
commit58eff50bf12dc330df284d7ff78bcfa59f5a2037 (patch)
tree42b500cefeff0b4226c9596f209adc086589bdb0
parent3306ffefd1d00ac5cec0783b9a34633d2d1a6ab3 (diff)
parent5da515773d8edec988b7523ea97cdfd54c3fd16c (diff)
Merge pull request #64268 from timothyqiu/is-finite
Add `is_finite` method for checking built-in types
-rw-r--r--core/math/aabb.cpp4
-rw-r--r--core/math/aabb.h1
-rw-r--r--core/math/basis.cpp4
-rw-r--r--core/math/basis.h1
-rw-r--r--core/math/math_funcs.h3
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/plane.h1
-rw-r--r--core/math/quaternion.cpp4
-rw-r--r--core/math/quaternion.h1
-rw-r--r--core/math/rect2.cpp4
-rw-r--r--core/math/rect2.h1
-rw-r--r--core/math/transform_2d.cpp4
-rw-r--r--core/math/transform_2d.h1
-rw-r--r--core/math/transform_3d.cpp4
-rw-r--r--core/math/transform_3d.h1
-rw-r--r--core/math/vector2.cpp4
-rw-r--r--core/math/vector2.h1
-rw-r--r--core/math/vector3.cpp4
-rw-r--r--core/math/vector3.h1
-rw-r--r--core/math/vector4.cpp4
-rw-r--r--core/math/vector4.h1
-rw-r--r--core/string/ustring.cpp12
-rw-r--r--core/variant/variant_call.cpp10
-rw-r--r--core/variant/variant_utility.cpp5
-rw-r--r--doc/classes/@GlobalScope.xml7
-rw-r--r--doc/classes/AABB.xml6
-rw-r--r--doc/classes/Basis.xml6
-rw-r--r--doc/classes/Plane.xml6
-rw-r--r--doc/classes/Quaternion.xml6
-rw-r--r--doc/classes/Rect2.xml6
-rw-r--r--doc/classes/Transform2D.xml6
-rw-r--r--doc/classes/Transform3D.xml6
-rw-r--r--doc/classes/Vector2.xml6
-rw-r--r--doc/classes/Vector3.xml6
-rw-r--r--doc/classes/Vector4.xml6
-rw-r--r--servers/rendering/renderer_scene_cull.cpp7
-rw-r--r--tests/core/math/test_aabb.h21
-rw-r--r--tests/core/math/test_basis.h34
-rw-r--r--tests/core/math/test_plane.h23
-rw-r--r--tests/core/math/test_quaternion.h57
-rw-r--r--tests/core/math/test_rect2.h21
-rw-r--r--tests/core/math/test_transform_2d.h34
-rw-r--r--tests/core/math/test_transform_3d.h23
-rw-r--r--tests/core/math/test_vector2.h26
-rw-r--r--tests/core/math/test_vector3.h45
-rw-r--r--tests/core/math/test_vector4.h78
46 files changed, 504 insertions, 12 deletions
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index 026f179445..fcf245d2ad 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -76,6 +76,10 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const {
return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size);
}
+bool AABB::is_finite() const {
+ return position.is_finite() && size.is_finite();
+}
+
AABB AABB::intersection(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
diff --git a/core/math/aabb.h b/core/math/aabb.h
index b9f777c6cf..9d5837ad37 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -63,6 +63,7 @@ struct _NO_DISCARD_ AABB {
bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const;
+ bool is_finite() const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 845686f339..9b8188eed8 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -691,6 +691,10 @@ bool Basis::is_equal_approx(const Basis &p_basis) const {
return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]);
}
+bool Basis::is_finite() const {
+ return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite();
+}
+
bool Basis::operator==(const Basis &p_matrix) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
diff --git a/core/math/basis.h b/core/math/basis.h
index cc2924f5ff..69bef5a7be 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -134,6 +134,7 @@ struct _NO_DISCARD_ Basis {
}
bool is_equal_approx(const Basis &p_basis) const;
+ bool is_finite() const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 7fa674a23d..0af529ad98 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -184,6 +184,9 @@ public:
#endif
}
+ static _ALWAYS_INLINE_ bool is_finite(double p_val) { return isfinite(p_val); }
+ static _ALWAYS_INLINE_ bool is_finite(float p_val) { return isfinite(p_val); }
+
static _ALWAYS_INLINE_ double abs(double g) { return absd(g); }
static _ALWAYS_INLINE_ float abs(float g) { return absf(g); }
static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; }
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 3b2eab4ae2..a5d2fe5628 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -176,6 +176,10 @@ bool Plane::is_equal_approx(const Plane &p_plane) const {
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
}
+bool Plane::is_finite() const {
+ return normal.is_finite() && Math::is_finite(d);
+}
+
Plane::operator String() const {
return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
}
diff --git a/core/math/plane.h b/core/math/plane.h
index 73babfa496..77da59fb27 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -74,6 +74,7 @@ struct _NO_DISCARD_ Plane {
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const;
+ bool is_finite() const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index 4a8d29e402..6a5f29f3d8 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -79,6 +79,10 @@ bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const {
return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w);
}
+bool Quaternion::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
+}
+
real_t Quaternion::length() const {
return Math::sqrt(length_squared());
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index 178cfaca70..7aa400aa8c 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -55,6 +55,7 @@ struct _NO_DISCARD_ Quaternion {
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
+ bool is_finite() const;
real_t length() const;
void normalize();
Quaternion normalized() const;
diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp
index 9e78ead816..facf4eb3c4 100644
--- a/core/math/rect2.cpp
+++ b/core/math/rect2.cpp
@@ -38,6 +38,10 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size);
}
+bool Rect2::is_finite() const {
+ return position.is_finite() && size.is_finite();
+}
+
bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 50dd2dc1df..9863405d8e 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -207,6 +207,7 @@ struct _NO_DISCARD_ Rect2 {
}
bool is_equal_approx(const Rect2 &p_rect) const;
+ bool is_finite() const;
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 2bfefe979f..548a82d254 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -168,6 +168,10 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
}
+bool Transform2D::is_finite() const {
+ return columns[0].is_finite() && columns[1].is_finite() && columns[2].is_finite();
+}
+
Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
Transform2D return_trans = Transform2D(get_rotation(), get_origin());
Vector2 target_position = affine_inverse().xform(p_target);
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index f23f32867a..2b11f36535 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -98,6 +98,7 @@ struct _NO_DISCARD_ Transform2D {
void orthonormalize();
Transform2D orthonormalized() const;
bool is_equal_approx(const Transform2D &p_transform) const;
+ bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const;
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index 6741ef4034..3285cbd664 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -174,6 +174,10 @@ bool Transform3D::is_equal_approx(const Transform3D &p_transform) const {
return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin);
}
+bool Transform3D::is_finite() const {
+ return basis.is_finite() && origin.is_finite();
+}
+
bool Transform3D::operator==(const Transform3D &p_transform) const {
return (basis == p_transform.basis && origin == p_transform.origin);
}
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index 44d6d826f3..cb347aa1c1 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -75,6 +75,7 @@ struct _NO_DISCARD_ Transform3D {
void orthogonalize();
Transform3D orthogonalized() const;
bool is_equal_approx(const Transform3D &p_transform) const;
+ bool is_finite() const;
bool operator==(const Transform3D &p_transform) const;
bool operator!=(const Transform3D &p_transform) const;
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index 56dbba393a..5366587126 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -186,6 +186,10 @@ bool Vector2::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y);
}
+bool Vector2::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y);
+}
+
Vector2::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 75364f72f0..5775d8e735 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -121,6 +121,7 @@ struct _NO_DISCARD_ Vector2 {
bool is_equal_approx(const Vector2 &p_v) const;
bool is_zero_approx() const;
+ bool is_finite() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 55ba509144..b106200c4a 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -139,6 +139,10 @@ bool Vector3::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
}
+bool Vector3::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z);
+}
+
Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 62e810fb4d..19771eb312 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -136,6 +136,7 @@ struct _NO_DISCARD_ Vector3 {
bool is_equal_approx(const Vector3 &p_v) const;
bool is_zero_approx() const;
+ bool is_finite() const;
/* Operators */
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index 9fd980aaff..3b189f7ed4 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -64,6 +64,10 @@ bool Vector4::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
}
+bool Vector4::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
+}
+
real_t Vector4::length() const {
return Math::sqrt(length_squared());
}
diff --git a/core/math/vector4.h b/core/math/vector4.h
index ac7b6c3aee..7c4bdc1788 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -71,6 +71,7 @@ struct _NO_DISCARD_ Vector4 {
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
bool is_zero_approx() const;
+ bool is_finite() const;
real_t length() const;
void normalize();
Vector4 normalized() const;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index dbbcedca84..872c8357ae 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -4654,10 +4654,10 @@ String String::sprintf(const Array &values, bool *error) const {
double value = values[value_index];
bool is_negative = (value < 0);
String str = String::num(ABS(value), min_decimals);
- bool not_numeric = isinf(value) || isnan(value);
+ const bool is_finite = Math::is_finite(value);
// Pad decimals out.
- if (!not_numeric) {
+ if (is_finite) {
str = str.pad_decimals(min_decimals);
}
@@ -4665,7 +4665,7 @@ String String::sprintf(const Array &values, bool *error) const {
// Padding. Leave room for sign later if required.
int pad_chars_count = (is_negative || show_sign) ? min_chars - 1 : min_chars;
- String pad_char = (pad_with_zeros && !not_numeric) ? String("0") : String(" "); // Never pad NaN or inf with zeros
+ String pad_char = (pad_with_zeros && is_finite) ? String("0") : String(" "); // Never pad NaN or inf with zeros
if (left_justified) {
str = str.rpad(pad_chars_count, pad_char);
} else {
@@ -4716,10 +4716,10 @@ String String::sprintf(const Array &values, bool *error) const {
for (int i = 0; i < count; i++) {
double val = vec[i];
String number_str = String::num(ABS(val), min_decimals);
- bool not_numeric = isinf(val) || isnan(val);
+ const bool is_finite = Math::is_finite(val);
// Pad decimals out.
- if (!not_numeric) {
+ if (is_finite) {
number_str = number_str.pad_decimals(min_decimals);
}
@@ -4727,7 +4727,7 @@ String String::sprintf(const Array &values, bool *error) const {
// Padding. Leave room for sign later if required.
int pad_chars_count = val < 0 ? min_chars - 1 : min_chars;
- String pad_char = (pad_with_zeros && !not_numeric) ? String("0") : String(" "); // Never pad NaN or inf with zeros
+ String pad_char = (pad_with_zeros && is_finite) ? String("0") : String(" "); // Never pad NaN or inf with zeros
if (left_justified) {
number_str = number_str.rpad(pad_chars_count, pad_char);
} else {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 1831f7b72a..900e3d8e77 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1606,6 +1606,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, is_normalized, sarray(), varray());
bind_method(Vector2, is_equal_approx, sarray("to"), varray());
bind_method(Vector2, is_zero_approx, sarray(), varray());
+ bind_method(Vector2, is_finite, sarray(), varray());
bind_method(Vector2, posmod, sarray("mod"), varray());
bind_method(Vector2, posmodv, sarray("modv"), varray());
bind_method(Vector2, project, sarray("b"), varray());
@@ -1653,6 +1654,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2, has_area, sarray(), varray());
bind_method(Rect2, has_point, sarray("point"), varray());
bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
+ bind_method(Rect2, is_finite, sarray(), varray());
bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
bind_method(Rect2, encloses, sarray("b"), varray());
bind_method(Rect2, intersection, sarray("b"), varray());
@@ -1695,6 +1697,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, is_normalized, sarray(), varray());
bind_method(Vector3, is_equal_approx, sarray("to"), varray());
bind_method(Vector3, is_zero_approx, sarray(), varray());
+ bind_method(Vector3, is_finite, sarray(), varray());
bind_method(Vector3, inverse, sarray(), varray());
bind_method(Vector3, clamp, sarray("min", "max"), varray());
bind_method(Vector3, snapped, sarray("step"), varray());
@@ -1759,6 +1762,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4, inverse, sarray(), varray());
bind_method(Vector4, is_equal_approx, sarray("with"), varray());
bind_method(Vector4, is_zero_approx, sarray(), varray());
+ bind_method(Vector4, is_finite, sarray(), varray());
/* Vector4i */
@@ -1775,6 +1779,7 @@ static void _register_variant_builtin_methods() {
bind_method(Plane, normalized, sarray(), varray());
bind_method(Plane, center, sarray(), varray());
bind_method(Plane, is_equal_approx, sarray("to_plane"), varray());
+ bind_method(Plane, is_finite, sarray(), varray());
bind_method(Plane, is_point_over, sarray("point"), varray());
bind_method(Plane, distance_to, sarray("point"), varray());
bind_method(Plane, has_point, sarray("point", "tolerance"), varray(CMP_EPSILON));
@@ -1790,6 +1795,7 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, normalized, sarray(), varray());
bind_method(Quaternion, is_normalized, sarray(), varray());
bind_method(Quaternion, is_equal_approx, sarray("to"), varray());
+ bind_method(Quaternion, is_finite, sarray(), varray());
bind_method(Quaternion, inverse, sarray(), varray());
bind_method(Quaternion, log, sarray(), varray());
bind_method(Quaternion, exp, sarray(), varray());
@@ -1909,6 +1915,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform2D, is_finite, sarray(), varray());
bind_method(Transform2D, set_rotation, sarray("rotation"), varray());
bind_method(Transform2D, set_scale, sarray("scale"), varray());
bind_method(Transform2D, set_skew, sarray("skew"), varray());
@@ -1929,6 +1936,7 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, tdotz, sarray("with"), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
bind_method(Basis, is_equal_approx, sarray("b"), varray());
+ bind_method(Basis, is_finite, sarray(), varray());
bind_method(Basis, get_rotation_quaternion, sarray(), varray());
bind_static_method(Basis, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_static_method(Basis, from_scale, sarray("scale"), varray());
@@ -1943,6 +1951,7 @@ static void _register_variant_builtin_methods() {
bind_method(AABB, has_surface, sarray(), varray());
bind_method(AABB, has_point, sarray("point"), varray());
bind_method(AABB, is_equal_approx, sarray("aabb"), varray());
+ bind_method(AABB, is_finite, sarray(), varray());
bind_method(AABB, intersects, sarray("with"), varray());
bind_method(AABB, encloses, sarray("with"), varray());
bind_method(AABB, intersects_plane, sarray("plane"), varray());
@@ -1975,6 +1984,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform3D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform3D, is_finite, sarray(), varray());
/* Projection */
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 670b66d53e..3843c32bcc 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -310,6 +310,10 @@ struct VariantUtilityFunctions {
return Math::is_zero_approx(x);
}
+ static inline bool is_finite(double x) {
+ return Math::is_finite(x);
+ }
+
static inline double ease(float x, float curve) {
return Math::ease(x, curve);
}
@@ -1420,6 +1424,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(is_equal_approx, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(is_zero_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(is_finite, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 6e9e82bbf0..43f85fcdbc 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -476,6 +476,13 @@
Infinity values of the same sign are considered equal.
</description>
</method>
+ <method name="is_finite">
+ <return type="bool" />
+ <param index="0" name="x" type="float" />
+ <description>
+ Returns whether [code]x[/code] is a finite value, i.e. it is not [constant @GDScript.NAN], positive infinity, or negative infinity.
+ </description>
+ </method>
<method name="is_inf">
<return type="bool" />
<param index="0" name="x" type="float" />
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 23dd41f275..1ac3e6b64c 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -205,6 +205,12 @@
Returns [code]true[/code] if this [AABB] and [param aabb] are approximately equal, by calling [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this [AABB] is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="merge" qualifiers="const">
<return type="AABB" />
<param index="0" name="with" type="AABB" />
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index 6d9b679fbc..f499be34a0 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -112,6 +112,12 @@
Returns [code]true[/code] if this basis and [param b] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this basis is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="looking_at" qualifiers="static">
<return type="Basis" />
<param index="0" name="target" type="Vector3" />
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index e51e3753fc..fbe8afa8d1 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -119,6 +119,12 @@
Returns [code]true[/code] if this plane and [param to_plane] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this plane is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_point_over" qualifiers="const">
<return type="bool" />
<param index="0" name="point" type="Vector3" />
diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml
index f21ebf57e2..99dffeff9d 100644
--- a/doc/classes/Quaternion.xml
+++ b/doc/classes/Quaternion.xml
@@ -115,6 +115,12 @@
Returns [code]true[/code] if this quaternion and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this quaternion is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index ac012e9604..28fe42afae 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -165,6 +165,12 @@
Returns [code]true[/code] if this [Rect2] and [param rect] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this [Rect2] is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="merge" qualifiers="const">
<return type="Rect2" />
<param index="0" name="b" type="Rect2" />
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 905b3d77af..23d20a5a75 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -123,6 +123,12 @@
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this transform is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="looking_at" qualifiers="const">
<return type="Transform2D" />
<param index="0" name="target" type="Vector2" default="Vector2(0, 0)" />
diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml
index 18b4f9e6f9..b3145ea022 100644
--- a/doc/classes/Transform3D.xml
+++ b/doc/classes/Transform3D.xml
@@ -82,6 +82,12 @@
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this transform is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="looking_at" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="target" type="Vector3" />
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index e1852340c0..5590f82336 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -206,6 +206,12 @@
Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 1ef84050cd..81e8dd2260 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -174,6 +174,12 @@
Returns [code]true[/code] if this vector and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml
index fdc93f82ec..662d0bce3a 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -135,6 +135,12 @@
Returns [code]true[/code] if this vector and [param with] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 2b25e8962f..d0cb46dee9 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -869,12 +869,7 @@ void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D
for (int i = 0; i < 4; i++) {
const Vector3 &v = i < 3 ? p_transform.basis.rows[i] : p_transform.origin;
- ERR_FAIL_COND(Math::is_inf(v.x));
- ERR_FAIL_COND(Math::is_nan(v.x));
- ERR_FAIL_COND(Math::is_inf(v.y));
- ERR_FAIL_COND(Math::is_nan(v.y));
- ERR_FAIL_COND(Math::is_inf(v.z));
- ERR_FAIL_COND(Math::is_nan(v.z));
+ ERR_FAIL_COND(!v.is_finite());
}
#endif
diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h
index d5f54a139e..ebaf441abf 100644
--- a/tests/core/math/test_aabb.h
+++ b/tests/core/math/test_aabb.h
@@ -389,6 +389,27 @@ TEST_CASE("[AABB] Expanding") {
aabb.expand(Vector3(-20, 0, 0)).is_equal_approx(AABB(Vector3(-20, 0, -2.5), Vector3(22.5, 7, 6))),
"expand() with non-contained point should return the expected AABB.");
}
+
+TEST_CASE("[AABB] Finite number checks") {
+ const Vector3 x(0, 1, 2);
+ const Vector3 infinite(NAN, NAN, NAN);
+
+ CHECK_MESSAGE(
+ AABB(x, x).is_finite(),
+ "AABB with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ AABB(infinite, x).is_finite(),
+ "AABB with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ AABB(x, infinite).is_finite(),
+ "AABB with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ AABB(infinite, infinite).is_finite(),
+ "AABB with two components infinite should not be finite.");
+}
+
} // namespace TestAABB
#endif // TEST_AABB_H
diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h
index b6493c5726..a65020597a 100644
--- a/tests/core/math/test_basis.h
+++ b/tests/core/math/test_basis.h
@@ -334,6 +334,40 @@ TEST_CASE("[Basis] Set axis angle") {
bugNan.get_axis_angle(axis, angle);
CHECK(!Math::is_nan(angle));
}
+
+TEST_CASE("[Basis] Finite number checks") {
+ const Vector3 x(0, 1, 2);
+ const Vector3 infinite(NAN, NAN, NAN);
+
+ CHECK_MESSAGE(
+ Basis(x, x, x).is_finite(),
+ "Basis with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(infinite, x, x).is_finite(),
+ "Basis with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Basis(x, infinite, x).is_finite(),
+ "Basis with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Basis(x, x, infinite).is_finite(),
+ "Basis with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(infinite, infinite, x).is_finite(),
+ "Basis with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Basis(infinite, x, infinite).is_finite(),
+ "Basis with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Basis(x, infinite, infinite).is_finite(),
+ "Basis with two components infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(infinite, infinite, infinite).is_finite(),
+ "Basis with three components infinite should not be finite.");
+}
+
} // namespace TestBasis
#endif // TEST_BASIS_H
diff --git a/tests/core/math/test_plane.h b/tests/core/math/test_plane.h
index d81a5af1ce..84d9a0ff7d 100644
--- a/tests/core/math/test_plane.h
+++ b/tests/core/math/test_plane.h
@@ -167,6 +167,29 @@ TEST_CASE("[Plane] Intersection") {
vec_out.is_equal_approx(Vector3(1, 1, 1)),
"intersects_segment() should modify vec_out to the expected result.");
}
+
+TEST_CASE("[Plane] Finite number checks") {
+ const Vector3 x(0, 1, 2);
+ const Vector3 infinite_vec(NAN, NAN, NAN);
+ const real_t y = 0;
+ const real_t infinite_y = NAN;
+
+ CHECK_MESSAGE(
+ Plane(x, y).is_finite(),
+ "Plane with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Plane(x, infinite_y).is_finite(),
+ "Plane with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Plane(infinite_vec, y).is_finite(),
+ "Plane with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Plane(infinite_vec, infinite_y).is_finite(),
+ "Plane with two components infinite should not be finite.");
+}
+
} // namespace TestPlane
#endif // TEST_PLANE_H
diff --git a/tests/core/math/test_quaternion.h b/tests/core/math/test_quaternion.h
index 63d30759bb..d1912cbf42 100644
--- a/tests/core/math/test_quaternion.h
+++ b/tests/core/math/test_quaternion.h
@@ -384,6 +384,63 @@ TEST_CASE("[Stress][Quaternion] Many vector xforms") {
}
}
+TEST_CASE("[Quaternion] Finite number checks") {
+ const real_t x = NAN;
+
+ CHECK_MESSAGE(
+ Quaternion(0, 1, 2, 3).is_finite(),
+ "Quaternion with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, 1, 2, 3).is_finite(),
+ "Quaternion with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, x, 2, 3).is_finite(),
+ "Quaternion with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, 1, x, 3).is_finite(),
+ "Quaternion with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, 1, 2, x).is_finite(),
+ "Quaternion with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, x, 2, 3).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, 1, x, 3).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, 1, 2, x).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, x, x, 3).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, x, 2, x).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, 1, x, x).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, x, x, x).is_finite(),
+ "Quaternion with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, 1, x, x).is_finite(),
+ "Quaternion with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, x, 2, x).is_finite(),
+ "Quaternion with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, x, x, 3).is_finite(),
+ "Quaternion with three components infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, x, x, x).is_finite(),
+ "Quaternion with four components infinite should not be finite.");
+}
+
} // namespace TestQuaternion
#endif // TEST_QUATERNION_H
diff --git a/tests/core/math/test_rect2.h b/tests/core/math/test_rect2.h
index 6323b214db..d784875c1c 100644
--- a/tests/core/math/test_rect2.h
+++ b/tests/core/math/test_rect2.h
@@ -300,6 +300,27 @@ TEST_CASE("[Rect2] Merging") {
Rect2(0, 100, 1280, 720).merge(Rect2(-4000, -4000, 100, 100)).is_equal_approx(Rect2(-4000, -4000, 5280, 4820)),
"merge() with non-enclosed Rect2 should return the expected result.");
}
+
+TEST_CASE("[Rect2] Finite number checks") {
+ const Vector2 x(0, 1);
+ const Vector2 infinite(NAN, NAN);
+
+ CHECK_MESSAGE(
+ Rect2(x, x).is_finite(),
+ "Rect2 with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Rect2(infinite, x).is_finite(),
+ "Rect2 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Rect2(x, infinite).is_finite(),
+ "Rect2 with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Rect2(infinite, infinite).is_finite(),
+ "Rect2 with two components infinite should not be finite.");
+}
+
} // namespace TestRect2
#endif // TEST_RECT2_H
diff --git a/tests/core/math/test_transform_2d.h b/tests/core/math/test_transform_2d.h
index 697bf63fc5..ab51bcd7da 100644
--- a/tests/core/math/test_transform_2d.h
+++ b/tests/core/math/test_transform_2d.h
@@ -83,6 +83,40 @@ TEST_CASE("[Transform2D] rotation") {
CHECK(orig.rotated(phi) == R * orig);
CHECK(orig.rotated_local(phi) == orig * R);
}
+
+TEST_CASE("[Transform2D] Finite number checks") {
+ const Vector2 x(0, 1);
+ const Vector2 infinite(NAN, NAN);
+
+ CHECK_MESSAGE(
+ Transform2D(x, x, x).is_finite(),
+ "Transform2D with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Transform2D(infinite, x, x).is_finite(),
+ "Transform2D with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform2D(x, infinite, x).is_finite(),
+ "Transform2D with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform2D(x, x, infinite).is_finite(),
+ "Transform2D with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Transform2D(infinite, infinite, x).is_finite(),
+ "Transform2D with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform2D(infinite, x, infinite).is_finite(),
+ "Transform2D with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform2D(x, infinite, infinite).is_finite(),
+ "Transform2D with two components infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Transform2D(infinite, infinite, infinite).is_finite(),
+ "Transform2D with three components infinite should not be finite.");
+}
+
} // namespace TestTransform2D
#endif // TEST_TRANSFORM_2D_H
diff --git a/tests/core/math/test_transform_3d.h b/tests/core/math/test_transform_3d.h
index da166b43f7..d2730f3577 100644
--- a/tests/core/math/test_transform_3d.h
+++ b/tests/core/math/test_transform_3d.h
@@ -84,6 +84,29 @@ TEST_CASE("[Transform3D] rotation") {
CHECK(orig.rotated(axis, phi) == R * orig);
CHECK(orig.rotated_local(axis, phi) == orig * R);
}
+
+TEST_CASE("[Transform3D] Finite number checks") {
+ const Vector3 y(0, 1, 2);
+ const Vector3 infinite_vec(NAN, NAN, NAN);
+ const Basis x(y, y, y);
+ const Basis infinite_basis(infinite_vec, infinite_vec, infinite_vec);
+
+ CHECK_MESSAGE(
+ Transform3D(x, y).is_finite(),
+ "Transform3D with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Transform3D(x, infinite_vec).is_finite(),
+ "Transform3D with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform3D(infinite_basis, y).is_finite(),
+ "Transform3D with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Transform3D(infinite_basis, infinite_vec).is_finite(),
+ "Transform3D with two components infinite should not be finite.");
+}
+
} // namespace TestTransform3D
#endif // TEST_TRANSFORM_3D_H
diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h
index 0d7f1163e4..a87b9ffc02 100644
--- a/tests/core/math/test_vector2.h
+++ b/tests/core/math/test_vector2.h
@@ -465,6 +465,32 @@ TEST_CASE("[Vector2] Linear algebra methods") {
Math::is_equal_approx(Vector2(-a.x, a.y).dot(Vector2(b.x, -b.y)), (real_t)-57.3),
"Vector2 dot should return expected value.");
}
+
+TEST_CASE("[Vector2] Finite number checks") {
+ const double infinite[] = { NAN, INFINITY, -INFINITY };
+
+ CHECK_MESSAGE(
+ Vector2(0, 1).is_finite(),
+ "Vector2(0, 1) should be finite");
+
+ for (double x : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector2(x, 1).is_finite(),
+ "Vector2 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector2(0, x).is_finite(),
+ "Vector2 with one component infinite should not be finite.");
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector2(x, y).is_finite(),
+ "Vector2 with two components infinite should not be finite.");
+ }
+ }
+}
+
} // namespace TestVector2
#endif // TEST_VECTOR2_H
diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h
index be271bad1f..4932cd04db 100644
--- a/tests/core/math/test_vector3.h
+++ b/tests/core/math/test_vector3.h
@@ -479,6 +479,51 @@ TEST_CASE("[Vector3] Linear algebra methods") {
Math::is_equal_approx(Vector3(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)), (real_t)-75.24),
"Vector3 dot should return expected value.");
}
+
+TEST_CASE("[Vector3] Finite number checks") {
+ const double infinite[] = { NAN, INFINITY, -INFINITY };
+
+ CHECK_MESSAGE(
+ Vector3(0, 1, 2).is_finite(),
+ "Vector3(0, 1, 2) should be finite");
+
+ for (double x : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector3(x, 1, 2).is_finite(),
+ "Vector3 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector3(0, x, 2).is_finite(),
+ "Vector3 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector3(0, 1, x).is_finite(),
+ "Vector3 with one component infinite should not be finite.");
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector3(x, y, 2).is_finite(),
+ "Vector3 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector3(x, 1, y).is_finite(),
+ "Vector3 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector3(0, x, y).is_finite(),
+ "Vector3 with two components infinite should not be finite.");
+ }
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ for (double z : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector3(x, y, z).is_finite(),
+ "Vector3 with three components infinite should not be finite.");
+ }
+ }
+ }
+}
+
} // namespace TestVector3
#endif // TEST_VECTOR3_H
diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h
index 3f50f16635..b31db56f67 100644
--- a/tests/core/math/test_vector4.h
+++ b/tests/core/math/test_vector4.h
@@ -314,6 +314,84 @@ TEST_CASE("[Vector4] Linear algebra methods") {
Math::is_equal_approx((vector1 * 2).dot(vector2 * 4), (real_t)-25.9 * 8),
"Vector4 dot product should work as expected.");
}
+
+TEST_CASE("[Vector4] Finite number checks") {
+ const double infinite[] = { NAN, INFINITY, -INFINITY };
+
+ CHECK_MESSAGE(
+ Vector4(0, 1, 2, 3).is_finite(),
+ "Vector4(0, 1, 2, 3) should be finite");
+
+ for (double x : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, 1, 2, 3).is_finite(),
+ "Vector4 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, x, 2, 3).is_finite(),
+ "Vector4 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, 1, x, 3).is_finite(),
+ "Vector4 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, 1, 2, x).is_finite(),
+ "Vector4 with one component infinite should not be finite.");
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, y, 2, 3).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, 1, y, 3).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, 1, 2, y).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, x, y, 3).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, x, 2, y).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, 1, x, y).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ }
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ for (double z : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, x, y, z).is_finite(),
+ "Vector4 with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, 1, y, z).is_finite(),
+ "Vector4 with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, y, 2, z).is_finite(),
+ "Vector4 with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, y, z, 3).is_finite(),
+ "Vector4 with three components infinite should not be finite.");
+ }
+ }
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ for (double z : infinite) {
+ for (double w : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, y, z, w).is_finite(),
+ "Vector4 with four components infinite should not be finite.");
+ }
+ }
+ }
+ }
+}
+
} // namespace TestVector4
#endif // TEST_VECTOR4_H