Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add is_conformal method to Basis and Transform2D #79523

Merged
merged 1 commit into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions core/math/basis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ bool Basis::is_orthogonal() const {
return m.is_equal_approx(identity);
}

bool Basis::is_conformal() const {
const Vector3 x = get_column(0);
const Vector3 y = get_column(1);
const Vector3 z = get_column(2);
const real_t x_len_sq = x.length_squared();
return Math::is_equal_approx(x_len_sq, y.length_squared()) && Math::is_equal_approx(x_len_sq, z.length_squared()) && Math::is_zero_approx(x.dot(y)) && Math::is_zero_approx(x.dot(z)) && Math::is_zero_approx(y.dot(z));
}

bool Basis::is_diagonal() const {
return (
Math::is_zero_approx(rows[0][1]) && Math::is_zero_approx(rows[0][2]) &&
Expand Down
1 change: 1 addition & 0 deletions core/math/basis.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ Basis operator*(const real_t p_val) const;

bool is_orthogonal() const;
bool is_conformal() const;
bool is_diagonal() const;
bool is_rotation() const;

Expand Down
12 changes: 12 additions & 0 deletions core/math/transform_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ Transform2D Transform2D::orthonormalized() const {
return ortho;
}

bool Transform2D::is_conformal() const {
// Non-flipped case.
if (Math::is_equal_approx(columns[0][0], columns[1][1]) && Math::is_equal_approx(columns[0][1], -columns[1][0])) {
return true;
}
// Flipped case.
if (Math::is_equal_approx(columns[0][0], -columns[1][1]) && Math::is_equal_approx(columns[0][1], columns[1][0])) {
return true;
}
return false;
}

aaronfranke marked this conversation as resolved.
Show resolved Hide resolved
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]);
}
Expand Down
1 change: 1 addition & 0 deletions core/math/transform_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ struct _NO_DISCARD_ Transform2D {

void orthonormalize();
Transform2D orthonormalized() const;
bool is_conformal() const;
bool is_equal_approx(const Transform2D &p_transform) const;
bool is_finite() const;

Expand Down
2 changes: 2 additions & 0 deletions core/variant/variant_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2076,6 +2076,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, basis_xform, sarray("v"), varray());
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform2D, is_conformal, sarray(), varray());
bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
bind_method(Transform2D, is_finite, sarray(), varray());
// Do not bind functions like set_rotation, set_scale, set_skew, etc because this type is immutable and can't be modified.
Expand All @@ -2095,6 +2096,7 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, tdoty, sarray("with"), varray());
bind_method(Basis, tdotz, sarray("with"), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
bind_method(Basis, is_conformal, sarray(), 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());
Expand Down
6 changes: 6 additions & 0 deletions doc/classes/Basis.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@
Returns the inverse of the matrix.
</description>
</method>
<method name="is_conformal" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the basis is conformal, meaning it preserves angles and distance ratios, and may only be composed of rotation and uniform scale. Returns [code]false[/code] if the basis has non-uniform scale or shear/skew. This can be used to validate if the basis is non-distorted, which is important for physics and other use cases.
</description>
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
<param index="0" name="b" type="Basis" />
Expand Down
6 changes: 6 additions & 0 deletions doc/classes/Transform2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use [method affine_inverse] for transforms with scaling).
</description>
</method>
<method name="is_conformal" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the transform's basis is conformal, meaning it preserves angles and distance ratios, and may only be composed of rotation and uniform scale. Returns [code]false[/code] if the transform's basis has non-uniform scale or shear/skew. This can be used to validate if the transform is non-distorted, which is important for physics and other use cases.
</description>
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
<param index="0" name="xform" type="Transform2D" />
Expand Down
30 changes: 30 additions & 0 deletions tests/core/math/test_basis.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,36 @@ TEST_CASE("[Basis] Finite number checks") {
"Basis with three components infinite should not be finite.");
}

TEST_CASE("[Basis] Is conformal checks") {
CHECK_MESSAGE(
Basis().is_conformal(),
"Identity Basis should be conformal.");

CHECK_MESSAGE(
Basis::from_euler(Vector3(1.2, 3.4, 5.6)).is_conformal(),
"Basis with only rotation should be conformal.");

CHECK_MESSAGE(
Basis::from_scale(Vector3(-1, -1, -1)).is_conformal(),
"Basis with only a flip should be conformal.");

CHECK_MESSAGE(
Basis::from_scale(Vector3(1.2, 1.2, 1.2)).is_conformal(),
"Basis with only uniform scale should be conformal.");

CHECK_MESSAGE(
Basis(Vector3(3, 4, 0), Vector3(4, -3, 0.0), Vector3(0, 0, 5)).is_conformal(),
"Basis with a flip, rotation, and uniform scale should be conformal.");

CHECK_FALSE_MESSAGE(
Basis::from_scale(Vector3(1.2, 3.4, 5.6)).is_conformal(),
"Basis with non-uniform scale should not be conformal.");

CHECK_FALSE_MESSAGE(
Basis(Vector3(Math_SQRT12, Math_SQRT12, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)).is_conformal(),
"Basis with the X axis skewed 45 degrees should not be conformal.");
}

} // namespace TestBasis

#endif // TEST_BASIS_H
30 changes: 30 additions & 0 deletions tests/core/math/test_transform_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,36 @@ TEST_CASE("[Transform2D] Finite number checks") {
"Transform2D with three components infinite should not be finite.");
}

TEST_CASE("[Transform2D] Is conformal checks") {
CHECK_MESSAGE(
Transform2D().is_conformal(),
"Identity Transform2D should be conformal.");

CHECK_MESSAGE(
Transform2D(1.2, Vector2()).is_conformal(),
"Transform2D with only rotation should be conformal.");

CHECK_MESSAGE(
Transform2D(Vector2(1, 0), Vector2(0, -1), Vector2()).is_conformal(),
"Transform2D with only a flip should be conformal.");

CHECK_MESSAGE(
Transform2D(Vector2(1.2, 0), Vector2(0, 1.2), Vector2()).is_conformal(),
"Transform2D with only uniform scale should be conformal.");

CHECK_MESSAGE(
Transform2D(Vector2(1.2, 3.4), Vector2(3.4, -1.2), Vector2()).is_conformal(),
"Transform2D with a flip, rotation, and uniform scale should be conformal.");

CHECK_FALSE_MESSAGE(
Transform2D(Vector2(1.2, 0), Vector2(0, 3.4), Vector2()).is_conformal(),
"Transform2D with non-uniform scale should not be conformal.");

CHECK_FALSE_MESSAGE(
Transform2D(Vector2(Math_SQRT12, Math_SQRT12), Vector2(0, 1), Vector2()).is_conformal(),
"Transform2D with the X axis skewed 45 degrees should not be conformal.");
}

} // namespace TestTransform2D

#endif // TEST_TRANSFORM_2D_H