Merge pull request #55923 from bluenote10/feature/consistent_transform_operations

Fix consistency of translated/scaled/rotated in Transform2D and Transform3D
This commit is contained in:
Rémi Verschelde 2022-08-03 07:50:01 +02:00 committed by GitHub
commit a49cf9fe90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 426 additions and 41 deletions

View File

@ -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 {

View File

@ -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;

View File

@ -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() {

View File

@ -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; }

View File

@ -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());

View File

@ -141,14 +141,40 @@
<return type="Transform2D" />
<argument index="0" name="angle" type="float" />
<description>
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.
</description>
</method>
<method name="rotated_local" qualifiers="const">
<return type="Transform2D" />
<argument index="0" name="angle" type="float" />
<description>
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.
</description>
</method>
<method name="scaled" qualifiers="const">
<return type="Transform2D" />
<argument index="0" name="scale" type="Vector2" />
<description>
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.
</description>
</method>
<method name="scaled_local" qualifiers="const">
<return type="Transform2D" />
<argument index="0" name="scale" type="Vector2" />
<description>
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.
</description>
</method>
<method name="set_rotation">
@ -173,12 +199,24 @@
Sets the transform's skew (in radians).
</description>
</method>
<method name="translated" qualifiers="const">
<return type="Transform2D" />
<argument index="0" name="offset" type="Vector2" />
<description>
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.
</description>
</method>
<method name="translated_local" qualifiers="const">
<return type="Transform2D" />
<argument index="0" name="offset" type="Vector2" />
<description>
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.
</description>
</method>
</methods>

View File

@ -102,14 +102,43 @@
<argument index="0" name="axis" type="Vector3" />
<argument index="1" name="angle" type="float" />
<description>
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.
</description>
</method>
<method name="rotated_local" qualifiers="const">
<return type="Transform3D" />
<argument index="0" name="axis" type="Vector3" />
<argument index="1" name="angle" type="float" />
<description>
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.
</description>
</method>
<method name="scaled" qualifiers="const">
<return type="Transform3D" />
<argument index="0" name="scale" type="Vector3" />
<description>
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.
</description>
</method>
<method name="scaled_local" qualifiers="const">
<return type="Transform3D" />
<argument index="0" name="scale" type="Vector3" />
<description>
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.
</description>
</method>
<method name="spherical_interpolate_with" qualifiers="const">
@ -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).
</description>
</method>
<method name="translated" qualifiers="const">
<return type="Transform3D" />
<argument index="0" name="offset" type="Vector3" />
<description>
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.
</description>
</method>
<method name="translated_local" qualifiers="const">
<return type="Transform3D" />
<argument index="0" name="offset" type="Vector3" />
<description>
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.
</description>
</method>
</methods>

View File

@ -297,7 +297,9 @@ namespace Godot
}
/// <summary>
/// Rotates the transform by <paramref name="angle"/> (in radians), using matrix multiplication.
/// Rotates the transform by <paramref name="angle"/> (in radians).
/// The operation is done in the parent/global frame, equivalent to
/// multiplying the matrix from the left.
/// </summary>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
@ -307,7 +309,21 @@ namespace Godot
}
/// <summary>
/// Scales the transform by the given scaling factor, using matrix multiplication.
/// Rotates the transform by <paramref name="angle"/> (in radians).
/// The operation is done in the local frame, equivalent to
/// multiplying the matrix from the right.
/// </summary>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform2D RotatedLocal(real_t angle)
{
return new Transform2D(angle, new Vector2()) * this;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
@ -320,6 +336,21 @@ namespace Godot
return copy;
}
/// <summary>
/// Scales the transform by the given scaling factor.
/// The operation is done in the local frame, equivalent to
/// multiplying the matrix from the right.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
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
}
/// <summary>
/// Translates the transform by the given <paramref name="offset"/>,
/// relative to the transform's basis vectors.
///
/// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>,
/// this does not use matrix multiplication.
/// Translates the transform by the given <paramref name="offset"/>.
/// The operation is done in the parent/global frame, equivalent to
/// multiplying the matrix from the left.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
public Transform2D Translated(Vector2 offset)
{
Transform2D copy = this;
copy.origin += offset;
return copy;
}
/// <summary>
/// Translates the transform by the given <paramref name="offset"/>.
/// The operation is done in the local frame, equivalent to
/// multiplying the matrix from the right.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>

View File

@ -186,8 +186,10 @@ namespace Godot
}
/// <summary>
/// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians),
/// using matrix multiplication. The axis must be a normalized vector.
/// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (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.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
@ -198,7 +200,24 @@ namespace Godot
}
/// <summary>
/// Scales the transform by the given 3D scaling factor, using matrix multiplication.
/// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (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.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform3D RotatedLocal(Vector3 axis, real_t angle)
{
Basis tmpBasis = new Basis(axis, angle);
return new Transform3D(basis * tmpBasis, origin);
}
/// <summary>
/// Scales the transform by the given 3D <paramref name="scale"/> factor.
/// The operation is done in the parent/global frame, equivalent to
/// multiplying the matrix from the left.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
@ -207,6 +226,19 @@ namespace Godot
return new Transform3D(basis.Scaled(scale), origin * scale);
}
/// <summary>
/// Scales the transform by the given 3D <paramref name="scale"/> factor.
/// The operation is done in the local frame, equivalent to
/// multiplying the matrix from the right.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
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
}
/// <summary>
/// Translates the transform by the given <paramref name="offset"/>,
/// relative to the transform's basis vectors.
///
/// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>,
/// this does not use matrix multiplication.
/// Translates the transform by the given <paramref name="offset"/>.
/// The operation is done in the parent/global frame, equivalent to
/// multiplying the matrix from the left.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
public Transform3D Translated(Vector3 offset)
{
return new Transform3D(basis, origin + offset);
}
/// <summary>
/// Translates the transform by the given <paramref name="offset"/>.
/// The operation is done in the local frame, equivalent to
/// multiplying the matrix from the right.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>

View File

@ -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

View File

@ -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

View File

@ -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"