Merge pull request #116427 from TokageItLab/normalizable

Add finite check for `normalize()` in vector classes
This commit is contained in:
Thaddeus Crews 2026-03-12 09:03:39 -05:00
commit 106cff7567
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
11 changed files with 69 additions and 20 deletions

View file

@ -54,7 +54,8 @@ void Basis::invert() {
}
void Basis::orthonormalize() {
// Gram-Schmidt Process
// Orthonormalizable check is done in Vector3 class below.
// Gram-Schmidt Process:
Vector3 x = get_column(0);
Vector3 y = get_column(1);

View file

@ -38,9 +38,15 @@ void Plane::set_normal(const Vector3 &p_normal) {
}
void Plane::normalize() {
#ifdef MATH_CHECKS
if (!is_finite()) {
WARN_PRINT("Plane cannot be normalized, the distance and the normal should be finite.");
}
#endif // MATH_CHECKS
real_t l = normal.length();
if (l == 0) {
*this = Plane(0, 0, 0, 0);
zero();
return;
}
normal /= l;

View file

@ -45,6 +45,11 @@ struct [[nodiscard]] Plane {
void set_normal(const Vector3 &p_normal);
_FORCE_INLINE_ Vector3 get_normal() const { return normal; }
void zero() {
normal.zero();
d = 0;
}
void normalize();
Plane normalized() const;

View file

@ -63,6 +63,11 @@ real_t Quaternion::length() const {
}
void Quaternion::normalize() {
#ifdef MATH_CHECKS
if (!is_finite()) {
WARN_PRINT("Quaternion cannot be normalized, the elements should be finite.");
}
#endif // MATH_CHECKS
*this /= length();
}

View file

@ -145,7 +145,8 @@ void Transform2D::translate_local(const Vector2 &p_translation) {
}
void Transform2D::orthonormalize() {
// Gram-Schmidt Process
// Orthonormalizable check is done in Vector2 class below.
// Gram-Schmidt Process:
Vector2 x = columns[0];
Vector2 y = columns[1];

View file

@ -150,6 +150,7 @@ Transform3D Transform3D::translated_local(const Vector3 &p_translation) const {
}
void Transform3D::orthonormalize() {
// Orthonormalizable check is done in Basis class below.
basis.orthonormalize();
}

View file

@ -50,8 +50,18 @@ real_t Vector2::length_squared() const {
}
void Vector2::normalize() {
real_t l = x * x + y * y;
if (l != 0) {
if (!is_finite()) {
#ifdef MATH_CHECKS
WARN_PRINT("Vector2 cannot be normalized, the elements must be finite. Making (0, 0) as a fallback.");
#endif // MATH_CHECKS
zero();
return;
}
real_t l = length_squared();
if (l == 0) {
zero();
} else {
l = Math::sqrt(l);
x /= l;
y /= l;

View file

@ -91,6 +91,8 @@ struct [[nodiscard]] Vector2 {
real_t length_squared() const;
Vector2 limit_length(real_t p_len = 1.0) const;
void zero() { x = y = 0; }
Vector2 min(const Vector2 &p_vector2) const {
return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y));
}

View file

@ -546,14 +546,22 @@ real_t Vector3::length_squared() const {
}
void Vector3::normalize() {
real_t lengthsq = length_squared();
if (lengthsq == 0) {
x = y = z = 0;
if (!is_finite()) {
#ifdef MATH_CHECKS
WARN_PRINT("Vector3 cannot be normalized, the elements must be finite. Making (0, 0, 0) as a fallback.");
#endif // MATH_CHECKS
zero();
return;
}
real_t l = length_squared();
if (l == 0) {
zero();
} else {
real_t length = Math::sqrt(lengthsq);
x /= length;
y /= length;
z /= length;
l = Math::sqrt(l);
x /= l;
y /= l;
z /= l;
}
}

View file

@ -79,15 +79,23 @@ real_t Vector4::length() const {
}
void Vector4::normalize() {
real_t lengthsq = length_squared();
if (lengthsq == 0) {
x = y = z = w = 0;
if (!is_finite()) {
#ifdef MATH_CHECKS
WARN_PRINT("Vector4 cannot be normalized, the elements must be finite. Making (0, 0, 0, 0) as a fallback.");
#endif // MATH_CHECKS
zero();
return;
}
real_t l = length_squared();
if (l == 0) {
zero();
} else {
real_t length = Math::sqrt(lengthsq);
x /= length;
y /= length;
z /= length;
w /= length;
l = Math::sqrt(l);
x /= l;
y /= l;
z /= l;
w /= l;
}
}

View file

@ -98,6 +98,8 @@ struct [[nodiscard]] Vector4 {
Vector4 normalized() const;
bool is_normalized() const;
void zero() { x = y = z = w = 0; }
real_t distance_to(const Vector4 &p_to) const;
real_t distance_squared_to(const Vector4 &p_to) const;
Vector4 direction_to(const Vector4 &p_to) const;