TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
63 / 63
100.0%
Branches:
46 / 52
88.5%
Functions:
7 / 7
100.0%

layers/exposure.cpp
Line Branch Exec Source
1 #include "terraingen/layers/exposure.h"
2
3 #include "terraingen/layers/fade.h"
4 #include "terraingen/noise/perlin.h"
5 #include "terraingen/util/checks.h"
6 #include "terraingen/util/parallel.h"
7
8 #include <algorithm>
9 #include <array>
10 #include <cmath>
11 #include <stdexcept>
12
13 namespace terraingen {
14
15 namespace {
16
17 /// Smoothstep of where `value` lies between `low` and `high`.
18 10066773 double Share(double value, double low, double high) {
19 10066773 return Smoothstep((value - low) / (high - low));
20 }
21
22 } // namespace
23
24 27128 void ValidateExposureParams(const ExposureParams& params) {
25
1/1
✓ Branch 2 taken 27122 times.
27128 RequirePositive(params.reach, "Exposure reach");
26
5/6
✓ Branch 0 taken 27121 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 27121 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 27121 times.
54243 if (!(params.riseBoulder > params.riseSoil && std::isfinite(params.riseSoil) &&
27
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27121 times.
27121 std::isfinite(params.riseBoulder))) {
28
1/1
✓ Branch 2 taken 1 time.
1 throw std::invalid_argument("Exposure riseBoulder must exceed riseSoil");
29 }
30
5/6
✓ Branch 0 taken 27120 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 27120 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 27120 times.
54241 if (!(params.slopeBoulder > params.slopeSoil && std::isfinite(params.slopeSoil) &&
31
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27120 times.
27120 std::isfinite(params.slopeBoulder))) {
32
1/1
✓ Branch 2 taken 1 time.
1 throw std::invalid_argument("Exposure slopeBoulder must exceed slopeSoil");
33 }
34
3/4
✓ Branch 0 taken 27120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 27119 times.
27120 if (!(params.floorCover >= 0.0 && params.floorCover < 1.0)) {
35
1/1
✓ Branch 2 taken 1 time.
1 throw std::invalid_argument("Exposure floorCover must be in [0, 1)");
36 }
37
1/1
✓ Branch 2 taken 27118 times.
27119 RequirePositive(params.floorPatch, "Exposure floorPatch");
38 27118 }
39
40 13559 ExposureField::ExposureField(const ExposureParams& params, const Surface& surface)
41 13559 : params_(params), surface_(surface) {
42
1/1
✓ Branch 1 taken 13554 times.
13559 ValidateExposureParams(params_);
43 13559 }
44
45 3871530 double ExposureField::Exposure(const Ground& ground, double x, double y, double spacing) const {
46
1/1
✓ Branch 1 taken 3871530 times.
3871530 const float here = ground.HeightAt(x, y, spacing);
47
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3871529 times.
3871530 if (std::isnan(here)) {
48 1 return 0.0;
49 }
50 3871529 constexpr double kDiagonal = 0.70710678118654752;
51 3871529 constexpr std::array<double, 8> kEast{1.0, kDiagonal, 0.0, -kDiagonal,
52 -1.0, -kDiagonal, 0.0, kDiagonal};
53 3871529 constexpr std::array<double, 8> kNorth{0.0, kDiagonal, 1.0, kDiagonal,
54 0.0, -kDiagonal, -1.0, -kDiagonal};
55 3871529 const double reach = params_.reach;
56 3871529 std::array<double, 8> heights{};
57 3871529 double mean = 0.0;
58
2/2
✓ Branch 0 taken 30972232 times.
✓ Branch 1 taken 3871529 times.
34843761 for (std::size_t k = 0; k < 8; ++k) {
59
1/1
✓ Branch 3 taken 30972232 times.
30972232 const Vec2d at = surface_.Locate({x, y}, {kEast[k] * reach, kNorth[k] * reach});
60
1/1
✓ Branch 1 taken 30972232 times.
30972232 const float there = ground.HeightAt(at.x, at.y, spacing);
61
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30972232 times.
30972232 heights[k] = static_cast<double>(std::isnan(there) ? here : there);
62 30972232 mean += heights[k] / 8.0;
63 }
64 3871529 const double rise = (static_cast<double>(here) - mean) / reach;
65 const double slope =
66 3871529 std::hypot(heights[0] - heights[4], heights[2] - heights[6]) / (2.0 * reach);
67 3871529 double exposure = std::max(Share(rise, params_.riseSoil, params_.riseBoulder),
68
2/2
✓ Branch 1 taken 3871529 times.
✓ Branch 4 taken 3871529 times.
3871529 Share(slope, params_.slopeSoil, params_.slopeBoulder));
69
2/2
✓ Branch 0 taken 2323715 times.
✓ Branch 1 taken 1547814 times.
3871529 if (params_.floorCover > 0.0) {
70
1/1
✓ Branch 1 taken 2323715 times.
2323715 const double noise = PatchNoise(surface_, x, y, params_.floorPatch, params_.seed);
71 2323715 const double threshold = 1.0 - 2.0 * params_.floorCover;
72
1/1
✓ Branch 1 taken 2323715 times.
2323715 exposure = std::max(exposure, Share(noise, threshold - 0.2, threshold + 0.2));
73 }
74 3871529 return exposure;
75 }
76
77 6 void ExposureField::Fill(Raster<float>& raster, const Ground& ground, double spacing,
78 unsigned threads) const {
79
2/2
✓ Branch 1 taken 6 times.
✓ Branch 5 taken 6 times.
6 ParallelFor(raster.Height(), threads, [&](std::size_t row) {
80
2/2
✓ Branch 1 taken 555458 times.
✓ Branch 2 taken 1450 times.
556908 for (std::size_t col = 0; col < raster.Width(); ++col) {
81 555458 const Vec2d centre = raster.CellCenter(col, row);
82
1/1
✓ Branch 1 taken 555458 times.
555458 raster(col, row) = static_cast<float>(Exposure(ground, centre.x, centre.y, spacing));
83 }
84 1450 });
85 6 }
86
87 4958325 double PatchNoise(const Surface& surface, double x, double y, double size, std::uint32_t seed) {
88 4958325 double coarse = 0.0;
89 4958325 double fine = 0.0;
90
2/2
✓ Branch 1 taken 2003 times.
✓ Branch 2 taken 4956322 times.
4958325 if (surface.IsBody()) {
91
1/1
✓ Branch 1 taken 2003 times.
2003 const Vec3d p = surface.Position({x, y});
92 2003 const double s = 1.0 / size;
93
1/1
✓ Branch 1 taken 2003 times.
2003 coarse = static_cast<double>(PerlinNoise3Precise(s * p.x, s * p.y, s * p.z, seed));
94 2003 fine = static_cast<double>(
95
1/1
✓ Branch 1 taken 2003 times.
2003 PerlinNoise3Precise(4.0 * s * p.x, 4.0 * s * p.y, 4.0 * s * p.z, seed + 1u));
96 } else {
97 4956322 const auto px = static_cast<float>(x / size);
98 4956322 const auto py = static_cast<float>(y / size);
99 4956322 coarse = static_cast<double>(PerlinNoise2(px, py, seed));
100 4956322 fine = static_cast<double>(PerlinNoise2(4.0f * px, 4.0f * py, seed + 1u));
101 }
102
1/1
✓ Branch 1 taken 4958325 times.
4958325 return std::clamp(2.5 * (0.7 * coarse + 0.3 * fine), -1.0, 1.0);
103 }
104
105 } // namespace terraingen
106