From 9e9c18d37e140005fb696259f0e0d6d831c6f726 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 30 Apr 2012 13:40:54 +0000 Subject: [PATCH] test: add several unit tests for rotations with matrices and quaternions. --- test/Makefile.am | 2 +- test/unit/quat.cpp | 88 +++++++++++++++------------- test/unit/rotation.cpp | 124 ++++++++++++++++++++++++++++++++++++++++ win32/testsuite.vcxproj | 1 + 4 files changed, 175 insertions(+), 40 deletions(-) create mode 100644 test/unit/rotation.cpp diff --git a/test/Makefile.am b/test/Makefile.am index aaddff86..e738c6f3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -24,7 +24,7 @@ TESTS = testsuite testsuite_SOURCES = testsuite.cpp \ unit/vector.cpp unit/matrix.cpp unit/half.cpp unit/trig.cpp \ unit/build.cpp unit/real.cpp unit/image.cpp unit/quat.cpp unit/cmplx.cpp \ - unit/array.cpp + unit/array.cpp unit/rotation.cpp testsuite_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ testsuite_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@ @PIPI_LIBS@ testsuite_DEPENDENCIES = $(top_builddir)/src/liblol.a diff --git a/test/unit/quat.cpp b/test/unit/quat.cpp index 5e42af16..17e9a076 100644 --- a/test/unit/quat.cpp +++ b/test/unit/quat.cpp @@ -26,11 +26,11 @@ LOLUNIT_FIXTURE(QuaternionTest) LOLUNIT_TEST(Equality) { - quat a4(1.0f, 2.0f, 3.0f, 4.0f); - quat b4(0.0f, 2.0f, 3.0f, 4.0f); - quat c4(1.0f, 0.0f, 3.0f, 4.0f); - quat d4(1.0f, 2.0f, 0.0f, 4.0f); - quat e4(1.0f, 2.0f, 3.0f, 0.0f); + quat a4(1.f, 2.f, 3.f, 4.f); + quat b4(0.f, 2.f, 3.f, 4.f); + quat c4(1.f, 0.f, 3.f, 4.f); + quat d4(1.f, 2.f, 0.f, 4.f); + quat e4(1.f, 2.f, 3.f, 0.f); LOLUNIT_ASSERT_EQUAL(a4, a4); LOLUNIT_ASSERT_NOT_DIFFERENT(a4, a4); @@ -47,8 +47,8 @@ LOLUNIT_FIXTURE(QuaternionTest) LOLUNIT_TEST(UnaryMinus) { - quat a(1.0f, 3.0f, 2.0f, 4.0f); - quat b(-1.0f, -3.0f, -2.0f, -4.0f); + quat a(1.f, 3.f, 2.f, 4.f); + quat b(-1.f, -3.f, -2.f, -4.f); LOLUNIT_ASSERT_EQUAL(a, -b); LOLUNIT_ASSERT_EQUAL(-a, b); @@ -56,8 +56,8 @@ LOLUNIT_FIXTURE(QuaternionTest) LOLUNIT_TEST(Conjugate) { - quat a(1.0f, 3.0f, 2.0f, 4.0f); - quat b(1.0f, -3.0f, -2.0f, -4.0f); + quat a(1.f, 3.f, 2.f, 4.f); + quat b(1.f, -3.f, -2.f, -4.f); LOLUNIT_ASSERT_EQUAL(a, ~b); LOLUNIT_ASSERT_EQUAL(~a, b); @@ -65,31 +65,31 @@ LOLUNIT_FIXTURE(QuaternionTest) LOLUNIT_TEST(Norm) { - quat a(2.0f, -2.0f, -8.0f, 3.0f); + quat a(2.f, -2.f, -8.f, 3.f); - LOLUNIT_ASSERT_EQUAL(norm(a), 81.0f); + LOLUNIT_ASSERT_EQUAL(norm(a), 81.f); quat b = a * ~a; - quat c(norm(a), 0.0f, 0.0f, 0.0f); + quat c(norm(a), 0.f, 0.f, 0.f); LOLUNIT_ASSERT_EQUAL(b, c); - quat d(2.0f, 3.0f, -4.0f, -1.0f); + quat d(2.f, 3.f, -4.f, -1.f); LOLUNIT_ASSERT_EQUAL(norm(a * d), norm(a) * norm(d)); } LOLUNIT_TEST(Base) { - quat i(0.0f, 1.0f, 0.0f, 0.0f); - quat j(0.0f, 0.0f, 1.0f, 0.0f); - quat k(0.0f, 0.0f, 0.0f, 1.0f); - quat one(1.0f, 0.0f, 0.0f, 0.0f); + quat one(1.f, 0.f, 0.f, 0.f); + quat i(0.f, 1.f, 0.f, 0.f); + quat j(0.f, 0.f, 1.f, 0.f); + quat k(0.f, 0.f, 0.f, 1.f); - LOLUNIT_ASSERT_EQUAL(norm(i), 1.0f); - LOLUNIT_ASSERT_EQUAL(norm(j), 1.0f); - LOLUNIT_ASSERT_EQUAL(norm(k), 1.0f); - LOLUNIT_ASSERT_EQUAL(norm(one), 1.0f); + LOLUNIT_ASSERT_EQUAL(norm(one), 1.f); + LOLUNIT_ASSERT_EQUAL(norm(i), 1.f); + LOLUNIT_ASSERT_EQUAL(norm(j), 1.f); + LOLUNIT_ASSERT_EQUAL(norm(k), 1.f); LOLUNIT_ASSERT_EQUAL(i * i, -one); LOLUNIT_ASSERT_EQUAL(j * j, -one); @@ -106,40 +106,50 @@ LOLUNIT_FIXTURE(QuaternionTest) LOLUNIT_TEST(Normalize) { - quat a(2.0f, -2.0f, -8.0f, 3.0f); + quat a(2.f, -2.f, -8.f, 3.f); quat b = normalize(a); - LOLUNIT_ASSERT_DOUBLES_EQUAL(norm(b), 1.0, 1e-8); + LOLUNIT_ASSERT_DOUBLES_EQUAL(norm(b), 1.0, 1e-5); } LOLUNIT_TEST(Reciprocal) { - quat a(2.0f, -2.0f, -8.0f, 3.0f); + quat a(2.f, -2.f, -8.f, 3.f); quat b = re(a); quat m1 = a * b; quat m2 = b * a; - LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.x, m2.x, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.y, m2.y, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.z, m2.z, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.w, m2.w, 1e-8); - - LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.x, 0.0, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.y, 0.0, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.z, 0.0, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.w, 1.0, 1e-8); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.w, m2.w, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.x, m2.x, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.y, m2.y, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.z, m2.z, 1e-5); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.w, 1.0, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.x, 0.0, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.y, 0.0, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m1.z, 0.0, 1e-5); } LOLUNIT_TEST(Rotation) { - quat a = quat::rotate(10.0f, vec3(1, 0, 0)); - quat b = quat::rotate(20.0f, vec3(1, 0, 0)); + /* Check that rotating 10 degrees twice means rotating 20 degrees */ + quat a = quat::rotate(10.f, vec3(1, 0, 0)); + quat b = quat::rotate(20.f, vec3(1, 0, 0)); quat c = a * a; - LOLUNIT_ASSERT_DOUBLES_EQUAL(a.w, a.w, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(a.x, a.x, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(a.y, a.y, 1e-8); - LOLUNIT_ASSERT_DOUBLES_EQUAL(a.z, a.z, 1e-8); + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.w, b.w, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.x, b.x, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.y, b.y, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.z, b.z, 1e-5); + + /* Check that rotating 10 degrees then 20 is the same as 20 then 10 */ + quat d = a * b; + quat e = b * a; + + LOLUNIT_ASSERT_DOUBLES_EQUAL(e.w, d.w, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(e.x, d.x, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(e.y, d.y, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(e.z, d.z, 1e-5); } }; diff --git a/test/unit/rotation.cpp b/test/unit/rotation.cpp new file mode 100644 index 00000000..499aeaa5 --- /dev/null +++ b/test/unit/rotation.cpp @@ -0,0 +1,124 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2012 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/projects/COPYING.WTFPL for more details. +// + +#if defined HAVE_CONFIG_H +# include "config.h" +#endif + +#include "core.h" +#include "lol/unit.h" + +namespace lol +{ + +LOLUNIT_FIXTURE(RotationTest) +{ + void SetUp() {} + + void TearDown() {} + + LOLUNIT_TEST(Rotate2D) + { + /* Check that rotation is CCW */ + mat2 m90 = mat2::rotate(90.f); + + vec2 a(2.f, 3.f); + vec2 b = m90 * a; + + LOLUNIT_ASSERT_DOUBLES_EQUAL(b.x, -a.y, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(b.y, a.x, 1e-5); + } + + LOLUNIT_TEST(Compose2D) + { + /* Check that rotating 20 degrees twice means rotating 40 degrees */ + mat2 m20 = mat2::rotate(20.f); + mat2 m40 = mat2::rotate(40.f); + mat2 m20x20 = m20 * m20; + + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[0][0], m40[0][0], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[1][0], m40[1][0], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[0][1], m40[0][1], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[1][1], m40[1][1], 1e-5); + } + + LOLUNIT_TEST(Rotate3D) + { + /* Check that rotation is CCW around each axis */ + mat3 m90x = mat3::rotate(90.f, 1.f, 0.f, 0.f); + mat3 m90y = mat3::rotate(90.f, 0.f, 1.f, 0.f); + mat3 m90z = mat3::rotate(90.f, 0.f, 0.f, 1.f); + + vec3 a(2.f, 3.f, 4.f); + vec3 b = m90x * a; + vec3 c = m90y * a; + vec3 d = m90z * a; + + LOLUNIT_ASSERT_DOUBLES_EQUAL(b.x, a.x, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(b.y, -a.z, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(b.z, a.y, 1e-5); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.x, a.z, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.y, a.y, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.z, -a.x, 1e-5); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(d.x, -a.y, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(d.y, a.x, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(d.z, a.z, 1e-5); + } + + LOLUNIT_TEST(Compose3D) + { + /* Check that rotating 20 degrees twice means rotating 40 degrees */ + mat3 m20 = mat3::rotate(20.f, 1.f, 2.f, 3.f); + mat3 m40 = mat3::rotate(40.f, 1.f, 2.f, 3.f); + mat3 m20x20 = m20 * m20; + + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[0][0], m40[0][0], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[1][0], m40[1][0], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[2][0], m40[2][0], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[0][1], m40[0][1], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[1][1], m40[1][1], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[2][1], m40[2][1], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[0][2], m40[0][2], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[1][2], m40[1][2], 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(m20x20[2][2], m40[2][2], 1e-5); + } + + LOLUNIT_TEST(QuaternionTransform) + { + /* Check that rotating using a quaternion is the same as rotating + * using a matrix */ + mat3 m20 = mat3::rotate(20.f, 1.f, 2.f, 3.f); + quat q20 = quat::rotate(20.f, 1.f, 2.f, 3.f); + vec3 a(-2.f, 4.f, 3.f); + + vec3 b = m20 * a; + vec3 c = q20.transform(a); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.x, b.x, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.y, b.y, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(c.z, b.z, 1e-5); + } + + LOLUNIT_TEST(QuaternionFromMatrix) + { + quat q1 = quat::rotate(20.f, 1.f, 2.f, 3.f); + quat q2 = quat(mat3::rotate(20.f, 1.f, 2.f, 3.f)); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(q2.w, q1.w, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(q2.x, q1.x, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(q2.y, q1.y, 1e-5); + LOLUNIT_ASSERT_DOUBLES_EQUAL(q2.z, q1.z, 1e-5); + } +}; + +} /* namespace lol */ + diff --git a/win32/testsuite.vcxproj b/win32/testsuite.vcxproj index d57eab3b..5c6a1bef 100644 --- a/win32/testsuite.vcxproj +++ b/win32/testsuite.vcxproj @@ -36,6 +36,7 @@ +