diff options
Diffstat (limited to 'test/test-maths.cpp')
-rw-r--r-- | test/test-maths.cpp | 215 |
1 files changed, 168 insertions, 47 deletions
diff --git a/test/test-maths.cpp b/test/test-maths.cpp index 420b69e..02d3708 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -1,5 +1,6 @@ #define BOOST_TEST_MODULE test_maths +#include "test-helpers.hpp" #include <boost/test/data/test_case.hpp> #include <boost/test/unit_test.hpp> #include <glm/gtx/transform.hpp> @@ -7,22 +8,73 @@ #include <string_view> #include <type_traits> +#include <game/network/link.h> #include <glm/glm.hpp> #include <maths.h> #include <tuple> -using vecter_to_angle = std::tuple<glm::vec3, float>; +using vecter_and_angle = std::tuple<glm::vec3, float>; +using angle_pair = std::tuple<float, float>; +// +// STANDARD DEFINITIONS +// +// (x, y) in the 2D plane of geographic coordinates. +// (x, y, z) in the 3D plane, where (x, y) are geographic and z is veritcal. +// +// (x, y, 0) is sea level +// (x, y, +ve) is "up" +static_assert(up.z > 0); +static_assert(down == -up); +// (x, +ve, z) is "north" +static_assert(north.y > 0); +static_assert(south == -north); +// (x, -ve, z) is "south" +static_assert(south.y < 0); +// (+ve, y, z) is "east" +static_assert(east.x > 0); +static_assert(west == -east); +// (-ve, y, z) is "west" +static_assert(west.x < 0); +// +// Therefore, the geographic world exists west -ve to east +ve and from south -ve to north +ve. Forward shall be +// considered +ve motion; the "front" of a vehicle shall have a +ve value in y axis. +// +// An unrotated vehicle shall be facing north, thus forward motion of the vehicle shall increase it's position in the y +// axis. +// +// Positive rotation on the XY plane (y member, yaw, around the down axis, as would be expected for vehicle or building +// on flat land) shall be clockwise, in radians. Cycles shall be considered equal; 0 == 2pi, pi == -pi, 1/4pi == -3/4pi. + BOOST_DATA_TEST_CASE(test_vector_yaw, - boost::unit_test::data::make<vecter_to_angle>( - {{north, 0}, {south, pi}, {west, half_pi}, {east, -half_pi}, {north + east, -quarter_pi}, - {south + east, quarter_pi * -3}, {north + west, quarter_pi}, {south + west, quarter_pi * 3}}), + boost::unit_test::data::make<vecter_and_angle>( + {{up, 0}, {north, 0}, {south, pi}, {west, -half_pi}, {east, half_pi}, {north + east, quarter_pi}, + {south + east, quarter_pi * 3}, {north + west, -quarter_pi}, {south + west, -quarter_pi * 3}}), v, a) { BOOST_CHECK_CLOSE(vector_yaw(v), a, 1.F); } +BOOST_DATA_TEST_CASE(test_angle_normalize, + boost::unit_test::data::make<angle_pair>({ + {0, 0}, + {two_pi, 0}, + {-two_pi, 0}, + {half_pi, half_pi}, + {-half_pi, -half_pi}, + {half_pi * 3, -half_pi}, + {-half_pi * 3, half_pi}, + }), + in, exp) +{ + BOOST_CHECK_CLOSE(normalize(in), exp, 1); +} + +// Positive rotation on the YZ plane (x member, pitch, around the east axis relative to its yaw, as would be expected +// for a vehicle travelling forward uphill), in radians. Cycles can be considered non-sense as even in the worst/best +// cases pitch beyond +/- 1/2pi would be crashing. + BOOST_DATA_TEST_CASE(test_vector_pitch, - boost::unit_test::data::make<vecter_to_angle>({ + boost::unit_test::data::make<vecter_and_angle>({ {north, 0}, {east, 0}, {south, 0}, @@ -43,31 +95,48 @@ BOOST_DATA_TEST_CASE(test_vector_pitch, BOOST_CHECK_CLOSE(vector_pitch(v), a, 1.F); } -using normalize_angle = std::tuple<float, float>; -BOOST_DATA_TEST_CASE(test_angle_normalize, - boost::unit_test::data::make<normalize_angle>({ - {0, 0}, - {two_pi, 0}, - {-two_pi, 0}, - {half_pi, half_pi}, - {-half_pi, -half_pi}, - {half_pi * 3, -half_pi}, - {-half_pi * 3, half_pi}, - }), - in, exp) +// Positive rotation on the ZX plane (z member, roll, around Y axis relative to its yaw and pitch, as would be expected +// for an aircraft banking/turning right), in radians. Cycles can be considered non-sense as even in the worst/best +// cases pitch beyond +/- 1/2pi would be crashing. + +// The ILT functions rotate_yaw, rotate_pitch and rotate_roll provide a simple equivelent to glm::rotate around the +// stated axis. +const auto angs = boost::unit_test::data::make({pi, half_pi, two_pi, quarter_pi, -pi, -half_pi, -quarter_pi, 0.F}) + * boost::unit_test::data::make(0); +const auto random_angs = boost::unit_test::data::random(-two_pi, two_pi) ^ boost::unit_test::data::xrange(1000); +const auto rots = boost::unit_test::data::make<std::tuple<glm::vec3, glm::mat4 (*)(float), std::string_view>>({ + {down, rotate_yaw, "yaw"}, + {east, rotate_pitch, "pitch"}, + {north, rotate_roll, "roll"}, +}); +BOOST_DATA_TEST_CASE(test_rotations, (angs + random_angs) * rots, angle, ai, axis, ilt_func, name) { - BOOST_CHECK_CLOSE(normalize(in), exp, 1); + (void)ai; + BOOST_TEST_CONTEXT(name) { + const auto g {glm::rotate(angle, axis)}, ilt {ilt_func(angle)}; + for (glm::length_t c = 0; c < 4; c++) { + BOOST_TEST_CONTEXT(c) { + for (glm::length_t r = 0; r < 4; r++) { + BOOST_TEST_CONTEXT(r) { + BOOST_CHECK_CLOSE(g[c][r], ilt[c][r], 0.0001); + } + } + } + } + } } +// An arc shall be defined as a centre point, start point and end point. The arc shall progress positively from start to +// end in a clockwise manner. Arc start shall be the yaw from centre to start, arc end shall be greater than arc start. using pos3_to_arc = std::tuple<glm::vec3, glm::vec3, glm::vec3, Arc>; BOOST_DATA_TEST_CASE(test_create_arc, boost::unit_test::data::make<pos3_to_arc>({ - {{0, 0, 0}, north, east, {0, half_pi * 3}}, - {{0, 0, 0}, west, east, {half_pi, half_pi * 3}}, - {{0, 0, 0}, south, east, {pi, half_pi * 3}}, - {{0, 0, 0}, east, north, {-half_pi, 0}}, + {{0, 0, 0}, north, east, {0, half_pi}}, + {{0, 0, 0}, west, east, {-half_pi, half_pi}}, + {{0, 0, 0}, south, east, {pi, half_pi * 5}}, + {{0, 0, 0}, east, north, {half_pi, two_pi}}, {{0, 0, 0}, south, north, {pi, two_pi}}, - {{0, 0, 0}, east, south, {-half_pi, pi}}, + {{0, 0, 0}, east, south, {half_pi, pi}}, }), c, s, e, a) { @@ -99,33 +168,85 @@ BOOST_AUTO_TEST_CASE(test_find_arcs_radius) BOOST_CHECK_CLOSE(find_arcs_radius({10.32, 26.71}, {0.4, .92}, {2.92, 22.41}, {-0.89, -0.45}), 2.29, 1); } -static void -compare_rotations(float a, const glm::vec3 & axis, glm::mat4 (*rotate_func)(float), std::string_view n) +struct TestLinkStraight : public LinkStraight { + TestLinkStraight(glm::vec3 v) : + Link {{std::make_shared<Node>(origin), vector_yaw(v)}, {std::make_shared<Node>(v), vector_yaw(-v)}, + glm::length(v)} + { + } +}; + +using StraightsData = std::tuple<glm::vec3, float /*angFor*/, float /* angBack*/>; +BOOST_DATA_TEST_CASE(straight1, + boost::unit_test::data::make<StraightsData>({ + {north, 0, pi}, + {south, pi, 0}, + {east, half_pi, -half_pi}, + {west, -half_pi, half_pi}, + }), + v, angFor, angBack) { - BOOST_TEST_CONTEXT(n) { - const auto g {glm::rotate(a, axis)}, ilt {rotate_func(a)}; - for (int c = 0; c < 4; c++) { - BOOST_TEST_CONTEXT(c) { - for (int r = 0; r < 4; r++) { - BOOST_TEST_CONTEXT(r) { - BOOST_CHECK_CLOSE(g[c][r], ilt[c][r], 0.0001); - } - } - } - } + TestLinkStraight l(v); + { + const auto p = l.positionAt(0, 0); + BOOST_CHECK_EQUAL(p.pos, origin); + BOOST_CHECK_EQUAL(p.rot, glm::vec3(0, angFor, 0)); + } + { + const auto p = l.positionAt(0, 1); + BOOST_CHECK_EQUAL(p.pos, v); + BOOST_CHECK_EQUAL(p.rot, glm::vec3(0, angBack, 0)); } } -const auto angs = boost::unit_test::data::make({pi, half_pi, two_pi, quarter_pi, -pi, -half_pi, -quarter_pi, 0.F}) - * boost::unit_test::data::make(0); -const auto random_angs = boost::unit_test::data::random(-two_pi, two_pi) ^ boost::unit_test::data::xrange(1000); -const auto rots = boost::unit_test::data::make<std::tuple<glm::vec3, glm::mat4 (*)(float), std::string_view>>({ - {up, rotate_yaw, "yaw"}, - {west, rotate_pitch, "pitch"}, - {north, rotate_roll, "roll"}, -}); -BOOST_DATA_TEST_CASE(test_rotations, (angs + random_angs) * rots, a, ai, ax, func, n) +struct TestLinkCurve : public LinkCurve { + TestLinkCurve(glm::vec3 e0, glm::vec3 e1, glm::vec3 ctr) : + Link {{std::make_shared<Node>(e0), normalize(vector_yaw(ctr - e0) - half_pi)}, + {std::make_shared<Node>(e1), normalize(vector_yaw(ctr - e1) - half_pi)}, glm::length(e1 - e0)}, + LinkCurve(ctr, glm::length(e0 - ctr), {ctr, e0, e1}) + { + } +}; + +using CurvesData = std::tuple<glm::vec3 /*e1*/, glm::vec3 /*ctr*/, float /*angFor*/, float /* angBack*/>; +BOOST_DATA_TEST_CASE(curve1, + boost::unit_test::data::make<CurvesData>({ + {north + east, east, 0, -half_pi}, + {east * 2.F, east, 0, 0}, + {south + east, east, 0, half_pi}, + {south + west, west, pi, half_pi}, + }), + e1, ctr, angFor, angBack) { - (void)ai; - compare_rotations(a, ax, func, n); + { // One-way... + TestLinkCurve l(origin, e1, ctr); + BOOST_CHECK_EQUAL(l.radius, 1.F); + { + const auto p = l.positionAt(0, 0); + BOOST_CHECK_CLOSE_VEC(p.pos, origin); + BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angFor, 0)); + } + { + const auto p = l.positionAt(0, 1); + BOOST_CHECK_CLOSE_VEC(p.pos, e1); + BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBack, 0)); + } + } + + { // The other way... + TestLinkCurve l(e1, origin, ctr); + BOOST_CHECK_EQUAL(l.radius, 1.F); + { + const auto p = l.positionAt(0, 0); + const auto angForReversed = normalize(vector_yaw(origin - e1) * 2 - angFor); + BOOST_CHECK_CLOSE_VEC(p.pos, e1); + BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angForReversed, 0)); + } + { + const auto p = l.positionAt(0, 1); + const auto angBackReversed = normalize(vector_yaw(e1 - origin) * 2 - angBack); + BOOST_CHECK_CLOSE_VEC(p.pos, origin); + BOOST_CHECK_CLOSE_VEC(p.rot, glm::vec3(0, angBackReversed, 0)); + } + } } |