From b7fadd730a78671a0eaf55c36df24c04661ef2c3 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 16 Nov 2021 00:07:48 +0000 Subject: Swap y,z axis This was a pain... but all the coords make much more sense now and a lot of mystery negation has disappeared. --- test/test-helpers.hpp | 18 +++++ test/test-maths.cpp | 215 +++++++++++++++++++++++++++++++++++++++----------- test/test-network.cpp | 72 +++++++++++++++-- test/test-obj.cpp | 2 +- 4 files changed, 254 insertions(+), 53 deletions(-) create mode 100644 test/test-helpers.hpp (limited to 'test') 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 +#include + +#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 #include #include @@ -7,22 +8,73 @@ #include #include +#include #include #include #include -using vecter_to_angle = std::tuple; +using vecter_and_angle = std::tuple; +using angle_pair = std::tuple; +// +// 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( - {{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( + {{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({ + {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({ + boost::unit_test::data::make({ {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; -BOOST_DATA_TEST_CASE(test_angle_normalize, - boost::unit_test::data::make({ - {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>({ + {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; BOOST_DATA_TEST_CASE(test_create_arc, boost::unit_test::data::make({ - {{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(origin), vector_yaw(v)}, {std::make_shared(v), vector_yaw(-v)}, + glm::length(v)} + { + } +}; + +using StraightsData = std::tuple; +BOOST_DATA_TEST_CASE(straight1, + boost::unit_test::data::make({ + {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>({ - {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(e0), normalize(vector_yaw(ctr - e0) - half_pi)}, + {std::make_shared(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; +BOOST_DATA_TEST_CASE(curve1, + boost::unit_test::data::make({ + {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 #include @@ -8,6 +9,7 @@ #include #include #include // IWYU pragma: keep +#include #include #include #include @@ -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 { TestNetwork() : NetworkOf {RESDIR "rails.jpg"} @@ -31,13 +33,13 @@ struct TestNetwork : public NetworkOf { // \ | / // \ 5 / // 3 | 4 - // \-> p101 <-/ + // \-> p110 <-/ addLink(p000, p100, 1.F); addLink(p100, p200, 1.F); addLink(p200, p300, 1.F); - addLink(p000, p101, 2.F); - addLink(p200, p101, 2.F); - addLink(p100, p101, 1.F); + addLink(p000, p110, 2.F); + addLink(p200, p110, 2.F); + addLink(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(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(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(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(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()); } -- cgit v1.2.3