mirror of
https://github.com/minetest/minetest.git
synced 2025-03-06 20:48:40 +01:00
Add Irrlicht rotation consistency unit tests
This commit is contained in:
parent
5abf220979
commit
c261c26456
3 changed files with 110 additions and 58 deletions
|
@ -14,7 +14,7 @@ set (UNITTEST_SRCS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/test_inventory.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_irrptr.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_irr_matrix4.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_irr_quaternion.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_irr_rotation.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_logging.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_lua.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_map.cpp
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "catch.h"
|
||||
#include "irrMath.h"
|
||||
#include "matrix4.h"
|
||||
#include "quaternion.h"
|
||||
#include "irr_v3d.h"
|
||||
|
||||
using matrix4 = core::matrix4;
|
||||
|
||||
static bool matrix_equals(const matrix4 &a, const matrix4 &b) {
|
||||
return a.equals(b, 0.00001f);
|
||||
}
|
||||
|
||||
TEST_CASE("quaternion") {
|
||||
|
||||
// Make sure that the conventions are consistent
|
||||
SECTION("equivalence to euler rotations") {
|
||||
auto test_rotation = [](v3f rad) {
|
||||
matrix4 R;
|
||||
R.setRotationRadians(rad);
|
||||
v3f rad2;
|
||||
core::quaternion(rad).toEuler(rad2);
|
||||
matrix4 R2;
|
||||
R2.setRotationRadians(rad2);
|
||||
CHECK(matrix_equals(R, R2));
|
||||
};
|
||||
|
||||
Catch::Generators::RandomFloatingGenerator<f32> gen(0.0f, 2 * core::PI, Catch::getSeed());
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
test_rotation(v3f{gen.get(), gen.get(), gen.get()});
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (int k = 0; k < 4; k++)
|
||||
test_rotation(core::PI / 4.0f * v3f(i, j, k));
|
||||
}
|
||||
|
||||
SECTION("equivalence to rotation matrices") {
|
||||
auto test_rotation = [](v3f rad) {
|
||||
matrix4 R;
|
||||
R.setRotationRadians(rad);
|
||||
matrix4 R2;
|
||||
core::quaternion(R).getMatrix(R2);
|
||||
CHECK(matrix_equals(R, R2));
|
||||
};
|
||||
|
||||
Catch::Generators::RandomFloatingGenerator<f32> gen(0.0f, 2 * core::PI, Catch::getSeed());
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
test_rotation(v3f{gen.get(), gen.get(), gen.get()});
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (int k = 0; k < 4; k++)
|
||||
test_rotation(core::PI / 4.0f * v3f(i, j, k));
|
||||
}
|
||||
|
||||
}
|
109
src/unittest/test_irr_rotation.cpp
Normal file
109
src/unittest/test_irr_rotation.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "catch.h"
|
||||
#include "catch_amalgamated.hpp"
|
||||
#include "irrMath.h"
|
||||
#include "matrix4.h"
|
||||
#include "irrMath.h"
|
||||
#include "matrix4.h"
|
||||
#include "irr_v3d.h"
|
||||
#include "quaternion.h"
|
||||
#include <functional>
|
||||
|
||||
// Irrlicht provides three different representations of rotations:
|
||||
// - Euler angles in radians (or degrees, but that doesn't matter much);
|
||||
// - Quaternions;
|
||||
// - Rotation matrices.
|
||||
// These tests ensure that converting between these representations is rotation-preserving.
|
||||
|
||||
using matrix4 = core::matrix4;
|
||||
using quaternion = core::quaternion;
|
||||
|
||||
// Despite the internal usage of doubles, matrix4::setRotationRadians
|
||||
// simply incurs component-wise errors of the order 1e-3.
|
||||
const f32 tolerance = 1e-2f;
|
||||
|
||||
static bool matrix_equals(const matrix4 &mat, const matrix4 &mat2)
|
||||
{
|
||||
return mat.equals(mat2, tolerance);
|
||||
}
|
||||
|
||||
static bool euler_angles_equiv(v3f rad, v3f rad2)
|
||||
{
|
||||
matrix4 mat, mat2;
|
||||
mat.setRotationRadians(rad);
|
||||
mat2.setRotationRadians(rad2);
|
||||
return matrix_equals(mat, mat2);
|
||||
}
|
||||
|
||||
static void test_euler_angles_rad(const std::function<void(v3f)> &test_euler_radians)
|
||||
{
|
||||
Catch::Generators::RandomFloatingGenerator<f32> gen(0.0f, 2 * core::PI, Catch::getSeed());
|
||||
auto random_angle = [&gen]() {
|
||||
f32 f = gen.get();
|
||||
gen.next();
|
||||
return f;
|
||||
};
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
test_euler_radians(v3f{random_angle(), random_angle(), random_angle()});
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (int k = 0; k < 4; k++) {
|
||||
v3f rad = core::PI / 4.0f * v3f(i, j, k);
|
||||
test_euler_radians(rad);
|
||||
// Test very slightly nudged, "almost-perfect" rotations to make sure
|
||||
// that the conversions are relatively stable at extremal points
|
||||
for (int l = 0; l < 10; ++l) {
|
||||
v3f jitter = v3f{random_angle(), random_angle(), random_angle()} * 0.001f;
|
||||
test_euler_radians(rad + jitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("rotations") {
|
||||
|
||||
SECTION("euler-to-quaternion conversion") {
|
||||
test_euler_angles_rad([](v3f rad) {
|
||||
core::matrix4 rot, rot_quat;
|
||||
rot.setRotationRadians(rad);
|
||||
quaternion q(rad);
|
||||
q.getMatrix(rot_quat);
|
||||
// Check equivalence of the rotations via matrices
|
||||
CHECK(matrix_equals(rot, rot_quat));
|
||||
});
|
||||
}
|
||||
|
||||
// Now that we've already tested the conversion to quaternions,
|
||||
// this essentially primarily tests the quaternion to euler conversion
|
||||
SECTION("quaternion-euler roundtrip") {
|
||||
test_euler_angles_rad([](v3f rad) {
|
||||
quaternion q(rad);
|
||||
v3f rad2;
|
||||
q.toEuler(rad2);
|
||||
CHECK(euler_angles_equiv(rad, rad2));
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("matrix-quaternion roundtrip") {
|
||||
test_euler_angles_rad([](v3f rad) {
|
||||
matrix4 mat;
|
||||
mat.setRotationRadians(rad);
|
||||
quaternion q(mat);
|
||||
matrix4 mat2;
|
||||
q.getMatrix(mat2);
|
||||
CHECK(matrix_equals(mat, mat2));
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("matrix-euler roundtrip") {
|
||||
test_euler_angles_rad([](v3f rad) {
|
||||
matrix4 mat, mat2;
|
||||
mat.setRotationRadians(rad);
|
||||
v3f rad2 = mat.getRotationDegrees() * core::DEGTORAD;
|
||||
mat2.setRotationRadians(rad2);
|
||||
CHECK(matrix_equals(mat, mat2));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue