diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-02-24 01:28:14 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-02-24 01:28:14 +0000 |
commit | ef08a08617a1541d8aa1862d8bcfe049dcb57998 (patch) | |
tree | abfcb0e0146a29deead395b0a730acaf8b01dc47 /test | |
parent | Merge branch 'terrain-deform-2' (diff) | |
parent | New hardcoded test rail network (diff) | |
download | ilt-ef08a08617a1541d8aa1862d8bcfe049dcb57998.tar.bz2 ilt-ef08a08617a1541d8aa1862d8bcfe049dcb57998.tar.xz ilt-ef08a08617a1541d8aa1862d8bcfe049dcb57998.zip |
Merge remote-tracking branch 'origin/terrain-for-networks'
Diffstat (limited to 'test')
-rw-r--r-- | test/Jamfile.jam | 2 | ||||
-rw-r--r-- | test/fixtures/geoData/deform/multi1.json | 21 | ||||
-rw-r--r-- | test/perf-geoData.cpp | 15 | ||||
-rw-r--r-- | test/test-geoData-counts.cpp | 65 | ||||
-rw-r--r-- | test/test-geoData.cpp | 116 | ||||
-rw-r--r-- | test/test-lib.cpp | 45 | ||||
-rw-r--r-- | test/test-maths.cpp | 96 | ||||
-rw-r--r-- | test/test-network.cpp | 69 | ||||
-rw-r--r-- | test/test-render.cpp | 20 |
9 files changed, 371 insertions, 78 deletions
diff --git a/test/Jamfile.jam b/test/Jamfile.jam index 3ab4c4c..c5c49d2 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -47,7 +47,7 @@ lib test : [ glob *.cpp : test-*.cpp perf-*.cpp ] ; run test-collection.cpp ; run test-maths.cpp ; run test-lib.cpp ; -run test-geoData.cpp : -- : [ sequence.insertion-sort [ glob-tree $(fixtures)/geoData : *.json ] fixtures/height/SD19.asc ] : <library>test ; +run [ glob test-geoData*.cpp ] : -- : [ sequence.insertion-sort [ glob-tree $(fixtures)/geoData : *.json ] fixtures/height/SD19.asc ] : <library>test ; run test-network.cpp : : : <library>test ; run test-persistence.cpp : -- : [ sequence.insertion-sort [ glob-tree $(fixtures)/json : *.json ] ] : <library>test ; run test-text.cpp : -- : test-glContainer : <library>test ; diff --git a/test/fixtures/geoData/deform/multi1.json b/test/fixtures/geoData/deform/multi1.json new file mode 100644 index 0000000..c7456b6 --- /dev/null +++ b/test/fixtures/geoData/deform/multi1.json @@ -0,0 +1,21 @@ +[ + [ + [ + [ + 100, + 100, + 100 + ], + [ + 150, + 100, + 100 + ], + [ + 100, + 150, + 100 + ] + ] + ] +] diff --git a/test/perf-geoData.cpp b/test/perf-geoData.cpp index 4d4505e..d9ea8c6 100644 --- a/test/perf-geoData.cpp +++ b/test/perf-geoData.cpp @@ -33,10 +33,25 @@ namespace { }); } } + + void + terrain_deform(benchmark::State & state) + { + std::array<GlobalPosition3D, 3> points {{ + {315555000, 495556000, 0}, + {315655000, 495556000, 0}, + {315655000, 495557000, 0}, + }}; + for (auto _ : state) { + auto geoData {tm}; + benchmark::DoNotOptimize(geoData.setHeights(points, GeoData::SetHeightsOpts {.surface = nullptr})); + } + } } BENCHMARK(terrain_findPoint); BENCHMARK(terrain_walk); BENCHMARK(terrain_walkBoundary); +BENCHMARK(terrain_deform); BENCHMARK_MAIN(); diff --git a/test/test-geoData-counts.cpp b/test/test-geoData-counts.cpp new file mode 100644 index 0000000..446a68a --- /dev/null +++ b/test/test-geoData-counts.cpp @@ -0,0 +1,65 @@ +#include <OpenMesh/Core/IO/MeshIO.hh> +#include <boost/test/data/test_case.hpp> +#include <boost/test/test_tools.hpp> +#include <boost/test/unit_test_suite.hpp> + +#include "game/geoData.h" + +using GeoMutation = std::function<void(GeoData &)>; +using Something = std::tuple<const char *, GeoMutation, size_t, size_t, size_t>; +BOOST_TEST_DONT_PRINT_LOG_VALUE(GeoMutation); + +BOOST_TEST_DECORATOR(*boost::unit_test::timeout(2)); + +BOOST_DATA_TEST_CASE(deformLogical, + boost::unit_test::data::make<Something>({ + {"nochange", [](GeoData &) {}, 16, 33, 18}, // No change base case + {"simple", + [](GeoData & geoData) { + Surface surface; + // Basic triangle, no crossing, simple case + geoData.setHeights(std::array<GlobalPosition3D, 3> {{ + {2000, 8000, 1000}, + {2000, 4000, 1000}, + {6000, 8000, 1000}, + }}, + {.surface = &surface, .nearNodeTolerance = 0}); + }, + 19, 42, 24}, + {"simple-cross", + [](GeoData & geoData) { + Surface surface; + // Basic triangle, with crossing, reasonably simple case + geoData.setHeights(std::array<GlobalPosition3D, 3> {{ + {2000, 8000, 1000}, + {3000, 4000, 1000}, + {4000, 9000, 1000}, + }}, + {.surface = &surface, .nearNodeTolerance = 0}); + }, + 19, 42, 24}, + {"quad-multi-cross", + [](GeoData & geoData) { + Surface surface; + // Basic quad, with crossing, spans into adjacent original triangle, should remove that edge + geoData.setHeights(std::array<GlobalPosition3D, 4> {{ + {2000, 8000, 1000}, + {3000, 4000, 1000}, + {4000, 9000, 1000}, + {8000, 2000, 1000}, + }}, + {.surface = &surface, .nearNodeTolerance = 0}); + }, + 20, 45, 26}, + }), + name, func, expVertices, expEdges, expFaces) +{ + auto geoData = GeoData::createFlat({0, 0}, {30'000, 30'000}, 1000); + + BOOST_REQUIRE_NO_THROW(func(geoData)); + OpenMesh::IO::write_mesh(geoData, std::format("/tmp/mesh-{}.obj", name)); + + BOOST_CHECK_EQUAL(geoData.n_vertices(), expVertices); + BOOST_CHECK_EQUAL(geoData.n_edges(), expEdges); + BOOST_CHECK_EQUAL(geoData.n_faces(), expFaces); +} diff --git a/test/test-geoData.cpp b/test/test-geoData.cpp index bd1ff87..2332513 100644 --- a/test/test-geoData.cpp +++ b/test/test-geoData.cpp @@ -29,26 +29,9 @@ BOOST_AUTO_TEST_CASE(loadSuccess) BOOST_CHECK_EQUAL(upper, GlobalPosition3D(319950000, 499950000, 571600)); } -BOOST_AUTO_TEST_CASE(normalsAllPointUp) +BOOST_AUTO_TEST_CASE(sanityCheck) { - BOOST_CHECK(std::ranges::all_of(vertices(), [this](auto && vertex) { - return normal(vertex).z > 0; - })); -} - -BOOST_AUTO_TEST_CASE(trianglesContainsPoints) -{ - const auto face = face_handle(0); - - BOOST_TEST_CONTEXT(this->triangle<2>(face)) { - BOOST_CHECK(triangleContainsPoint(GlobalPosition2D {xllcorner, yllcorner}, face)); - BOOST_CHECK(triangleContainsPoint(GlobalPosition2D {xllcorner + cellsize, yllcorner + cellsize}, face)); - BOOST_CHECK(triangleContainsPoint(GlobalPosition2D {xllcorner, yllcorner + cellsize}, face)); - BOOST_CHECK(triangleContainsPoint(GlobalPosition2D {xllcorner + 1, yllcorner + 1}, face)); - BOOST_CHECK(triangleContainsPoint(GlobalPosition2D {xllcorner + 1, yllcorner + 2}, face)); - BOOST_CHECK(!triangleContainsPoint(GlobalPosition2D {xllcorner + 3, yllcorner + 2}, face)); - BOOST_CHECK(!triangleContainsPoint(GlobalPosition2D {xllcorner + cellsize, yllcorner}, face)); - } + BOOST_CHECK_NO_THROW(sanityCheck()); } BOOST_AUTO_TEST_SUITE_END(); @@ -105,7 +88,7 @@ BOOST_DATA_TEST_CASE(findPositionAt, }), p, h) { - BOOST_CHECK_EQUAL(fixedTerrtain.positionAt(p), GlobalPosition3D(p, h)); + BOOST_CHECK_EQUAL(fixedTerrtain.positionAt(p), p || h); } using FindRayIntersectData = std::tuple<GlobalPosition3D, Direction3D, GlobalPosition3D>; @@ -150,8 +133,11 @@ BOOST_DATA_TEST_CASE(walkTerrain, from, to, visits) { std::vector<int> visited; - BOOST_CHECK_NO_THROW(fixedTerrtain.walk(from, to, [&visited](auto fh) { - visited.emplace_back(fh.idx()); + BOOST_CHECK_NO_THROW(fixedTerrtain.walk(from, to, [&visited](auto step) { + if (!visited.empty()) { + BOOST_CHECK_EQUAL(step.previous.idx(), visited.back()); + } + visited.emplace_back(step.current.idx()); })); BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); } @@ -183,28 +169,57 @@ BOOST_DATA_TEST_CASE(walkTerrainUntil, from, to, visits) { std::vector<int> visited; - BOOST_CHECK_NO_THROW(fixedTerrtain.walkUntil(from, to, [&visited](auto fh) { - visited.emplace_back(fh.idx()); + BOOST_CHECK_NO_THROW(fixedTerrtain.walkUntil(from, to, [&visited](const auto & step) { + visited.emplace_back(step.current.idx()); return visited.size() >= 5; })); BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); } -BOOST_AUTO_TEST_CASE(triangle_helpers) +using WalkTerrainCurveData = std::tuple<GlobalPosition2D, GlobalPosition2D, GlobalPosition2D, std::vector<int>, + std::vector<GlobalPosition2D>>; + +BOOST_TEST_DECORATOR(*boost::unit_test::timeout(1)) + +BOOST_DATA_TEST_CASE(walkTerrainCurveSetsFromFace, + boost::unit_test::data::make<WalkTerrainCurveData>({ + {{310002000, 490003000}, {310002000, 490003000}, {310002000, 490003000}, {0}, {}}, + {{310003000, 490002000}, {310003000, 490002000}, {310003000, 490002000}, {1}, {}}, + {{310202000, 490203000}, {310002000, 490003000}, {310002000, 490203000}, + {1600, 1601, 1202, 1201, 802, 803, 404, 403, 4, 3, 2, 1, 0}, + { + {310201997, 490201997}, + {310201977, 490200000}, + {310200000, 490174787}, + {310194850, 490150000}, + {310192690, 490142690}, + {310173438, 490100000}, + {310150000, 490068479}, + {310130806, 490050000}, + {310100000, 490028656}, + {310062310, 490012310}, + {310050000, 490008845}, + {310003003, 490003003}, + }}, + {{310999999, 490205000}, {310999999, 490203000}, {310999000, 490204000}, {1631, 1632, 1631}, + { + {311000000, 490204999}, + {311000000, 490203001}, + }}, + }), + from, to, centre, visits, exits) { - constexpr static GeoData::Triangle<3> t {{0, 0, 0}, {5, 0, 0}, {5, 5, 0}}; - - BOOST_CHECK_EQUAL(t.nnormal(), up); - BOOST_CHECK_CLOSE(t.angle(0), quarter_pi, 0.01F); - BOOST_CHECK_CLOSE(t.angleAt({0, 0, 0}), quarter_pi, 0.01F); - BOOST_CHECK_CLOSE(t.angle(1), half_pi, 0.01F); - BOOST_CHECK_CLOSE(t.angleAt({5, 0, 0}), half_pi, 0.01F); - BOOST_CHECK_CLOSE(t.angle(2), quarter_pi, 0.01F); - BOOST_CHECK_CLOSE(t.angleAt({5, 5, 0}), quarter_pi, 0.01F); - - BOOST_CHECK_CLOSE(t.angleAt({0, 1, 0}), 0.F, 0.01F); + BOOST_REQUIRE_EQUAL(visits.size(), exits.size() + 1); - BOOST_CHECK_CLOSE(t.area(), 12.5F, 0.01F); + std::vector<int> visited; + std::vector<GlobalPosition2D> exited; + BOOST_CHECK_NO_THROW(fixedTerrtain.walk(from, to, centre, [&](const auto & step) { + visited.emplace_back(step.current.idx()); + BOOST_REQUIRE(!std::ranges::contains(exited, step.exitPosition)); + exited.emplace_back(step.exitPosition); + })); + BOOST_CHECK_EQUAL_COLLECTIONS(visited.begin(), visited.end(), visits.begin(), visits.end()); + BOOST_CHECK_EQUAL_COLLECTIONS(exited.begin() + 1, exited.end(), exits.begin(), exits.end()); } using FindEntiesData = std::tuple<GlobalPosition2D, GlobalPosition2D, int>; @@ -229,18 +244,13 @@ BOOST_DATA_TEST_CASE(deform, loadFixtureJson<DeformTerrainData>("geoData/deform/ { Surface surface; surface.colorBias = RGB {0, 0, 1}; - auto gd = std::make_shared<GeoData>(GeoData::createFlat({0, 0}, {1000000, 1000000}, 100)); - BOOST_CHECK_NO_THROW(gd->setHeights(points, {.surface = surface})); - BOOST_CHECK(std::ranges::all_of(gd->vertices(), [&gd](auto && vertex) { - return gd->normal(vertex).z > 0; - })); ApplicationBase ab; TestMainWindow tmw; TestRenderOutput tro {{640, 480}}; struct TestTerrain : public SceneProvider { - explicit TestTerrain(std::shared_ptr<GeoData> gd) : terrain(std::move(gd)) { } + explicit TestTerrain(GeoData gd) : terrain(std::move(gd)) { } const Terrain terrain; @@ -269,7 +279,11 @@ BOOST_DATA_TEST_CASE(deform, loadFixtureJson<DeformTerrainData>("geoData/deform/ } }; - TestTerrain t {gd}; + TestTerrain t {[&points, &surface]() { + auto gd = GeoData::createFlat({0, 0}, {1000000, 1000000}, 100); + BOOST_CHECK_NO_THROW(gd.setHeights(points, {.surface = &surface})); + return gd; + }()}; SceneRenderer ss {tro.size, tro.output}; std::for_each(cams.begin(), cams.end(), [&ss, &t, &tro](const auto & cam) { ss.camera.setView(cam.first.first, glm::normalize(cam.first.second)); @@ -277,3 +291,17 @@ BOOST_DATA_TEST_CASE(deform, loadFixtureJson<DeformTerrainData>("geoData/deform/ Texture::save(tro.outImage, cam.second.c_str()); }); } + +BOOST_TEST_DECORATOR(*boost::unit_test::timeout(2)); + +BOOST_DATA_TEST_CASE( + deformMulti, loadFixtureJson<std::vector<std::vector<GlobalPosition3D>>>("geoData/deform/multi1.json"), points) +{ + BOOST_REQUIRE(!points.empty()); + Surface surface; + auto gd = std::make_shared<GeoData>(GeoData::createFlat({0, 0}, {1000000, 1000000}, 100)); + for (const auto & strip : points) { + BOOST_REQUIRE_GE(strip.size(), 3); + BOOST_CHECK_NO_THROW(gd->setHeights(strip, {.surface = &surface, .nearNodeTolerance = 50})); + } +} diff --git a/test/test-lib.cpp b/test/test-lib.cpp index 5f0b5e5..17c0f63 100644 --- a/test/test-lib.cpp +++ b/test/test-lib.cpp @@ -3,6 +3,7 @@ #include "testHelpers.h" #include <boost/test/data/test_case.hpp> #include <boost/test/unit_test.hpp> +#include <stream_support.h> #include <collections.h> #include <glArrays.h> @@ -66,6 +67,46 @@ BOOST_AUTO_TEST_CASE(triangle_strip_iter) out.push_back(c); }); BOOST_REQUIRE_EQUAL(out.size(), (TRIANGLE_STRIP_IN.size() - 2) * 3); - BOOST_CHECK_EQUAL_COLLECTIONS( - out.begin(), out.end(), TRIANGLE_STRIP_EXPECTED.begin(), TRIANGLE_STRIP_EXPECTED.end()); + BOOST_CHECK_EQUAL_COLCOL(out, TRIANGLE_STRIP_EXPECTED); +} + +BOOST_AUTO_TEST_CASE(triangle_strip_range_adapter) +{ + using TriTuple = std::tuple<int, int, int>; + std::vector<TriTuple> outRange; + std::ranges::copy(TRIANGLE_STRIP_IN | triangleTriples, std::back_inserter(outRange)); + constexpr std::array<TriTuple, 4> TRIANGLE_STRIP_EXPECTED_TUPLES {{{0, 1, 2}, {2, 1, 3}, {2, 3, 4}, {4, 3, 5}}}; + BOOST_CHECK_EQUAL_COLCOL(outRange, TRIANGLE_STRIP_EXPECTED_TUPLES); +} + +using MergeCloseData = std::tuple<std::vector<int>, int, std::vector<int>>; + +BOOST_DATA_TEST_CASE(mergeCloseInts, + boost::unit_test::data::make<MergeCloseData>({ + {{0}, 0, {0}}, + {{0, 1}, 0, {0, 1}}, + {{0, 1}, 2, {0, 1}}, + {{0, 1, 2}, 2, {0, 2}}, + {{0, 1, 4}, 2, {0, 4}}, + {{0, 1, 2}, 4, {0, 2}}, + {{0, 4, 8}, 4, {0, 8}}, + {{0, 4, 10, 14}, 4, {0, 14}}, + {{0, 3, 6}, 2, {0, 3, 6}}, + {{0, 3, 4}, 2, {0, 4}}, + {{0, 5, 7, 12}, 4, {0, 6, 12}}, + {{0, 3, 4, 5, 10, 17, 18, 19}, 2, {0, 4, 10, 19}}, + }), + collection, tolerance, expected) +{ + auto mutableCollection {collection}; + BOOST_REQUIRE_NO_THROW((mergeClose( + mutableCollection, + [](int left, int right) { + return std::abs(left - right); + }, + [](int left, int right) { + return (left + right) / 2; + }, + tolerance))); + BOOST_CHECK_EQUAL_COLCOL(mutableCollection, expected); } diff --git a/test/test-maths.cpp b/test/test-maths.cpp index b9d08bb..a6b780a 100644 --- a/test/test-maths.cpp +++ b/test/test-maths.cpp @@ -12,6 +12,7 @@ #include <gfx/gl/camera.h> #include <glm/glm.hpp> #include <maths.h> +#include <triangle.h> #include <tuple> using vecter_and_angle = std::tuple<glm::vec3, float>; @@ -341,3 +342,98 @@ static_assert(linesIntersectAt(GlobalPosition2D {311000100, 491100100}, {3110500 .value() == GlobalPosition2D {311000100, 491100100}); static_assert(!linesIntersectAt(glm::dvec2 {0, 1}, {0, 4}, {1, 8}, {1, 4}).has_value()); + +BOOST_AUTO_TEST_CASE(triangle2d_helpers) +{ + constexpr static Triangle<2, float> t {{0, 0}, {5, 0}, {5, 5}}; + + BOOST_CHECK_CLOSE(t.angle(0), quarter_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angleAt({0, 0}), quarter_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angle(1), half_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angleAt({5, 0}), half_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angle(2), quarter_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angleAt({5, 5}), quarter_pi, 0.01F); + + BOOST_CHECK_CLOSE(t.angleAt({0, 1}), 0.F, 0.01F); + + BOOST_CHECK_CLOSE(t.area(), 12.5F, 0.01F); +} + +BOOST_AUTO_TEST_CASE(triangle3d_helpers) +{ + constexpr static Triangle<3, float> t {{0, 0, 0}, {5, 0, 0}, {5, 5, 0}}; + + BOOST_CHECK_EQUAL(t.nnormal(), up); + BOOST_CHECK_CLOSE(t.angle(0), quarter_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angleAt({0, 0, 0}), quarter_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angle(1), half_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angleAt({5, 0, 0}), half_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angle(2), quarter_pi, 0.01F); + BOOST_CHECK_CLOSE(t.angleAt({5, 5, 0}), quarter_pi, 0.01F); + + BOOST_CHECK_CLOSE(t.angleAt({0, 1, 0}), 0.F, 0.01F); + + BOOST_CHECK_CLOSE(t.area(), 12.5F, 0.01F); +} + +using ArcLineIntersectExp = std::pair<GlobalPosition2D, Angle>; +using ArcLineIntersectData = std::tuple<GlobalPosition2D, GlobalPosition2D, GlobalPosition2D, GlobalPosition2D, + GlobalPosition2D, std::optional<ArcLineIntersectExp>>; + +BOOST_DATA_TEST_CASE(arcline_intersection, + boost::unit_test::data::make<ArcLineIntersectData>({ + {{0, 0}, {0, 100}, {100, 0}, {200, 0}, {0, 200}, std::nullopt}, + {{0, 0}, {0, 100}, {100, 0}, {0, 0}, {10, 10}, std::nullopt}, + {{0, 0}, {0, 100}, {100, 0}, {0, 0}, {100, 100}, ArcLineIntersectExp {{71, 71}, quarter_pi}}, + {{15, 27}, {15, 127}, {115, 27}, {15, 27}, {115, 127}, ArcLineIntersectExp {{86, 98}, quarter_pi}}, + {{0, 0}, {0, 100}, {100, 0}, {0, 0}, {-100, -100}, std::nullopt}, + {{0, 0}, {0, 100}, {100, 0}, {-10, 125}, {125, -10}, ArcLineIntersectExp {{16, 99}, 0.164F}}, + {{0, 0}, {0, 100}, {100, 0}, {125, -10}, {-10, 125}, ArcLineIntersectExp {{99, 16}, 1.407F}}, + {{0, 0}, {0, 100}, {100, 0}, {10, 125}, {125, -10}, ArcLineIntersectExp {{38, 93}, 0.385F}}, + {{0, 0}, {0, 100}, {100, 0}, {12, 80}, {125, -10}, ArcLineIntersectExp {{99, 10}, 1.467F}}, + {{0, 0}, {0, 100}, {100, 0}, {40, 80}, {125, -10}, ArcLineIntersectExp {{98, 18}, 1.387F}}, + {{0, 0}, {0, 100}, {100, 0}, {40, 80}, {80, 20}, std::nullopt}, + {{0, 0}, {0, 100}, {100, 0}, {40, 80}, {80, 80}, ArcLineIntersectExp {{60, 80}, 0.6435F}}, + {{0, 0}, {0, 100}, {100, 0}, {80, 40}, {80, 80}, ArcLineIntersectExp {{80, 60}, 0.9273F}}, + {{310002000, 490203000}, {310202000, 490203000}, {310002000, 490003000}, {310200000, 490150000}, + {310150000, 490150000}, ArcLineIntersectExp {{310194850, 490150000}, 1.839F}}, + }), + centre, arcStart, arcEnd, lineStart, lineEnd, expected) +{ + const ArcSegment arc {centre, arcStart, arcEnd}; + BOOST_TEST_INFO(arc.first); + BOOST_TEST_INFO(arc.second); + BOOST_TEST_INFO(arc.length()); + + const auto intersection = arc.crossesLineAt(lineStart, lineEnd); + BOOST_REQUIRE_EQUAL(expected.has_value(), intersection.has_value()); + if (expected.has_value()) { + BOOST_CHECK_EQUAL(expected->first, intersection->first); + BOOST_CHECK_CLOSE(expected->second, intersection->second, 1.F); + } +} + +static_assert(pointLeftOfLine({1, 2}, {1, 1}, {2, 2})); +static_assert(pointLeftOfLine({2, 1}, {2, 2}, {1, 1})); +static_assert(pointLeftOfLine({2, 2}, {1, 2}, {2, 1})); +static_assert(pointLeftOfLine({1, 1}, {2, 1}, {1, 2})); +static_assert(pointLeftOfOrOnLine({310000000, 490000000}, {310000000, 490000000}, {310050000, 490050000})); +static_assert(pointLeftOfOrOnLine({310000000, 490000000}, {310050000, 490050000}, {310000000, 490050000})); +static_assert(pointLeftOfOrOnLine({310000000, 490000000}, {310000000, 490050000}, {310000000, 490000000})); + +static_assert(linesCross({1, 1}, {2, 2}, {1, 2}, {2, 1})); +static_assert(linesCross({2, 2}, {1, 1}, {1, 2}, {2, 1})); + +static_assert(linesCrossLtR({1, 1}, {2, 2}, {1, 2}, {2, 1})); +static_assert(!linesCrossLtR({2, 2}, {1, 1}, {1, 2}, {2, 1})); + +static_assert(Triangle<3, GlobalDistance> {{1, 2, 3}, {1, 0, 1}, {-2, 1, 0}}.positionOnPlane({7, -2}) + == GlobalPosition3D {7, -2, 3}); +static_assert(Triangle<3, GlobalDistance> { + {310000000, 490000000, 32800}, {310050000, 490050000, 33000}, {310000000, 490050000, 32700}} + .positionOnPlane({310000000, 490000000}) + == GlobalPosition3D {310000000, 490000000, 32800}); +static_assert(Triangle<3, GlobalDistance> { + {310750000, 490150000, 58400}, {310800000, 490200000, 55500}, {310750000, 490200000, 57600}} + .positionOnPlane({310751000, 490152000}) + == GlobalPosition3D {310751000, 490152000, 58326}); diff --git a/test/test-network.cpp b/test/test-network.cpp index 59eebae..e7419b5 100644 --- a/test/test-network.cpp +++ b/test/test-network.cpp @@ -47,8 +47,8 @@ struct TestLinkS : public TestLink, public LinkStraight { } }; -constexpr GlobalPosition3D p000 {0, 0, 0}, p100 {10000, 0, 0}, p200 {20000, 0, 0}, p300 {30000, 0, 0}; -constexpr GlobalPosition3D p110 {10000, 10000, 0}; +constexpr GlobalPosition3D p000 {0, 0, 500}, p100 {10500, 0, 1000}, p200 {20100, 0, 2000}, p300 {30700, 0, 3000}; +constexpr GlobalPosition3D p110 {10300, 10400, 4000}; template<> NetworkLinkHolder<TestLinkS>::NetworkLinkHolder() = default; @@ -73,6 +73,18 @@ struct TestNetwork : public NetworkOf<TestLink, TestLinkS> { render(const SceneShader &) const override { } + + const Surface * + getBaseSurface() const override + { + return nullptr; + } + + RelativeDistance + getBaseWidth() const override + { + return 5'700; + } }; const auto VALID_NODES = boost::unit_test::data::make<GlobalPosition3D>({ @@ -208,6 +220,14 @@ BOOST_AUTO_TEST_CASE(routeTo_downStream_3to300) BOOST_AUTO_TEST_SUITE_END() +namespace std { + std::ostream & + operator<<(std::ostream & s, const Link::End & e) + { + return s << std::format("End[dir: {}, loc: ({}, {}, {})]", e.dir, e.node->pos.x, e.node->pos.y, e.node->pos.z); + } +} + BOOST_FIXTURE_TEST_CASE(test_rail_network, RailLinks) { // 0 1 2 @@ -221,7 +241,7 @@ BOOST_FIXTURE_TEST_CASE(test_rail_network, RailLinks) // -------- auto l0 = addLinksBetween(p000, p100); BOOST_CHECK(dynamic_cast<RailLinkStraight *>(l0.get())); - BOOST_CHECK_EQUAL(l0->length, 10000); + BOOST_CHECK_EQUAL(l0->length, ::distance(p000, p100)); 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()); @@ -229,7 +249,7 @@ BOOST_FIXTURE_TEST_CASE(test_rail_network, RailLinks) auto l1 = addLinksBetween(p200, p100); BOOST_CHECK(dynamic_cast<RailLinkStraight *>(l1.get())); - BOOST_CHECK_EQUAL(l1->length, 10000); + BOOST_CHECK_EQUAL(l1->length, ::distance(p200, p100)); 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()); @@ -241,7 +261,7 @@ BOOST_FIXTURE_TEST_CASE(test_rail_network, RailLinks) auto l2 = addLinksBetween(p200, p300); BOOST_CHECK(dynamic_cast<RailLinkStraight *>(l2.get())); - BOOST_CHECK_EQUAL(l2->length, 10000); + BOOST_CHECK_EQUAL(l2->length, ::distance(p200, p300)); 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()); @@ -251,19 +271,28 @@ BOOST_FIXTURE_TEST_CASE(test_rail_network, RailLinks) 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) * 10000.F, 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, 30400.F, 0.1F); - BOOST_CHECK_BETWEEN(l4->ends[0].dir, .23F, .24F); - BOOST_CHECK_CLOSE(l4->ends[1].dir, half_pi, 0.1F); + BOOST_CHECK_IF(l3, addLinksBetween(p000, p110)) { + BOOST_CHECK_IF(l3c, dynamic_cast<RailLinkCurve *>(l3.get())) { + BOOST_CHECK_CLOSE(l3c->radius, 10'300.F, 0.1F); + BOOST_CHECK_CLOSE(l3c->arc.length(), pi + half_pi, 0.5F); + BOOST_CHECK_CLOSE(l3->length, 48'563.F, 0.1F); + BOOST_CHECK_CLOSE(l3->ends[0].dir, -half_pi, 0.5F); + BOOST_CHECK_CLOSE(l3->ends[1].dir, -0.0097F, 0.5F); + 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()); + } + } + + BOOST_CHECK_IF(l4, addLinksBetween(p110, p300)) { + BOOST_CHECK_IF(l4c, dynamic_cast<RailLinkCurve *>(l4.get())) { + BOOST_CHECK_CLOSE(l4c->radius, 6950.F, 0.1F); + BOOST_CHECK_CLOSE(l4c->arc.length(), 4.456F, 0.1F); + BOOST_CHECK_CLOSE(l4->length, 30'981.F, 0.1F); + BOOST_CHECK_BETWEEN(l4->ends[0].dir, .25F, .26F); + BOOST_CHECK_CLOSE(l4->ends[1].dir, half_pi, 0.1F); + } + } } diff --git a/test/test-render.cpp b/test/test-render.cpp index 3966f28..3c453bd 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -30,11 +30,10 @@ class TestScene : public SceneProvider { RailVehicleClassPtr brush47rvc; std::shared_ptr<RailVehicle> train1, train2; RailLinks rail; - std::shared_ptr<GeoData> gd = std::make_shared<GeoData>(GeoData::createFlat({0, 0}, {1000000, 1000000}, 1)); std::shared_ptr<Environment> env = std::make_shared<Environment>(); - Terrain terrain {gd}; - Water water {gd}; + std::shared_ptr<Terrain> terrain = std::make_shared<Terrain>(GeoData::createFlat({0, 0}, {1000000, 1000000}, 1)); + Water water {terrain}; public: TestScene() @@ -71,7 +70,7 @@ public: void content(const SceneShader & shader) const override { - terrain.render(shader); + terrain->render(shader); water.render(shader); rail.render(shader); std::ranges::for_each(gameState->assets, [&shader](const auto & asset) { @@ -95,7 +94,7 @@ public: void shadows(const ShadowMapper & shadowMapper) const override { - terrain.shadows(shadowMapper); + terrain->shadows(shadowMapper); std::ranges::for_each(gameState->assets, [&shadowMapper](const auto & asset) { if (const auto renderable = std::dynamic_pointer_cast<const Renderable>(asset.second)) { renderable->shadows(shadowMapper); @@ -167,15 +166,14 @@ BOOST_AUTO_TEST_CASE(terrain) ss.camera.setView({310000000, 490000000, 600000}, glm::normalize(glm::vec3 {1, 1, -0.5F})); class TestTerrain : public SceneProvider { - std::shared_ptr<GeoData> gd - = std::make_shared<GeoData>(GeoData::loadFromAsciiGrid(FIXTURESDIR "height/SD19.asc")); - Terrain terrain {gd}; - Water water {gd}; + std::shared_ptr<Terrain> terrain + = std::make_shared<Terrain>(GeoData::loadFromAsciiGrid(FIXTURESDIR "height/SD19.asc")); + Water water {terrain}; void content(const SceneShader & shader) const override { - terrain.render(shader); + terrain->render(shader); water.render(shader); } @@ -194,7 +192,7 @@ BOOST_AUTO_TEST_CASE(terrain) void shadows(const ShadowMapper & shadowMapper) const override { - terrain.shadows(shadowMapper); + terrain->shadows(shadowMapper); } }; |