From f242f9c7385f86c5bb5ebd8c56b5a6d6ebb59985 Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Sat, 30 Jul 2022 12:17:33 +0200 Subject: [PATCH] Fix consistency of translated/scaled/rotated in Transform2D and Transform3D --- core/math/transform_2d.cpp | 34 ++++--- core/math/transform_2d.h | 5 +- core/math/transform_3d.cpp | 30 +++++-- core/math/transform_3d.h | 3 + core/variant/variant_call.cpp | 6 ++ doc/classes/Transform2D.xml | 46 +++++++++- doc/classes/Transform3D.xml | 49 +++++++++- .../GodotSharp/GodotSharp/Core/Transform2D.cs | 57 ++++++++++-- .../GodotSharp/GodotSharp/Core/Transform3D.cs | 58 ++++++++++-- tests/core/math/test_transform_2d.h | 88 ++++++++++++++++++ tests/core/math/test_transform_3d.h | 89 +++++++++++++++++++ tests/test_main.cpp | 2 + 12 files changed, 426 insertions(+), 41 deletions(-) create mode 100644 tests/core/math/test_transform_2d.h create mode 100644 tests/core/math/test_transform_3d.h diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index bb8bf9f5696..226076029b2 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -217,16 +217,22 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const { return t; } +Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const { + Transform2D copy = *this; + copy.scale_basis(p_scale); + return copy; +} + Transform2D Transform2D::scaled(const Size2 &p_scale) const { + // Equivalent to left multiplication Transform2D copy = *this; copy.scale(p_scale); return copy; } -Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const { - Transform2D copy = *this; - copy.scale_basis(p_scale); - return copy; +Transform2D Transform2D::scaled_local(const Size2 &p_scale) const { + // Equivalent to right multiplication + return Transform2D(columns[0] * p_scale.x, columns[1] * p_scale.y, columns[2]); } Transform2D Transform2D::untranslated() const { @@ -235,16 +241,24 @@ Transform2D Transform2D::untranslated() const { return copy; } +Transform2D Transform2D::translated(const Vector2 &p_offset) const { + // Equivalent to left multiplication + return Transform2D(columns[0], columns[1], columns[2] + p_offset); +} + Transform2D Transform2D::translated_local(const Vector2 &p_offset) const { - Transform2D copy = *this; - copy.translate_local(p_offset); - return copy; + // Equivalent to right multiplication + return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset)); } Transform2D Transform2D::rotated(const real_t p_angle) const { - Transform2D copy = *this; - copy.rotate(p_angle); - return copy; + // Equivalent to left multiplication + return Transform2D(p_angle, Vector2()) * (*this); +} + +Transform2D Transform2D::rotated_local(const real_t p_angle) const { + // Equivalent to right multiplication + return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped. } real_t Transform2D::basis_determinant() const { diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index e64d050f0c4..f23f32867a5 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -85,10 +85,13 @@ struct _NO_DISCARD_ Transform2D { _FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; } _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; } - Transform2D scaled(const Size2 &p_scale) const; Transform2D basis_scaled(const Size2 &p_scale) const; + Transform2D scaled(const Size2 &p_scale) const; + Transform2D scaled_local(const Size2 &p_scale) const; + Transform2D translated(const Vector2 &p_offset) const; Transform2D translated_local(const Vector2 &p_offset) const; Transform2D rotated(const real_t p_angle) const; + Transform2D rotated_local(const real_t p_angle) const; Transform2D untranslated() const; diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp index c497a276f32..a634faca9af 100644 --- a/core/math/transform_3d.cpp +++ b/core/math/transform_3d.cpp @@ -62,7 +62,15 @@ void Transform3D::rotate(const Vector3 &p_axis, real_t p_angle) { } Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_angle) const { - return Transform3D(Basis(p_axis, p_angle), Vector3()) * (*this); + // Equivalent to left multiplication + Basis p_basis(p_axis, p_angle); + return Transform3D(p_basis * basis, p_basis.xform(origin)); +} + +Transform3D Transform3D::rotated_local(const Vector3 &p_axis, real_t p_angle) const { + // Equivalent to right multiplication + Basis p_basis(p_axis, p_angle); + return Transform3D(basis * p_basis, origin); } void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) { @@ -120,9 +128,13 @@ void Transform3D::scale(const Vector3 &p_scale) { } Transform3D Transform3D::scaled(const Vector3 &p_scale) const { - Transform3D t = *this; - t.scale(p_scale); - return t; + // Equivalent to left multiplication + return Transform3D(basis.scaled(p_scale), origin * p_scale); +} + +Transform3D Transform3D::scaled_local(const Vector3 &p_scale) const { + // Equivalent to right multiplication + return Transform3D(basis.scaled_local(p_scale), origin); } void Transform3D::scale_basis(const Vector3 &p_scale) { @@ -139,10 +151,14 @@ void Transform3D::translate_local(const Vector3 &p_translation) { } } +Transform3D Transform3D::translated(const Vector3 &p_translation) const { + // Equivalent to left multiplication + return Transform3D(basis, origin + p_translation); +} + Transform3D Transform3D::translated_local(const Vector3 &p_translation) const { - Transform3D t = *this; - t.translate_local(p_translation); - return t; + // Equivalent to right multiplication + return Transform3D(basis, origin + basis.xform(p_translation)); } void Transform3D::orthonormalize() { diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h index 1f8026043f2..b572e90859c 100644 --- a/core/math/transform_3d.h +++ b/core/math/transform_3d.h @@ -46,6 +46,7 @@ struct _NO_DISCARD_ Transform3D { Transform3D affine_inverse() const; Transform3D rotated(const Vector3 &p_axis, real_t p_angle) const; + Transform3D rotated_local(const Vector3 &p_axis, real_t p_angle) const; void rotate(const Vector3 &p_axis, real_t p_angle); void rotate_basis(const Vector3 &p_axis, real_t p_angle); @@ -55,9 +56,11 @@ struct _NO_DISCARD_ Transform3D { void scale(const Vector3 &p_scale); Transform3D scaled(const Vector3 &p_scale) const; + Transform3D scaled_local(const Vector3 &p_scale) const; void scale_basis(const Vector3 &p_scale); void translate_local(real_t p_tx, real_t p_ty, real_t p_tz); void translate_local(const Vector3 &p_translation); + Transform3D translated(const Vector3 &p_translation) const; Transform3D translated_local(const Vector3 &p_translation) const; const Basis &get_basis() const { return basis; } diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index b933a90a483..a774aac52f6 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1882,7 +1882,10 @@ static void _register_variant_builtin_methods() { bind_method(Transform2D, get_skew, sarray(), varray()); bind_method(Transform2D, orthonormalized, sarray(), varray()); bind_method(Transform2D, rotated, sarray("angle"), varray()); + bind_method(Transform2D, rotated_local, sarray("angle"), varray()); bind_method(Transform2D, scaled, sarray("scale"), varray()); + bind_method(Transform2D, scaled_local, sarray("scale"), varray()); + bind_method(Transform2D, translated, sarray("offset"), varray()); bind_method(Transform2D, translated_local, sarray("offset"), varray()); bind_method(Transform2D, basis_xform, sarray("v"), varray()); bind_method(Transform2D, basis_xform_inv, sarray("v"), varray()); @@ -1947,7 +1950,10 @@ static void _register_variant_builtin_methods() { bind_method(Transform3D, affine_inverse, sarray(), varray()); bind_method(Transform3D, orthonormalized, sarray(), varray()); bind_method(Transform3D, rotated, sarray("axis", "angle"), varray()); + bind_method(Transform3D, rotated_local, sarray("axis", "angle"), varray()); bind_method(Transform3D, scaled, sarray("scale"), varray()); + bind_method(Transform3D, scaled_local, sarray("scale"), varray()); + bind_method(Transform3D, translated, sarray("offset"), varray()); bind_method(Transform3D, translated_local, sarray("offset"), varray()); bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); bind_method(Transform3D, spherical_interpolate_with, sarray("xform", "weight"), varray()); diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml index 924b4cd8e44..9979a73527d 100644 --- a/doc/classes/Transform2D.xml +++ b/doc/classes/Transform2D.xml @@ -141,14 +141,40 @@ - Returns a copy of the transform rotated by the given [code]angle[/code] (in radians), using matrix multiplication. + Returns a copy of the transform rotated by the given [code]angle[/code] (in radians). + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding rotation transform [code]R[/code] from the left, i.e., [code]R * X[/code]. + This can be seen as transforming with respect to the global/parent frame. + + + + + + + Returns a copy of the transform rotated by the given [code]angle[/code] (in radians). + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding rotation transform [code]R[/code] from the right, i.e., [code]X * R[/code]. + This can be seen as transforming with respect to the local frame. - Returns a copy of the transform scaled by the given [code]scale[/code] factor, using matrix multiplication. + Returns a copy of the transform scaled by the given [code]scale[/code] factor. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding scaling transform [code]S[/code] from the left, i.e., [code]S * X[/code]. + This can be seen as transforming with respect to the global/parent frame. + + + + + + + Returns a copy of the transform scaled by the given [code]scale[/code] factor. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding scaling transform [code]S[/code] from the right, i.e., [code]X * S[/code]. + This can be seen as transforming with respect to the local frame. @@ -173,12 +199,24 @@ Sets the transform's skew (in radians). + + + + + Returns a copy of the transform translated by the given [code]offset[/code]. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding translation transform [code]T[/code] from the left, i.e., [code]T * X[/code]. + This can be seen as transforming with respect to the global/parent frame. + + - Returns a copy of the transform translated by the given [code]offset[/code], relative to the transform's basis vectors. - Unlike [method rotated] and [method scaled], this does not use matrix multiplication. + Returns a copy of the transform translated by the given [code]offset[/code]. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding translation transform [code]T[/code] from the right, i.e., [code]X * T[/code]. + This can be seen as transforming with respect to the local frame. diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml index de1db718c24..9b673701ae2 100644 --- a/doc/classes/Transform3D.xml +++ b/doc/classes/Transform3D.xml @@ -102,14 +102,43 @@ - Returns a copy of the transform rotated around the given [code]axis[/code] by the given [code]angle[/code] (in radians), using matrix multiplication. The [code]axis[/code] must be a normalized vector. + Returns a copy of the transform rotated around the given [code]axis[/code] by the given [code]angle[/code] (in radians). + The [code]axis[/code] must be a normalized vector. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding rotation transform [code]R[/code] from the left, i.e., [code]R * X[/code]. + This can be seen as transforming with respect to the global/parent frame. + + + + + + + + Returns a copy of the transform rotated around the given [code]axis[/code] by the given [code]angle[/code] (in radians). + The [code]axis[/code] must be a normalized vector. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding rotation transform [code]R[/code] from the right, i.e., [code]X * R[/code]. + This can be seen as transforming with respect to the local frame. - Returns a copy of the transform with its basis and origin scaled by the given [code]scale[/code] factor, using matrix multiplication. + Returns a copy of the transform scaled by the given [code]scale[/code] factor. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding scaling transform [code]S[/code] from the left, i.e., [code]S * X[/code]. + This can be seen as transforming with respect to the global/parent frame. + + + + + + + Returns a copy of the transform scaled by the given [code]scale[/code] factor. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding scaling transform [code]S[/code] from the right, i.e., [code]X * S[/code]. + This can be seen as transforming with respect to the local frame. @@ -120,12 +149,24 @@ Returns a transform spherically interpolated between this transform and another by a given [code]weight[/code] (on the range of 0.0 to 1.0). + + + + + Returns a copy of the transform translated by the given [code]offset[/code]. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding translation transform [code]T[/code] from the left, i.e., [code]T * X[/code]. + This can be seen as transforming with respect to the global/parent frame. + + - Returns a copy of the transform translated by the given [code]offset[/code], relative to the transform's basis vectors. - Unlike [method rotated] and [method scaled], this does not use matrix multiplication. + Returns a copy of the transform translated by the given [code]offset[/code]. + This method is an optimized version of multiplying the given transform [code]X[/code] + with a corresponding translation transform [code]T[/code] from the right, i.e., [code]X * T[/code]. + This can be seen as transforming with respect to the local frame. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index b8413f1e16b..68d097eb4e3 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -297,7 +297,9 @@ namespace Godot } /// - /// Rotates the transform by (in radians), using matrix multiplication. + /// Rotates the transform by (in radians). + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// /// The angle to rotate, in radians. /// The rotated transformation matrix. @@ -307,7 +309,21 @@ namespace Godot } /// - /// Scales the transform by the given scaling factor, using matrix multiplication. + /// Rotates the transform by (in radians). + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// + /// The angle to rotate, in radians. + /// The rotated transformation matrix. + public Transform2D RotatedLocal(real_t angle) + { + return new Transform2D(angle, new Vector2()) * this; + } + + /// + /// Scales the transform by the given scaling factor. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// /// The scale to introduce. /// The scaled transformation matrix. @@ -320,6 +336,21 @@ namespace Godot return copy; } + /// + /// Scales the transform by the given scaling factor. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// + /// The scale to introduce. + /// The scaled transformation matrix. + public Transform2D ScaledLocal(Vector2 scale) + { + Transform2D copy = this; + copy.x *= scale; + copy.y *= scale; + return copy; + } + private real_t Tdotx(Vector2 with) { return (this[0, 0] * with[0]) + (this[1, 0] * with[1]); @@ -331,11 +362,23 @@ namespace Godot } /// - /// Translates the transform by the given , - /// relative to the transform's basis vectors. - /// - /// Unlike and , - /// this does not use matrix multiplication. + /// Translates the transform by the given . + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. + /// + /// The offset to translate by. + /// The translated matrix. + public Transform2D Translated(Vector2 offset) + { + Transform2D copy = this; + copy.origin += offset; + return copy; + } + + /// + /// Translates the transform by the given . + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. /// /// The offset to translate by. /// The translated matrix. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 97b4a87713c..c00b9d8e9bc 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -186,8 +186,10 @@ namespace Godot } /// - /// Rotates the transform around the given by (in radians), - /// using matrix multiplication. The axis must be a normalized vector. + /// Rotates the transform around the given by (in radians). + /// The axis must be a normalized vector. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// /// The axis to rotate around. Must be normalized. /// The angle to rotate, in radians. @@ -198,7 +200,24 @@ namespace Godot } /// - /// Scales the transform by the given 3D scaling factor, using matrix multiplication. + /// Rotates the transform around the given by (in radians). + /// The axis must be a normalized vector. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// + /// The axis to rotate around. Must be normalized. + /// The angle to rotate, in radians. + /// The rotated transformation matrix. + public Transform3D RotatedLocal(Vector3 axis, real_t angle) + { + Basis tmpBasis = new Basis(axis, angle); + return new Transform3D(basis * tmpBasis, origin); + } + + /// + /// Scales the transform by the given 3D factor. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// /// The scale to introduce. /// The scaled transformation matrix. @@ -207,6 +226,19 @@ namespace Godot return new Transform3D(basis.Scaled(scale), origin * scale); } + /// + /// Scales the transform by the given 3D factor. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// + /// The scale to introduce. + /// The scaled transformation matrix. + public Transform3D ScaledLocal(Vector3 scale) + { + Basis tmpBasis = new Basis(new Vector3(scale.x, 0, 0), new Vector3(0, scale.y, 0), new Vector3(0, 0, scale.z)); + return new Transform3D(basis * tmpBasis, origin); + } + private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) { // Make rotation matrix @@ -231,11 +263,21 @@ namespace Godot } /// - /// Translates the transform by the given , - /// relative to the transform's basis vectors. - /// - /// Unlike and , - /// this does not use matrix multiplication. + /// Translates the transform by the given . + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. + /// + /// The offset to translate by. + /// The translated matrix. + public Transform3D Translated(Vector3 offset) + { + return new Transform3D(basis, origin + offset); + } + + /// + /// Translates the transform by the given . + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. /// /// The offset to translate by. /// The translated matrix. diff --git a/tests/core/math/test_transform_2d.h b/tests/core/math/test_transform_2d.h new file mode 100644 index 00000000000..697bf63fc57 --- /dev/null +++ b/tests/core/math/test_transform_2d.h @@ -0,0 +1,88 @@ +/*************************************************************************/ +/* test_transform_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_TRANSFORM_2D_H +#define TEST_TRANSFORM_2D_H + +#include "core/math/transform_2d.h" + +#include "tests/test_macros.h" + +namespace TestTransform2D { + +Transform2D create_dummy_transform() { + return Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(5, 6)); +} + +Transform2D identity() { + return Transform2D(); +} + +TEST_CASE("[Transform2D] translation") { + Vector2 offset = Vector2(1, 2); + + // Both versions should give the same result applied to identity. + CHECK(identity().translated(offset) == identity().translated_local(offset)); + + // Check both versions against left and right multiplications. + Transform2D orig = create_dummy_transform(); + Transform2D T = identity().translated(offset); + CHECK(orig.translated(offset) == T * orig); + CHECK(orig.translated_local(offset) == orig * T); +} + +TEST_CASE("[Transform2D] scaling") { + Vector2 scaling = Vector2(1, 2); + + // Both versions should give the same result applied to identity. + CHECK(identity().scaled(scaling) == identity().scaled_local(scaling)); + + // Check both versions against left and right multiplications. + Transform2D orig = create_dummy_transform(); + Transform2D S = identity().scaled(scaling); + CHECK(orig.scaled(scaling) == S * orig); + CHECK(orig.scaled_local(scaling) == orig * S); +} + +TEST_CASE("[Transform2D] rotation") { + real_t phi = 1.0; + + // Both versions should give the same result applied to identity. + CHECK(identity().rotated(phi) == identity().rotated_local(phi)); + + // Check both versions against left and right multiplications. + Transform2D orig = create_dummy_transform(); + Transform2D R = identity().rotated(phi); + CHECK(orig.rotated(phi) == R * orig); + CHECK(orig.rotated_local(phi) == orig * R); +} +} // 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 new file mode 100644 index 00000000000..da166b43f73 --- /dev/null +++ b/tests/core/math/test_transform_3d.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* test_transform_3d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEST_TRANSFORM_3D_H +#define TEST_TRANSFORM_3D_H + +#include "core/math/transform_3d.h" + +#include "tests/test_macros.h" + +namespace TestTransform3D { + +Transform3D create_dummy_transform() { + return Transform3D(Basis(Vector3(1, 2, 3), Vector3(4, 5, 6), Vector3(7, 8, 9)), Vector3(10, 11, 12)); +} + +Transform3D identity() { + return Transform3D(); +} + +TEST_CASE("[Transform3D] translation") { + Vector3 offset = Vector3(1, 2, 3); + + // Both versions should give the same result applied to identity. + CHECK(identity().translated(offset) == identity().translated_local(offset)); + + // Check both versions against left and right multiplications. + Transform3D orig = create_dummy_transform(); + Transform3D T = identity().translated(offset); + CHECK(orig.translated(offset) == T * orig); + CHECK(orig.translated_local(offset) == orig * T); +} + +TEST_CASE("[Transform3D] scaling") { + Vector3 scaling = Vector3(1, 2, 3); + + // Both versions should give the same result applied to identity. + CHECK(identity().scaled(scaling) == identity().scaled_local(scaling)); + + // Check both versions against left and right multiplications. + Transform3D orig = create_dummy_transform(); + Transform3D S = identity().scaled(scaling); + CHECK(orig.scaled(scaling) == S * orig); + CHECK(orig.scaled_local(scaling) == orig * S); +} + +TEST_CASE("[Transform3D] rotation") { + Vector3 axis = Vector3(1, 2, 3).normalized(); + real_t phi = 1.0; + + // Both versions should give the same result applied to identity. + CHECK(identity().rotated(axis, phi) == identity().rotated_local(axis, phi)); + + // Check both versions against left and right multiplications. + Transform3D orig = create_dummy_transform(); + Transform3D R = identity().rotated(axis, phi); + CHECK(orig.rotated(axis, phi) == R * orig); + CHECK(orig.rotated_local(axis, phi) == orig * R); +} +} // namespace TestTransform3D + +#endif // TEST_TRANSFORM_3D_H diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 16654181c6f..d533ce4f636 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -49,6 +49,8 @@ #include "tests/core/math/test_random_number_generator.h" #include "tests/core/math/test_rect2.h" #include "tests/core/math/test_rect2i.h" +#include "tests/core/math/test_transform_2d.h" +#include "tests/core/math/test_transform_3d.h" #include "tests/core/math/test_vector2.h" #include "tests/core/math/test_vector2i.h" #include "tests/core/math/test_vector3.h"