TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
13 / 13
100.0%
Branches:
6 / 8
75.0%
Functions:
5 / 5
100.0%

layers/craters/shaping/datum.h
Line Branch Exec Source
1 /// @file
2 /// @brief Crater datums, the surfaces crater interiors are cut to, fitted to the ground.
3 #pragma once
4
5 #include "terraingen/layers/craters/profiles/profile.h"
6 #include "terraingen/layers/craters/shaping/apply_options.h"
7 #include "terraingen/layers/craters/shaping/prepared.h"
8 #include "terraingen/layers/ground.h"
9
10 #include <cstddef>
11 #include <cstdint>
12 #include <optional>
13 #include <unordered_map>
14 #include <vector>
15
16 namespace terraingen {
17
18 /// A least-squares plane h = a + b dx + c dy through points added one at a time.
19 class PlaneFit {
20 public:
21 /// Adds the point `dx` east and `dy` north (m) at height `h` (m).
22 void Add(double dx, double dy, double h);
23
24 /// Whether no point was added.
25 38487 bool Empty() const {
26 38487 return n_ == 0.0;
27 }
28
29 /// The mean height of the points; call only when not `Empty`.
30 1044 double Mean() const {
31 1044 return sh_ / n_;
32 }
33
34 /// The least-squares plane by Cramer's rule, or the flat plane at the mean for fewer than
35 /// three points or a degenerate layout; call only when not `Empty`.
36 Plane Solve() const;
37
38 private:
39 double n_ = 0.0;
40 double sx_ = 0.0;
41 double sy_ = 0.0;
42 double sxx_ = 0.0;
43 double sxy_ = 0.0;
44 double syy_ = 0.0;
45 double sh_ = 0.0;
46 double sxh_ = 0.0;
47 double syh_ = 0.0;
48 };
49
50 /// Points per side of the lattice crater datums are fitted over.
51 constexpr int kDatumLatticeSide = 7;
52
53 /// The offset (m) from a crater's centre of lattice point `index` (0 to `kDatumLatticeSide` - 1)
54 /// along one axis of a fit footprint of `fitRadius` (m).
55 4309984 inline double DatumLatticeOffset(int index, double fitRadius) {
56 4309984 return fitRadius * ((2.0 * index + 1.0) / kDatumLatticeSide - 1.0);
57 }
58
59 /// The datum a crater is cut to, fitted to the ground beneath it; nothing for
60 /// `CraterDatum::None` or where the ground has no data.
61 ///
62 /// `CentreHeight` reads the ground at the centre; `MeanHeight` and `Plane` fit it at the points of
63 /// a 7 x 7 lattice inside the `datumFitRadii` footprint.
64 std::optional<Plane> FitCraterDatum(const Crater& crater, const CraterApplyOptions& options,
65 const HeightSampler& ground);
66
67 /// Prepared craters indexed by position, to sum the relief of the craters before any one of
68 /// them at a point quickly.
69 ///
70 /// Craters are bucketed by size band, each band in square buckets twice its largest reach.
71 class CraterReliefIndex {
72 public:
73 /// Indexes craters; they and `profile` must outlive the index.
74 /// @param craters In the order applied; their datums are not read, so they may be set after the
75 /// index is built.
76 /// @param outlineScale Widens footprints; at least every crater's `CraterOutline::MaxScale`.
77 CraterReliefIndex(const std::vector<PreparedCrater>& craters, const CraterProfile& profile,
78 double outlineScale = 1.0, const Surface& surface = {});
79
80 /// The relief in metres at surface (x, y) of the craters before crater `k`: `resolution` times
81 /// the profile height of each, shaped by its slope as it is applied, summed in an order
82 /// independent of the other craters.
83 double ReliefBefore(double x, double y, std::size_t k) const;
84
85 /// The indexed craters, in the order applied.
86 1 const std::vector<PreparedCrater>& Craters() const {
87 1 return *craters_;
88 }
89
90 private:
91 struct Key {
92 6652 int band;
93 6652 std::int64_t i;
94 3680 std::int64_t j;
95 2274 std::int64_t k;
96
6/8
✗ Branch 0 not taken.
✓ Branch 1 taken 6652 times.
✓ Branch 2 taken 2972 times.
✓ Branch 3 taken 3680 times.
✓ Branch 4 taken 1406 times.
✓ Branch 5 taken 2274 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2274 times.
6652 bool operator==(const Key&) const = default;
97 };
98 struct KeyHash {
99 std::size_t operator()(const Key& key) const;
100 };
101
102 /// Adds to `relief` the relief at (`x`, `y`) of the craters of `bucket` before crater `k`.
103 void AddBucket(const std::vector<std::size_t>& bucket, double x, double y, std::size_t k,
104 double& relief) const;
105
106 const std::vector<PreparedCrater>* craters_;
107 const CraterProfile& profile_;
108 double outlineScale_ = 1.0;
109 Surface surface_;
110 std::vector<int> bands_;
111 std::unordered_map<Key, std::vector<std::size_t>, KeyHash> buckets_;
112 };
113
114 /// The ground crater `k` of `index` fits its datum to: `ground` plus the relief of the craters
115 /// applied before it, as if added without their own datums; NaN where `ground` has no data.
116 /// `ground` and `index` must outlive the result.
117 HeightSampler DatumGround(const HeightSampler& ground, const CraterReliefIndex& index,
118 std::size_t k);
119
120 /// How far (m) beyond a grid craters with a datum can change it through their datum fit: the fit
121 /// footprint plus the profile's reach for the largest crater; 0 without a datum. Craters for a
122 /// grid or point should be generated this far around it.
123 /// @param maxDiameter The largest crater's diameter, in metres.
124 double DatumMargin(const CraterApplyOptions& options, const CraterProfile& profile,
125 double maxDiameter);
126
127 } // namespace terraingen
128