summaryrefslogtreecommitdiff
path: root/test/test-maths.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/test-maths.cpp')
-rw-r--r--test/test-maths.cpp215
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));
+ }
+ }
}