summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/Jamfile.jam2
-rw-r--r--test/fixtures/geoData/deform/multi1.json21
-rw-r--r--test/perf-geoData.cpp15
-rw-r--r--test/test-geoData-counts.cpp65
-rw-r--r--test/test-geoData.cpp116
-rw-r--r--test/test-lib.cpp45
-rw-r--r--test/test-maths.cpp96
-rw-r--r--test/test-network.cpp69
-rw-r--r--test/test-render.cpp20
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);
}
};