summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/test-helpers.hpp18
-rw-r--r--test/test-maths.cpp215
-rw-r--r--test/test-network.cpp72
-rw-r--r--test/test-obj.cpp2
4 files changed, 254 insertions, 53 deletions
diff --git a/test/test-helpers.hpp b/test/test-helpers.hpp
new file mode 100644
index 0000000..294b6ff
--- /dev/null
+++ b/test/test-helpers.hpp
@@ -0,0 +1,18 @@
+#ifndef TEST_HELPERS_H
+#define TEST_HELPERS_H
+
+#include <boost/test/tools/context.hpp>
+#include <boost/test/tools/interface.hpp>
+
+#define BOOST_CHECK_CLOSE_VEC(a, b) \
+ BOOST_TEST_CONTEXT("BOOST_CHECK_CLOSE_VEC(" << a << ", " << b << ")") { \
+ BOOST_CHECK_LT(glm::length(a - b), 0.1F); \
+ }
+
+#define BOOST_CHECK_BETWEEN(a, b, c) \
+ BOOST_TEST_CONTEXT("BOOST_CHECK_BETWEEN(" << a << ", " << b << ", " << c << ")") { \
+ BOOST_CHECK_LE(b, a); \
+ BOOST_CHECK_GE(c, a); \
+ }
+
+#endif
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));
+ }
+ }
}
diff --git a/test/test-network.cpp b/test/test-network.cpp
index 7727434..70f2428 100644
--- a/test/test-network.cpp
+++ b/test/test-network.cpp
@@ -1,5 +1,6 @@
#define BOOST_TEST_MODULE network
+#include "test-helpers.hpp"
#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test.hpp>
@@ -8,6 +9,7 @@
#include <game/network/link.h>
#include <game/network/network.h>
#include <game/network/network.impl.h> // IWYU pragma: keep
+#include <game/network/rail.h>
#include <glm/glm.hpp>
#include <maths.h>
#include <memory>
@@ -21,7 +23,7 @@ struct TestLink : public LinkStraight {
};
constexpr glm::vec3 p000 {0, 0, 0}, p100 {1, 0, 0}, p200 {2, 0, 0}, p300 {3, 0, 0};
-constexpr glm::vec3 p101 {1, 0, 1};
+constexpr glm::vec3 p110 {1, 1, 0};
struct TestNetwork : public NetworkOf<TestLink> {
TestNetwork() : NetworkOf<TestLink> {RESDIR "rails.jpg"}
@@ -31,13 +33,13 @@ struct TestNetwork : public NetworkOf<TestLink> {
// \ | /
// \ 5 /
// 3 | 4
- // \-> p101 <-/
+ // \-> p110 <-/
addLink<TestLink>(p000, p100, 1.F);
addLink<TestLink>(p100, p200, 1.F);
addLink<TestLink>(p200, p300, 1.F);
- addLink<TestLink>(p000, p101, 2.F);
- addLink<TestLink>(p200, p101, 2.F);
- addLink<TestLink>(p100, p101, 1.F);
+ addLink<TestLink>(p000, p110, 2.F);
+ addLink<TestLink>(p200, p110, 2.F);
+ addLink<TestLink>(p100, p110, 1.F);
}
};
@@ -173,3 +175,63 @@ BOOST_AUTO_TEST_CASE(routeTo_downStream_3to300)
}
BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_FIXTURE_TEST_CASE(test_rail_network, RailLinks)
+{
+ // 0 1 2
+ // --p000 <-> p100 <-> p200 <-> p300 \ x
+ // / ?----- \ x
+ // / / \ |
+ // | / 4 /
+ // 3 p110 \ /
+ // \ | \ /
+ // \ / ------/
+ // --------
+ auto l0 = addLinksBetween(p000, p100);
+ BOOST_CHECK(dynamic_cast<RailLinkStraight *>(l0.get()));
+ BOOST_CHECK_EQUAL(l0->length, 1.F);
+ BOOST_CHECK_CLOSE(l0->ends[0].dir, half_pi, 0.1F);
+ BOOST_CHECK_CLOSE(l0->ends[1].dir, -half_pi, 0.1F);
+ BOOST_CHECK(l0->ends[0].nexts.empty());
+ BOOST_CHECK(l0->ends[1].nexts.empty());
+
+ auto l1 = addLinksBetween(p200, p100);
+ BOOST_CHECK(dynamic_cast<RailLinkStraight *>(l1.get()));
+ BOOST_CHECK_EQUAL(l1->length, 1.F);
+ BOOST_CHECK_CLOSE(l1->ends[0].dir, half_pi, 0.1F);
+ BOOST_CHECK_CLOSE(l1->ends[1].dir, -half_pi, 0.1F);
+ BOOST_CHECK(l0->ends[0].nexts.empty());
+ BOOST_CHECK_EQUAL(l0->ends[1].nexts.at(0).first.lock(), l1);
+ BOOST_CHECK_EQUAL(l0->ends[1].nexts.at(0).second, 0);
+ BOOST_CHECK_EQUAL(l1->ends[0].nexts.at(0).first.lock(), l0);
+ BOOST_CHECK_EQUAL(l1->ends[0].nexts.at(0).second, 1);
+ BOOST_CHECK(l1->ends[1].nexts.empty());
+
+ auto l2 = addLinksBetween(p200, p300);
+ BOOST_CHECK(dynamic_cast<RailLinkStraight *>(l2.get()));
+ BOOST_CHECK_EQUAL(l2->length, 1.F);
+ BOOST_CHECK_CLOSE(l2->ends[0].dir, half_pi, 0.1F);
+ BOOST_CHECK_CLOSE(l2->ends[1].dir, -half_pi, 0.1F);
+ BOOST_CHECK(l0->ends[0].nexts.empty());
+ BOOST_CHECK_EQUAL(l1->ends[1].nexts.at(0).first.lock(), l2);
+ BOOST_CHECK_EQUAL(l1->ends[1].nexts.at(0).second, 0);
+ BOOST_CHECK_EQUAL(l2->ends[0].nexts.at(0).first.lock(), l1);
+ BOOST_CHECK_EQUAL(l2->ends[0].nexts.at(0).second, 1);
+ BOOST_CHECK(l2->ends[1].nexts.empty());
+
+ auto l3 = addLinksBetween(p000, p110);
+ BOOST_CHECK(dynamic_cast<RailLinkCurve *>(l3.get()));
+ BOOST_CHECK_CLOSE(l3->length, pi + half_pi, 0.1F);
+ BOOST_CHECK_CLOSE(l3->ends[0].dir, -half_pi, 0.1F);
+ BOOST_CHECK_CLOSE(l3->ends[1].dir, 0, 0.1F);
+ BOOST_CHECK_EQUAL(l0->ends[0].nexts.at(0).first.lock(), l3);
+ BOOST_CHECK_EQUAL(l0->ends[0].nexts.at(0).second, 0);
+ BOOST_CHECK_EQUAL(l3->ends[0].nexts.at(0).first.lock(), l0);
+ BOOST_CHECK_EQUAL(l3->ends[0].nexts.at(0).second, 0);
+ BOOST_CHECK(l3->ends[1].nexts.empty());
+
+ auto l4 = addLinksBetween(p110, p300);
+ BOOST_CHECK_CLOSE(l4->length, 3.04F, 0.1F);
+ BOOST_CHECK_BETWEEN(l4->ends[0].dir, .23F, .24F);
+ BOOST_CHECK_CLOSE(l4->ends[1].dir, half_pi, 0.1F);
+}
diff --git a/test/test-obj.cpp b/test/test-obj.cpp
index 813a69c..c7bd6ce 100644
--- a/test/test-obj.cpp
+++ b/test/test-obj.cpp
@@ -34,6 +34,6 @@ BOOST_AUTO_TEST_CASE(create_meshes)
const auto & o = ms.at("Body");
BOOST_REQUIRE_EQUAL(88, o.first.size());
const auto & v = o.first.front();
- BOOST_REQUIRE_CLOSE(1.345, v.pos.x, 1);
+ BOOST_REQUIRE_CLOSE(-1.345, v.pos.x, 1);
BOOST_REQUIRE_EQUAL(138, o.second.size());
}