From fa6244c42b21a130e8413c24ab5275f9cb9eacf8 Mon Sep 17 00:00:00 2001 From: John Choi Date: Thu, 28 Dec 2023 10:31:14 -0600 Subject: [PATCH] added tests for euler_to_quat_lh. Currently they don't have any euler->mat4->quat tests because there is no left handed version of those. But I could try to find a way to change it --- test/src/test_euler_to_quat_lh.h | 521 +++++++++++++++++++++++++++++++ test/tests.h | 46 ++- 2 files changed, 566 insertions(+), 1 deletion(-) create mode 100644 test/src/test_euler_to_quat_lh.h diff --git a/test/src/test_euler_to_quat_lh.h b/test/src/test_euler_to_quat_lh.h new file mode 100644 index 0000000..2269757 --- /dev/null +++ b/test/src/test_euler_to_quat_lh.h @@ -0,0 +1,521 @@ +/* + * Copyright (c), Recep Aslantas. + * + * MIT License (MIT), http://opensource.org/licenses/MIT + * Full license can be found in the LICENSE file + */ + +#include "test_common.h" +#include "../../include/cglm/handed/euler_to_quat_lh.h" + +TEST_IMPL(GLM_PREFIX, euler_xyz_quat_lh) { + vec3 axis_x = {1.0f, 0.0f, 0.0f}; + vec3 axis_y = {0.0f, 1.0f, 0.0f}; + vec3 axis_z = {0.0f, 0.0f,-1.0f}; + + /* random angles for testing */ + vec3 angles; + + /* quaternion representations for rotations */ + versor rot_x, rot_y, rot_z; + + versor expected; + versor result; + versor tmp; + + mat4 expected_mat4; + + /* 100 randomized tests */ + for (int i = 0; i < 100; i++) { + test_rand_vec3(angles); + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in xyz order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + + glm_euler_xyz_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + } + + + /* Start gimbal lock tests */ + for (float x = -90.0f; x <= 90.0f; x += 90.0f) { + for (float y = -90.0f; y <= 90.0f; y += 90.0f) { + for (float z = -90.0f; z <= 90.0f; z += 90.0f) { + angles[0] = x; + angles[1] = y; + angles[2] = z; + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in xyz order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + + /* use my function to get the quaternion */ + glm_euler_xyz_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + } + } + } + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, euler_xzy_quat_lh) { + vec3 axis_x = {1.0f, 0.0f, 0.0f}; + vec3 axis_y = {0.0f, 1.0f, 0.0f}; + vec3 axis_z = {0.0f, 0.0f,-1.0f}; + + /* random angles for testing */ + vec3 angles; + + /* quaternion representations for rotations */ + versor rot_x, rot_y, rot_z; + + versor expected; + versor result; + versor tmp; + + /* 100 randomized tests */ + for (int i = 0; i < 100; i++) { + test_rand_vec3(angles); + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in xzy order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + + glm_euler_xzy_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + } + + + /* Start gimbal lock tests */ + for (float x = -90.0f; x <= 90.0f; x += 90.0f) { + for (float y = -90.0f; y <= 90.0f; y += 90.0f) { + for (float z = -90.0f; z <= 90.0f; z += 90.0f) { + angles[0] = x; + angles[1] = y; + angles[2] = z; + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in xzy order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + + /* use my function to get the quaternion */ + glm_euler_xzy_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + } + } + } + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, euler_yxz_quat_lh) { + vec3 axis_x = {1.0f, 0.0f, 0.0f}; + vec3 axis_y = {0.0f, 1.0f, 0.0f}; + vec3 axis_z = {0.0f, 0.0f,-1.0f}; + + /* random angles for testing */ + vec3 angles; + + /* quaternion representations for rotations */ + versor rot_x, rot_y, rot_z; + + versor expected; + versor result; + versor tmp; + + /* 100 randomized tests */ + for (int i = 0; i < 100; i++) { + test_rand_vec3(angles); + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in yxz order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + + glm_euler_yxz_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + + /* verify that it acts the same as glm_euler_by_order */ + glm_euler_by_order(angles, GLM_EULER_YXZ, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq_abs(result, expected)); + } + + + /* Start gimbal lock tests */ + for (float x = -90.0f; x <= 90.0f; x += 90.0f) { + for (float y = -90.0f; y <= 90.0f; y += 90.0f) { + for (float z = -90.0f; z <= 90.0f; z += 90.0f) { + angles[0] = x; + angles[1] = y; + angles[2] = z; + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in yxz order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + + /* use my function to get the quaternion */ + glm_euler_yxz_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + ASSERTIFY(test_assert_quat_eq(result, expected)) + + /* verify that it acts the same as glm_euler_by_order */ + glm_euler_by_order(angles, GLM_EULER_YXZ, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq_abs(result, expected)); + } + } + } + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, euler_yzx_quat_lh) { + vec3 axis_x = {1.0f, 0.0f, 0.0f}; + vec3 axis_y = {0.0f, 1.0f, 0.0f}; + vec3 axis_z = {0.0f, 0.0f,-1.0f}; + + /* random angles for testing */ + vec3 angles; + + /* quaternion representations for rotations */ + versor rot_x, rot_y, rot_z; + + versor expected; + versor result; + versor tmp; + + /* 100 randomized tests */ + for (int i = 0; i < 100; i++) { + test_rand_vec3(angles); + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in yzx order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + + glm_euler_yzx_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + + /* verify that it acts the same as glm_euler_by_order */ + glm_euler_by_order(angles, GLM_EULER_YZX, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq_abs(result, expected)); + } + + + /* Start gimbal lock tests */ + for (float x = -90.0f; x <= 90.0f; x += 90.0f) { + for (float y = -90.0f; y <= 90.0f; y += 90.0f) { + for (float z = -90.0f; z <= 90.0f; z += 90.0f) { + angles[0] = x; + angles[1] = y; + angles[2] = z; + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in yzx order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + + /* use my function to get the quaternion */ + glm_euler_yzx_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + ASSERTIFY(test_assert_quat_eq(result, expected)) + + /* verify that it acts the same as glm_euler_by_order */ + glm_euler_by_order(angles, GLM_EULER_YZX, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq_abs(result, expected)); + } + } + } + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, euler_zxy_quat_lh) { + vec3 axis_x = {1.0f, 0.0f, 0.0f}; + vec3 axis_y = {0.0f, 1.0f, 0.0f}; + vec3 axis_z = {0.0f, 0.0f,-1.0f}; + + /* random angles for testing */ + vec3 angles; + + /* quaternion representations for rotations */ + versor rot_x, rot_y, rot_z; + + versor expected; + versor result; + versor tmp; + + /* 100 randomized tests */ + for (int i = 0; i < 100; i++) { + test_rand_vec3(angles); + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in zxy order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + + glm_euler_zxy_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + } + + + /* Start gimbal lock tests */ + for (float x = -90.0f; x <= 90.0f; x += 90.0f) { + for (float y = -90.0f; y <= 90.0f; y += 90.0f) { + for (float z = -90.0f; z <= 90.0f; z += 90.0f) { + angles[0] = x; + angles[1] = y; + angles[2] = z; + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in zxy order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + + /* use my function to get the quaternion */ + glm_euler_zxy_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + } + } + } + TEST_SUCCESS +} + +TEST_IMPL(GLM_PREFIX, euler_zyx_quat_lh) { + vec3 axis_x = {1.0f, 0.0f, 0.0f}; + vec3 axis_y = {0.0f, 1.0f, 0.0f}; + vec3 axis_z = {0.0f, 0.0f,-1.0f}; + + /* random angles for testing */ + vec3 angles; + + /* quaternion representations for rotations */ + versor rot_x, rot_y, rot_z; + + versor expected; + versor result; + versor tmp; + + /* 100 randomized tests */ + for (int i = 0; i < 100; i++) { + test_rand_vec3(angles); + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in zyx order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + + glm_euler_zyx_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + } + + + /* Start gimbal lock tests */ + for (float x = -90.0f; x <= 90.0f; x += 90.0f) { + for (float y = -90.0f; y <= 90.0f; y += 90.0f) { + for (float z = -90.0f; z <= 90.0f; z += 90.0f) { + angles[0] = x; + angles[1] = y; + angles[2] = z; + + /* create the rotation quaternions using the angles and axises */ + glm_quatv(rot_x, angles[0], axis_x); + glm_quatv(rot_y, angles[1], axis_y); + glm_quatv(rot_z, angles[2], axis_z); + + /* apply the rotations to a unit quaternion in xyz order */ + glm_quat_identity(expected); + + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_z, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_y, expected); + glm_quat_copy(expected, tmp); + glm_quat_mul(tmp, rot_x, expected); + + /* use my function to get the quaternion */ + glm_euler_zyx_quat_lh(angles, result); + + /* verify if the magnitude of the quaternion stays 1 */ + ASSERT(test_eq(glm_quat_norm(result), 1.0f)) + + /* verify that it acts the same as rotating by 3 axis quaternions */ + ASSERTIFY(test_assert_quat_eq(result, expected)) + } + } + } + TEST_SUCCESS +} + + diff --git a/test/tests.h b/test/tests.h index 37f8abb..a6c0ff0 100644 --- a/test/tests.h +++ b/test/tests.h @@ -363,9 +363,31 @@ TEST_DECLARE(clamp) TEST_DECLARE(glm_euler_xyz_quat_rh) TEST_DECLARE(glm_euler_xzy_quat_rh) TEST_DECLARE(glm_euler_yxz_quat_rh) -TEST_DECLARE(glm_euler_yzx_quat_rh) +TEST_DECLARE(glm_euler_yzx_quat_rh) TEST_DECLARE(glm_euler_zxy_quat_rh) TEST_DECLARE(glm_euler_zyx_quat_rh) + +TEST_DECLARE(glm_euler_xyz_quat_lh) +TEST_DECLARE(glm_euler_xzy_quat_lh) +TEST_DECLARE(glm_euler_yxz_quat_lh) +TEST_DECLARE(glm_euler_yzx_quat_lh) +TEST_DECLARE(glm_euler_zxy_quat_lh) +TEST_DECLARE(glm_euler_zyx_quat_lh) + +TEST_DECLARE(glmc_euler_xyz_quat_rh) +TEST_DECLARE(glmc_euler_xzy_quat_rh) +TEST_DECLARE(glmc_euler_yxz_quat_rh) +TEST_DECLARE(glmc_euler_yzx_quat_rh) +TEST_DECLARE(glmc_euler_zxy_quat_rh) +TEST_DECLARE(glmc_euler_zyx_quat_rh) + +TEST_DECLARE(glmc_euler_xyz_quat_lh) +TEST_DECLARE(glmc_euler_xzy_quat_lh) +TEST_DECLARE(glmc_euler_yxz_quat_lh) +TEST_DECLARE(glmc_euler_yzx_quat_lh) +TEST_DECLARE(glmc_euler_zxy_quat_lh) +TEST_DECLARE(glmc_euler_zyx_quat_lh) + TEST_DECLARE(euler) /* ray */ @@ -1385,6 +1407,28 @@ TEST_LIST { TEST_ENTRY(glm_euler_yzx_quat_rh) TEST_ENTRY(glm_euler_zxy_quat_rh) TEST_ENTRY(glm_euler_zyx_quat_rh) + + TEST_ENTRY(glm_euler_xyz_quat_lh) + TEST_ENTRY(glm_euler_xzy_quat_lh) + TEST_ENTRY(glm_euler_yxz_quat_lh) + TEST_ENTRY(glm_euler_yzx_quat_lh) + TEST_ENTRY(glm_euler_zxy_quat_lh) + TEST_ENTRY(glm_euler_zyx_quat_lh) + + TEST_ENTRY(glmc_euler_xyz_quat_rh) + TEST_ENTRY(glmc_euler_xzy_quat_rh) + TEST_ENTRY(glmc_euler_yxz_quat_rh) + TEST_ENTRY(glmc_euler_yzx_quat_rh) + TEST_ENTRY(glmc_euler_zxy_quat_rh) + TEST_ENTRY(glmc_euler_zyx_quat_rh) + + TEST_ENTRY(glmc_euler_xyz_quat_lh) + TEST_ENTRY(glmc_euler_xzy_quat_lh) + TEST_ENTRY(glmc_euler_yxz_quat_lh) + TEST_ENTRY(glmc_euler_yzx_quat_lh) + TEST_ENTRY(glmc_euler_zxy_quat_lh) + TEST_ENTRY(glmc_euler_zyx_quat_lh) + TEST_ENTRY(euler) /* ray */