TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
92 / 92
100.0%
Branches:
59 / 59
100.0%
Functions:
17 / 17
100.0%

pipeline/terrain.cpp
Line Branch Exec Source
1 #include "terraingen/pipeline/terrain.h"
2
3 #include "terraingen/layers/evaluation_cache.h"
4 #include "terraingen/util/checks.h"
5 #include "terraingen/util/log.h"
6 #include "terraingen/util/parallel.h"
7
8 #include <algorithm>
9 #include <cmath>
10 #include <memory>
11 #include <optional>
12 #include <stdexcept>
13
14 namespace terraingen {
15
16 namespace {
17
18 /// Sets `heights` to the terrain's source at `points`, then applies its first `layers` layers to
19 /// them all at once, each on the ground beneath it.
20 41957430 void EvaluateStack(const Terrain& terrain, std::size_t layers, std::span<const Vec2d> points,
21 std::span<float> heights, double spacing, EvaluationCache* cache = nullptr) {
22
2/2
✓ Branch 1 taken 43172713 times.
✓ Branch 2 taken 41957430 times.
85130143 for (std::size_t i = 0; i < points.size(); ++i) {
23
2/2
✓ Branch 1 taken 7788804 times.
✓ Branch 2 taken 35383909 times.
43172713 heights[i] = terrain.source ? terrain.source->HeightAt(points[i].x, points[i].y) : 0.0f;
24 }
25
2/2
✓ Branch 0 taken 46565698 times.
✓ Branch 1 taken 41957430 times.
88523128 for (std::size_t n = 0; n < layers; ++n) {
26
1/1
✓ Branch 1 taken 46565698 times.
46565698 const TerrainGround ground(terrain, n);
27
1/1
✓ Branch 1 taken 46565698 times.
46565698 SampleBlock samples(points, heights);
28
1/1
✓ Branch 3 taken 46565698 times.
46565698 terrain.layers[n]->Apply(samples, LayerContext{spacing, 1, &ground, Backend::Cpu, cache});
29 46565698 }
30 41957430 }
31
32 } // namespace
33
34 65 Raster<float> Evaluate(const Terrain& terrain, const RasterGrid& grid, double spacing) {
35
1/1
✓ Branch 3 taken 62 times.
65 return Evaluate(terrain, grid, EvaluationOptions{spacing, 1});
36 }
37
38 1070 Raster<float> Evaluate(const Terrain& terrain, const RasterGrid& grid,
39 const EvaluationOptions& options) {
40 1070 ValidateTerrain(terrain);
41
1/1
✓ Branch 2 taken 1066 times.
1069 RequireNonNegative(options.spacing, "Sample spacing");
42
1/1
✓ Branch 1 taken 1066 times.
1066 const double resolved = std::max(options.spacing, grid.Spacing(terrain.surface));
43
2/2
✓ Branch 1 taken 1066 times.
✓ Branch 5 taken 1066 times.
1066 const Backend backend = ResolveBackend(options.backend.value_or(DefaultBackend()));
44 1066 Raster<float> heights = grid.MakeRaster();
45
2/2
✓ Branch 1 taken 913 times.
✓ Branch 2 taken 153 times.
1066 if (terrain.source) {
46
1/1
✓ Branch 2 taken 913 times.
913 terrain.source->Fill(heights);
47 }
48
2/2
✓ Branch 1 taken 1510 times.
✓ Branch 2 taken 1065 times.
2575 for (std::size_t n = 0; n < terrain.layers.size(); ++n) {
49 1510 const Stopwatch stopwatch;
50
1/1
✓ Branch 1 taken 1510 times.
1510 const TerrainGround ground(terrain, n);
51 1510 terrain.layers[n]->Apply(heights,
52
1/1
✓ Branch 1 taken 1509 times.
1510 LayerContext{resolved, options.threads, &ground, backend});
53
2/2
✓ Branch 1 taken 300 times.
✓ Branch 2 taken 1209 times.
1509 if (options.onLayer) {
54
2/2
✓ Branch 1 taken 300 times.
✓ Branch 4 taken 300 times.
300 options.onLayer(n, stopwatch.Milliseconds());
55 }
56 1510 }
57 1065 return heights;
58 1 }
59
60 65143 void ValidateTerrain(const Terrain& terrain) {
61
2/2
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 65137 times.
65143 if (std::any_of(terrain.layers.begin(), terrain.layers.end(),
62 158010 [](const auto& l) { return !l; })) {
63
1/1
✓ Branch 2 taken 6 times.
6 throw std::invalid_argument("A terrain's layers must not be null");
64 }
65 65137 }
66
67 50508 std::vector<float> EvaluatePoints(const Terrain& terrain, std::span<const Vec2d> points,
68 double spacing, unsigned threads) {
69
1/1
✓ Branch 1 taken 50506 times.
50508 ValidateTerrain(terrain);
70
1/1
✓ Branch 2 taken 50503 times.
50506 RequirePositive(spacing, "Sample spacing");
71 50503 constexpr std::size_t kBatch = 256;
72
1/1
✓ Branch 2 taken 50503 times.
50503 std::vector<float> heights(points.size());
73 50503 const std::size_t batches = (points.size() + kBatch - 1) / kBatch;
74 50503 std::optional<EvaluationCache> cache;
75
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 50487 times.
50503 if (batches > 1) {
76
1/1
✓ Branch 1 taken 16 times.
16 cache.emplace();
77 }
78
2/2
✓ Branch 1 taken 50503 times.
✓ Branch 4 taken 50503 times.
50503 ParallelFor(batches, threads, [&](std::size_t batch) {
79 51441 const std::size_t begin = batch * kBatch;
80 51441 const std::size_t count = std::min(kBatch, points.size() - begin);
81
3/3
✓ Branch 0 taken 955 times.
✓ Branch 1 taken 50486 times.
✓ Branch 6 taken 51441 times.
102882 EvaluateStack(terrain, terrain.layers.size(), points.subspan(begin, count),
82 51441 std::span<float>(heights).subspan(begin, count), spacing,
83 52396 cache ? &*cache : nullptr);
84 51441 });
85 101006 return heights;
86 50503 }
87
88 50486 float EvaluateAt(const Terrain& terrain, double x, double y, double spacing) {
89 50486 const Vec2d point{x, y};
90
1/1
✓ Branch 2 taken 50482 times.
50486 return EvaluatePoints(terrain, {&point, 1}, spacing, 1)[0];
91 }
92
93 46591716 TerrainGround::TerrainGround(const Terrain& terrain, std::size_t layers)
94 46591716 : terrain_(terrain), layers_(layers) {
95
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 46591714 times.
46591716 if (layers_ > terrain_.layers.size()) {
96
1/1
✓ Branch 2 taken 2 times.
2 throw std::invalid_argument("The terrain has fewer layers than the ground asks for");
97 }
98 46591716 }
99
100 41896782 float TerrainGround::HeightAt(double x, double y, double spacing) const {
101 41896782 const Vec2d point{x, y};
102 41896782 float height = 0.0f;
103
1/1
✓ Branch 3 taken 41896782 times.
41896782 EvaluateStack(terrain_, layers_, {&point, 1}, {&height, 1}, spacing);
104 41896782 return height;
105 }
106
107 45607 void TerrainGround::HeightsAt(std::span<const Vec2d> points, std::span<float> heights,
108 double spacing) const {
109 45607 constexpr std::size_t kBatch = 256;
110 45607 const std::size_t batches = (points.size() + kBatch - 1) / kBatch;
111 45607 std::optional<EvaluationCache> cache;
112
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 45549 times.
45607 if (batches > 1) {
113
1/1
✓ Branch 1 taken 58 times.
58 cache.emplace();
114 }
115
2/2
✓ Branch 1 taken 45607 times.
✓ Branch 4 taken 45607 times.
45607 ParallelFor(batches, 0, [&](std::size_t batch) {
116 9207 const std::size_t begin = batch * kBatch;
117 9207 const std::size_t count = std::min(kBatch, points.size() - begin);
118
2/2
✓ Branch 0 taken 3166 times.
✓ Branch 1 taken 6041 times.
12373 EvaluateStack(terrain_, layers_, points.subspan(begin, count),
119 12373 heights.subspan(begin, count), spacing, cache ? &*cache : nullptr);
120 9207 });
121 45607 }
122
123 namespace {
124
125 /// The ground beneath the first layers of a terrain it keeps.
126 class OwnedGround final : public Ground {
127 public:
128 6 OwnedGround(const Terrain& terrain, std::size_t layers)
129
2/2
✓ Branch 2 taken 6 times.
✓ Branch 6 taken 5 times.
7 : terrain_(std::make_shared<const Terrain>(terrain)), ground_(*terrain_, layers) {}
130
131 1 float HeightAt(double x, double y, double spacing) const override {
132 1 return ground_.HeightAt(x, y, spacing);
133 }
134 5 void HeightsAt(std::span<const Vec2d> points, std::span<float> heights,
135 double spacing) const override {
136 5 ground_.HeightsAt(points, heights, spacing);
137 5 }
138
139 private:
140 std::shared_ptr<const Terrain> terrain_;
141 TerrainGround ground_;
142 };
143
144 } // namespace
145
146 6 std::shared_ptr<const Ground> SharedGround(const Terrain& terrain, std::size_t layers) {
147
1/1
✓ Branch 1 taken 5 times.
6 return std::make_shared<OwnedGround>(terrain, layers);
148 }
149
150 37 Raster<float> Evaluate(const Terrain& terrain) {
151 37 ValidateTerrain(terrain);
152
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 34 times.
35 if (!terrain.source) {
153
1/1
✓ Branch 2 taken 1 time.
1 throw std::invalid_argument("A terrain without a source needs a grid to evaluate over");
154 }
155
2/2
✓ Branch 2 taken 34 times.
✓ Branch 5 taken 34 times.
34 return Evaluate(terrain, terrain.source->Grid());
156 }
157
158 } // namespace terraingen
159