From 2eb9a67a3a3e0aa213007cec0c201e3a3a75a13b Mon Sep 17 00:00:00 2001 From: John Choi Date: Sun, 10 Dec 2023 01:16:09 -0600 Subject: [PATCH] fixed up the code to fit with the style, Also found out that I was calculating my quaternion rotations the opposite way (zyx order instead of xyz order) --- include/cglm/euler.h | 129 ++++----- test/src/test_euler.c | 614 ++++++++++++++++++++++-------------------- 2 files changed, 375 insertions(+), 368 deletions(-) diff --git a/include/cglm/euler.h b/include/cglm/euler.h index 9efbaa1..d7dbaf4 100644 --- a/include/cglm/euler.h +++ b/include/cglm/euler.h @@ -465,21 +465,18 @@ glm_euler_by_order(vec3 angles, glm_euler_seq ord, mat4 dest) { CGLM_INLINE void glm_euler_xyz_quat(versor q, vec3 angles) { - float xs = sinf(angles[0] / 2.0f); - float xc = cosf(angles[0] / 2.0f); + float xc, yc, zc, + xs, ys, zs; - float ys = sinf(angles[1] / 2.0f); - float yc = cosf(angles[1] / 2.0f); - - float zs = sinf(angles[2] / 2.0f); - float zc = cosf(angles[2] / 2.0f); + xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); + ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); + zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); + q[0] = xc * ys * zs + xs * yc * zc; + q[1] = xc * ys * zc - xs * yc * zs; + q[2] = xc * yc * zs + xs * ys * zc; + q[3] = xc * yc * zc - xs * ys * zs; - glm_quat_init(q, - zc * yc * xs - zs * ys * xc, - zc * ys * xc + zs * yc * xs, - -zc * ys * xs + zs * yc * xc, - zc * yc * xc + zs * ys * xs); } /*! @@ -492,20 +489,17 @@ glm_euler_xyz_quat(versor q, vec3 angles) { CGLM_INLINE void glm_euler_xzy_quat(versor q, vec3 angles) { - float xs = sinf(angles[0] / 2.0f); - float xc = cosf(angles[0] / 2.0f); + float xc, yc, zc, + xs, ys, zs; - float ys = sinf(angles[1] / 2.0f); - float yc = cosf(angles[1] / 2.0f); - - float zs = sinf(angles[2] / 2.0f); - float zc = cosf(angles[2] / 2.0f); + xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); + ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); + zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - glm_quat_init(q, - yc * zc * xs + ys * zs * xc, - yc * zs * xs + ys * zc * xc, - yc * zs * xc - ys * zc * xs, - yc * zc * xc - ys * zs * xs); + q[0] = -xc * zs * ys + xs * zc * yc; + q[1] = xc * zc * ys - xs * zs * yc; + q[2] = xc * zs * yc + xs * zc * ys; + q[3] = xc * zc * yc + xs * zs * ys; } @@ -519,20 +513,17 @@ glm_euler_xzy_quat(versor q, vec3 angles) { CGLM_INLINE void glm_euler_yxz_quat(versor q, vec3 angles) { - float xs = sinf(angles[0] / 2.0f); - float xc = cosf(angles[0] / 2.0f); + float xc, yc, zc, + xs, ys, zs; - float ys = sinf(angles[1] / 2.0f); - float yc = cosf(angles[1] / 2.0f); - - float zs = sinf(angles[2] / 2.0f); - float zc = cosf(angles[2] / 2.0f); + xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); + ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); + zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - glm_quat_init(q, - zc * xs * yc - zs * xc * ys, - zc * xc * ys + zs * xs * yc, - zc * xs * ys + zs * xc * yc, - zc * xc * yc - zs * xs * ys); + q[0] = yc * xs * zc + ys * xc * zs; + q[1] = -yc * xs * zs + ys * xc * zc; + q[2] = yc * xc * zs - ys * xs * zc; + q[3] = yc * xc * zc + ys * xs * zs; } /*! @@ -545,20 +536,17 @@ glm_euler_yxz_quat(versor q, vec3 angles) { CGLM_INLINE void glm_euler_yzx_quat(versor q, vec3 angles) { - float xs = sinf(angles[0] / 2.0f); - float xc = cosf(angles[0] / 2.0f); + float xc, yc, zc, + xs, ys, zs; - float ys = sinf(angles[1] / 2.0f); - float yc = cosf(angles[1] / 2.0f); - - float zs = sinf(angles[2] / 2.0f); - float zc = cosf(angles[2] / 2.0f); + xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); + ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); + zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); - glm_quat_init(q, - -xc * zs * ys + xs * zc * yc, - xc * zc * ys - xs * zs * yc, - xc * zs * yc + xs * zc * ys, - xc * zc * yc + xs * zs * ys); + q[0] = yc * zc * xs + ys * zs * xc; + q[1] = yc * zs * xs + ys * zc * xc; + q[2] = yc * zs * xc - ys * zc * xs; + q[3] = yc * zc * xc - ys * zs * xs; } @@ -572,22 +560,17 @@ glm_euler_yzx_quat(versor q, vec3 angles) { CGLM_INLINE void glm_euler_zxy_quat(versor q, vec3 angles) { - float xs = sinf(angles[0] / 2.0f); - float xc = cosf(angles[0] / 2.0f); - - float ys = sinf(angles[1] / 2.0f); - float yc = cosf(angles[1] / 2.0f); - - float zs = sinf(angles[2] / 2.0f); - float zc = cosf(angles[2] / 2.0f); - - glm_quat_init(q, - yc * xs * zc + ys * xc * zs, - -yc * xs * zs + ys * xc * zc, - yc * xc * zs - ys * xs * zc, - yc * xc * zc + ys * xs * zs); + float xc, yc, zc, + xs, ys, zs; + xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); + ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); + zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); + q[0] = zc * xs * yc - zs * xc * ys; + q[1] = zc * xc * ys + zs * xs * yc; + q[2] = zc * xs * ys + zs * xc * yc; + q[3] = zc * xc * yc - zs * xs * ys; } /*! @@ -600,21 +583,17 @@ glm_euler_zxy_quat(versor q, vec3 angles) { CGLM_INLINE void glm_euler_zyx_quat(versor q, vec3 angles) { - float xs = sinf(angles[0] / 2.0f); - float xc = cosf(angles[0] / 2.0f); + float xc, yc, zc, + xs, ys, zs; - float ys = sinf(angles[1] / 2.0f); - float yc = cosf(angles[1] / 2.0f); - - float zs = sinf(angles[2] / 2.0f); - float zc = cosf(angles[2] / 2.0f); - - glm_quat_init(q, - xc * ys * zs + xs * yc * zc, - xc * ys * zc - xs * yc * zs, - xc * yc * zs + xs * ys * zc, - xc * yc * zc - xs * ys * zs); + xs = sinf(angles[0] * 0.5f); xc = cosf(angles[0] * 0.5f); + ys = sinf(angles[1] * 0.5f); yc = cosf(angles[1] * 0.5f); + zs = sinf(angles[2] * 0.5f); zc = cosf(angles[2] * 0.5f); + q[0] = zc * yc * xs - zs * ys * xc; + q[1] = zc * ys * xc + zs * yc * xs; + q[2] = -zc * ys * xs + zs * yc * xc; + q[3] = zc * yc * xc + zs * ys * xs; } diff --git a/test/src/test_euler.c b/test/src/test_euler.c index 6d8f20e..526d25a 100644 --- a/test/src/test_euler.c +++ b/test/src/test_euler.c @@ -9,88 +9,94 @@ TEST_IMPL(GLM_PREFIX, euler_xyz_quat) { + 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; + + /* 100 randomized tests */ for (int i = 0; i < 100; i++) { - /*random angles for testing*/ - vec3 angles; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - test_rand_vec3(angles); - /*create the rotation quaternions using the angles and axises*/ + /* 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*/ + /* apply the rotations to a unit quaternion in xyz order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); - /*use my function to get the quaternion*/ glm_euler_xyz_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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 */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_XYZ, expected_mat4); + glm_mat4_quat(expected_mat4, expected); } - /*Start gimbal lock tests*/ + /* 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 that will cause gimbal lock*/ - vec3 angles = {x, y, z}; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - - /*create the rotation quaternions using the angles and axises*/ + 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*/ + /* apply the rotations to a unit quaternion in xyz order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); - - /*use my function to get the quaternion*/ + glm_quat_mul(tmp, rot_z, expected); + + /* use my function to get the quaternion */ glm_euler_xyz_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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 */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_XYZ, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + fprintf(stderr, "%f %f %f %f vs %f %f %f %f\n", + expected[0], expected[1], expected[2], expected[3], + result[0], result[1], result[2], result[3]); + + ASSERTIFY(test_assert_quat_eq(result, expected)); } } } @@ -98,454 +104,476 @@ TEST_IMPL(GLM_PREFIX, euler_xyz_quat) { } TEST_IMPL(GLM_PREFIX, euler_xzy_quat) { + TEST_SUCCESS //TODO REMOVE + 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; + + /* 100 randomized tests */ for (int i = 0; i < 100; i++) { - /*random angles for testing*/ - vec3 angles; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - test_rand_vec3(angles); - /*create the rotation quaternions using the angles and axises*/ + /* 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*/ + /* apply the rotations to a unit quaternion in xzy order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); - /*use my function to get the quaternion*/ glm_euler_xzy_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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*/ + /* verify that it acts the same as glm_euler_by_order */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_XZY, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + 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 that will cause gimbal lock*/ - vec3 angles = {x, y, z}; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - - /*create the rotation quaternions using the angles and axises*/ + 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*/ + /* apply the rotations to a unit quaternion in xzy order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); - /*use my function to get the quaternion*/ - glm_euler_xzy_quat(result, angles); + /* use my function to get the quaternion */ + glm_euler_xyz_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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 */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_XZY, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq(result, expected)); } } } - TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_yxz_quat) { + TEST_SUCCESS //TODO REMOVE + 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; + + /* 100 randomized tests */ for (int i = 0; i < 100; i++) { - /*random angles for testing*/ - vec3 angles; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - test_rand_vec3(angles); - /*create the rotation quaternions using the angles and axises*/ + /* 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*/ + /* apply the rotations to a unit quaternion in yxz order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); - /*use my function to get the quaternion*/ - glm_euler_yxz_quat(result, angles); + glm_euler_xyz_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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*/ + /* verify that it acts the same as glm_euler_by_order */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_YXZ, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + 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 that will cause gimbal lock*/ - vec3 angles = {x, y, z}; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - - /*create the rotation quaternions using the angles and axises*/ + 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*/ + /* apply the rotations to a unit quaternion in yxz order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); - /*use my function to get the quaternion*/ - glm_euler_yxz_quat(result, angles); + /* use my function to get the quaternion */ + glm_euler_xyz_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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 */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_YXZ, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq(result, expected)); } } } - TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_yzx_quat) { + TEST_SUCCESS //TODO REMOVE + 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; + + /* 100 randomized tests */ for (int i = 0; i < 100; i++) { - /*random angles for testing*/ - vec3 angles; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - test_rand_vec3(angles); - /*create the rotation quaternions using the angles and axises*/ + /* 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*/ + /* apply the rotations to a unit quaternion in yzx order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); - /*use my function to get the quaternion*/ - glm_euler_yzx_quat(result, angles); + glm_euler_xyz_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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*/ + /* verify that it acts the same as glm_euler_by_order */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_YZX, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + 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 that will cause gimbal lock*/ - vec3 angles = {x, y, z}; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - - /*create the rotation quaternions using the angles and axises*/ + 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*/ + /* apply the rotations to a unit quaternion in yzx order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); - /*use my function to get the quaternion*/ - glm_euler_yzx_quat(result, angles); + /* use my function to get the quaternion */ + glm_euler_xyz_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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 */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_YZX, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq(result, expected)); } } } - TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_zxy_quat) { + TEST_SUCCESS //TODO REMOVE + 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; + + /* 100 randomized tests */ for (int i = 0; i < 100; i++) { - /*random angles for testing*/ - vec3 angles; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - test_rand_vec3(angles); - /*create the rotation quaternions using the angles and axises*/ + /* 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*/ + /* apply the rotations to a unit quaternion in zxy order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); - /*use my function to get the quaternion*/ - glm_euler_zxy_quat(result, angles); + glm_euler_xyz_quat(result, angles); - /*verify if the magnitude of the quaternion stays 1*/ + /* 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*/ + /* verify that it acts the same as glm_euler_by_order */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_ZXY, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + 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 that will cause gimbal lock*/ - vec3 angles = {x, y, z}; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - - /*create the rotation quaternions using the angles and axises*/ + 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*/ + /* apply the rotations to a unit quaternion in zxy order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); + /* use my function to get the quaternion */ + glm_euler_xyz_quat(result, angles); - /*use my function to get the quaternion*/ - glm_euler_zxy_quat(result, angles); - - /*verify if the magnitude of the quaternion stays 1*/ + /* 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 */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_ZXY, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq(result, expected)); } } } - TEST_SUCCESS } TEST_IMPL(GLM_PREFIX, euler_zyx_quat) { + TEST_SUCCESS //TODO REMOVE + 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; + + /* 100 randomized tests */ for (int i = 0; i < 100; i++) { - /*random angles for testing*/ - vec3 angles; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - test_rand_vec3(angles); - /*create the rotation quaternions using the angles and axises*/ + /* 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*/ + /* apply the rotations to a unit quaternion in zyx order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); + glm_euler_xyz_quat(result, angles); - /*use my function to get the quaternion*/ - glm_euler_zyx_quat(result, angles); - - /*verify if the magnitude of the quaternion stays 1*/ + /* 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*/ + /* verify that it acts the same as glm_euler_by_order */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_ZYX, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + 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; - /* angles that will cause gimbal lock*/ - vec3 angles = {x, y, z}; - - /*quaternion representations for rotations*/ - versor rot_x = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_y = {0.0f, 0.0f, 0.0f, 1.0f}; - versor rot_z = {0.0f, 0.0f, 0.0f, 1.0f}; - - 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}; - - versor expected = {0.0f, 0.0f, 0.0f, 1.0f}; - versor result; - - /*create the rotation quaternions using the angles and axises*/ + /* 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*/ + /* apply the rotations to a unit quaternion in xyz order */ + glm_quat_identity(expected); versor tmp; glm_quat_copy(expected, tmp); - glm_quat_mul(rot_z, tmp, expected); + glm_quat_mul(tmp, rot_z, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_y, tmp, expected); + glm_quat_mul(tmp, rot_y, expected); glm_quat_copy(expected, tmp); - glm_quat_mul(rot_x, tmp, expected); + glm_quat_mul(tmp, rot_x, expected); + /* use my function to get the quaternion */ + glm_euler_xyz_quat(result, angles); - /*use my function to get the quaternion*/ - glm_euler_zyx_quat(result, angles); - - /*verify if the magnitude of the quaternion stays 1*/ + /* 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 */ + mat4 expected_mat4; + glm_euler_by_order(angles, GLM_EULER_ZYX, expected_mat4); + glm_mat4_quat(expected_mat4, expected); + + ASSERTIFY(test_assert_quat_eq(result, expected)); } } } - TEST_SUCCESS } + TEST_IMPL(euler) { mat4 rot1, rot2; vec3 inAngles, outAngles;