#include "tap.hpp" #include "vector.hpp" #include "matrix.hpp" #include "quaternion.hpp" #include "coord/iostream.hpp" #include "matrix.hpp" #include /////////////////////////////////////////////////////////////////////////////// void test_matrix_identities (cruft::TAP::logger &tap) { static constexpr cruft::vector3f UP {0,1,0}; { cruft::point3f p { 1, 2, 3 }; auto m = cruft::translation (0-p); auto x = m * p; tap.expect_eq (x, cruft::point3f {0}, "trivial translation to origin"); } { cruft::point3f p {0}; auto m = cruft::rotation (1, { 1, 0, 0 }) * cruft::rotation (1, { 0, 1, 0 }) * cruft::rotation (1, { 0, 0, 1 }); auto x = m * p.homog (); tap.expect_eq (x, cruft::point4f {0,0,0,1}, "trivial rotation at origin"); } { cruft::point3f eye { 1, 2, 3 }; cruft::point3f tgt { 0, 0, 0 }; auto m = cruft::look_at (eye, tgt, UP); auto x = m * eye.homog (); tap.expect_eq (x, cruft::point4f {0,0,0,1}, "look_at eye translation"); } { cruft::point3f eye { 1, 2, 3 }; cruft::point3f tgt { 4, 5, 6 }; auto m = cruft::look_at (eye, tgt, UP); auto x = m * eye.homog (); tap.expect_eq (x, cruft::point4f {0,0,0,1}, "look_at eye translation with target"); } } /////////////////////////////////////////////////////////////////////////////// void test_perspective (cruft::TAP::logger &tap) { static const struct { float w, h; float near, far; float fov; float a, b, c, d; } TESTS[] = { { 1.f, 1.f, 1.f, 100.f, 45.f, 2.414213419f, 2.414213419f, -1.020202041f, -2.020201921f }, { 1.f, 1.f, 1.f, 100.f, 60.f, 1.732050776f, 1.732050776f, -1.020202041f, -2.020201921f }, { 1.f, 1.f, 1.f, 100.f, 90.f, 1.000000000f, 1.000000000f, -1.020202041f, -2.020201921f }, { 1.f, 1.f, 1.f, 100.f, 120.f, 0.577350199f, 0.577350199f, -1.020202041f, -2.020201921f }, { 1.f, 1.f, 1e-08f, 1e+08f, 45.f, 2.414213419f, 2.414213419f, -1.000000000f, -0.000000020f }, { 1.f, 1.f, 1e-08f, 1e+08f, 60.f, 1.732050776f, 1.732050776f, -1.000000000f, -0.000000020f }, { 1.f, 1.f, 1e-08f, 1e+08f, 90.f, 1.000000000f, 1.000000000f, -1.000000000f, -0.000000020f }, { 1.f, 1.f, 1e-08f, 1e+08f, 120.f, 0.577350199f, 0.577350199f, -1.000000000f, -0.000000020f }, { 1.f, 1.f, 0.01f, 1000.f, 45.f, 2.414213419f, 2.414213419f, -1.000020027f, -0.020000201f }, { 1.f, 1.f, 0.01f, 1000.f, 60.f, 1.732050776f, 1.732050776f, -1.000020027f, -0.020000201f }, { 1.f, 1.f, 0.01f, 1000.f, 90.f, 1.000000000f, 1.000000000f, -1.000020027f, -0.020000201f }, { 1.f, 1.f, 0.01f, 1000.f, 120.f, 0.577350199f, 0.577350199f, -1.000020027f, -0.020000201f }, { 4.f, 3.f, 1.f, 100.f, 45.f, 1.810660124f, 2.414213419f, -1.020202041f, -2.020201921f }, { 4.f, 3.f, 1.f, 100.f, 60.f, 1.299038053f, 1.732050776f, -1.020202041f, -2.020201921f }, { 4.f, 3.f, 1.f, 100.f, 90.f, 0.750000000f, 1.000000000f, -1.020202041f, -2.020201921f }, { 4.f, 3.f, 1.f, 100.f, 120.f, 0.433012664f, 0.577350199f, -1.020202041f, -2.020201921f }, { 4.f, 3.f, 1e-08f, 1e+08f, 45.f, 1.810660124f, 2.414213419f, -1.000000000f, -0.000000020f }, { 4.f, 3.f, 1e-08f, 1e+08f, 60.f, 1.299038053f, 1.732050776f, -1.000000000f, -0.000000020f }, { 4.f, 3.f, 1e-08f, 1e+08f, 90.f, 0.750000000f, 1.000000000f, -1.000000000f, -0.000000020f }, { 4.f, 3.f, 1e-08f, 1e+08f, 120.f, 0.433012664f, 0.577350199f, -1.000000000f, -0.000000020f }, { 4.f, 3.f, 0.01f, 1000.f, 45.f, 1.810660124f, 2.414213419f, -1.000020027f, -0.020000201f }, { 4.f, 3.f, 0.01f, 1000.f, 60.f, 1.299038053f, 1.732050776f, -1.000020027f, -0.020000201f }, { 4.f, 3.f, 0.01f, 1000.f, 90.f, 0.750000000f, 1.000000000f, -1.000020027f, -0.020000201f }, { 4.f, 3.f, 0.01f, 1000.f, 120.f, 0.433012664f, 0.577350199f, -1.000020027f, -0.020000201f }, { 16.f, 9.f, 1.f, 100.f, 45.f, 1.357995033f, 2.414213419f, -1.020202041f, -2.020201921f }, { 16.f, 9.f, 1.f, 100.f, 60.f, 0.974278569f, 1.732050776f, -1.020202041f, -2.020201921f }, { 16.f, 9.f, 1.f, 100.f, 90.f, 0.562500000f, 1.000000000f, -1.020202041f, -2.020201921f }, { 16.f, 9.f, 1.f, 100.f, 120.f, 0.324759483f, 0.577350199f, -1.020202041f, -2.020201921f }, { 16.f, 9.f, 1e-08f, 1e+08f, 45.f, 1.357995033f, 2.414213419f, -1.000000000f, -0.000000020f }, { 16.f, 9.f, 1e-08f, 1e+08f, 60.f, 0.974278569f, 1.732050776f, -1.000000000f, -0.000000020f }, { 16.f, 9.f, 1e-08f, 1e+08f, 90.f, 0.562500000f, 1.000000000f, -1.000000000f, -0.000000020f }, { 16.f, 9.f, 1e-08f, 1e+08f, 120.f, 0.324759483f, 0.577350199f, -1.000000000f, -0.000000020f }, { 16.f, 9.f, 0.01f, 1000.f, 45.f, 1.357995033f, 2.414213419f, -1.000020027f, -0.020000201f }, { 16.f, 9.f, 0.01f, 1000.f, 60.f, 0.974278569f, 1.732050776f, -1.000020027f, -0.020000201f }, { 16.f, 9.f, 0.01f, 1000.f, 90.f, 0.562500000f, 1.000000000f, -1.000020027f, -0.020000201f }, { 16.f, 9.f, 0.01f, 1000.f, 120.f, 0.324759483f, 0.577350199f, -1.000020027f, -0.020000201f }, { 16.f, 10.f, 1.f, 100.f, 45.f, 1.508883357f, 2.414213419f, -1.020202041f, -2.020201921f }, { 16.f, 10.f, 1.f, 100.f, 60.f, 1.082531691f, 1.732050776f, -1.020202041f, -2.020201921f }, { 16.f, 10.f, 1.f, 100.f, 90.f, 0.625000000f, 1.000000000f, -1.020202041f, -2.020201921f }, { 16.f, 10.f, 1.f, 100.f, 120.f, 0.360843867f, 0.577350199f, -1.020202041f, -2.020201921f }, { 16.f, 10.f, 1e-08f, 1e+08f, 45.f, 1.508883357f, 2.414213419f, -1.000000000f, -0.000000020f }, { 16.f, 10.f, 1e-08f, 1e+08f, 60.f, 1.082531691f, 1.732050776f, -1.000000000f, -0.000000020f }, { 16.f, 10.f, 1e-08f, 1e+08f, 90.f, 0.625000000f, 1.000000000f, -1.000000000f, -0.000000020f }, { 16.f, 10.f, 1e-08f, 1e+08f, 120.f, 0.360843867f, 0.577350199f, -1.000000000f, -0.000000020f }, { 16.f, 10.f, 0.01f, 1000.f, 45.f, 1.508883357f, 2.414213419f, -1.000020027f, -0.020000201f }, { 16.f, 10.f, 0.01f, 1000.f, 60.f, 1.082531691f, 1.732050776f, -1.000020027f, -0.020000201f }, { 16.f, 10.f, 0.01f, 1000.f, 90.f, 0.625000000f, 1.000000000f, -1.000020027f, -0.020000201f }, { 16.f, 10.f, 0.01f, 1000.f, 120.f, 0.360843867f, 0.577350199f, -1.000020027f, -0.020000201f }, { 21.f, 9.f, 1.f, 100.f, 45.f, 1.034662843f, 2.414213419f, -1.020202041f, -2.020201921f }, { 21.f, 9.f, 1.f, 100.f, 60.f, 0.742307484f, 1.732050776f, -1.020202041f, -2.020201921f }, { 21.f, 9.f, 1.f, 100.f, 90.f, 0.428571433f, 1.000000000f, -1.020202041f, -2.020201921f }, { 21.f, 9.f, 1.f, 100.f, 120.f, 0.247435793f, 0.577350199f, -1.020202041f, -2.020201921f }, { 21.f, 9.f, 1e-08f, 1e+08f, 45.f, 1.034662843f, 2.414213419f, -1.000000000f, -0.000000020f }, { 21.f, 9.f, 1e-08f, 1e+08f, 60.f, 0.742307484f, 1.732050776f, -1.000000000f, -0.000000020f }, { 21.f, 9.f, 1e-08f, 1e+08f, 90.f, 0.428571433f, 1.000000000f, -1.000000000f, -0.000000020f }, { 21.f, 9.f, 1e-08f, 1e+08f, 120.f, 0.247435793f, 0.577350199f, -1.000000000f, -0.000000020f }, { 21.f, 9.f, 0.01f, 1000.f, 45.f, 1.034662843f, 2.414213419f, -1.000020027f, -0.020000201f }, { 21.f, 9.f, 0.01f, 1000.f, 60.f, 0.742307484f, 1.732050776f, -1.000020027f, -0.020000201f }, { 21.f, 9.f, 0.01f, 1000.f, 90.f, 0.428571433f, 1.000000000f, -1.000020027f, -0.020000201f }, { 21.f, 9.f, 0.01f, 1000.f, 120.f, 0.247435793f, 0.577350199f, -1.000020027f, -0.020000201f }, }; for (const auto &t: TESTS) { cruft::matrix4f m {0}; m[0][0] = t.a; m[1][1] = t.b; m[2][2] = t.c; m[2][3] = t.d; m[3][2] = -1.f; const auto p = cruft::perspective (cruft::to_radians (t.fov), t.w / t.h, {t.near, t.far}); tap.expect ( cruft::relatively_equal (m, p, 1e-7f), "perspective {}:{}@{}", t.w, t.h, t.fov ); } } /////////////////////////////////////////////////////////////////////////////// void test_mq_axis (cruft::TAP::logger &tap) { static const struct { cruft::vector3f euler; const char *msg; } TESTS[] = { { { 1, 0, 0 }, "x-axis" }, { { 0, 1, 0 }, "y-axis" }, { { 0, 0, 1 }, "z-axis" }, }; for (auto t: TESTS) { auto m = cruft::rotation (1, t.euler); auto q = cruft::quaternionf::angle_axis (1, t.euler); auto diff = sum (abs (m - q.as_matrix ())); tap.expect_le (diff, 1e-6f, "matrix/quaternion rotation identities, {:s}", t.msg); } } /////////////////////////////////////////////////////////////////////////////// void test_mq_euler (cruft::TAP::logger &tap) { static const struct { float x, y, z; const char *msg; } TESTS[] = { { 0, 0, 0, "zeroes" }, { 1, 0, 0, "x-axis" }, { 0, 1, 0, "y-axis" }, { 0, 0, 1, "z-axis" }, { 1, 1, 1, "ones" }, { 3, 3, 3, "threes" } }; for (auto t: TESTS) { const auto mx = cruft::rotation (t.x, {1,0,0}); const auto my = cruft::rotation (t.y, {0,1,0}); const auto mz = cruft::rotation (t.z, {0,0,1}); const auto m = mx * my * mz; auto q = ( cruft::quaternionf::angle_axis (t.x, { 1, 0, 0 }) * cruft::quaternionf::angle_axis (t.y, { 0, 1, 0 }) * cruft::quaternionf::angle_axis (t.z, { 0, 0, 1 }) ).as_matrix (); auto diff = cruft::sum (abs (m - q)); tap.expect_le (diff, 1e-6f, "matrix-quaternion xyz euler rotations, {:s}", t.msg); } } /////////////////////////////////////////////////////////////////////////////// int main (int, char**) { cruft::TAP::logger tap; test_matrix_identities (tap); test_mq_axis (tap); test_mq_euler (tap); test_perspective (tap); return tap.status (); }