TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
142 / 142
100.0%
Branches:
78 / 90
86.7%
Functions:
4 / 4
100.0%

layers/craters/shaping/crater_kernel.cpp
Line Branch Exec Source
1 #include "terraingen/layers/craters/shaping/crater_kernel.h"
2
3 #include "terraingen/layers/craters/degradation/diffusion.h"
4 #include "terraingen/layers/craters/profiles/complex.h"
5 #include "terraingen/layers/craters/profiles/fassett_thomson.h"
6 #include "terraingen/layers/craters/profiles/martin_parkes_dunstan.h"
7 #include "terraingen/layers/craters/shaping/apply.h"
8 #include "terraingen/noise/hash.h"
9
10 #include <map>
11 #include <stdexcept>
12
13 namespace terraingen {
14
15 namespace {
16
17 /// The key that seeds `crater`'s noise or texture with `seed`.
18 4248544 std::uint32_t CraterKey(const Crater& crater, std::uint32_t seed) {
19 4248544 return PcgHash(static_cast<std::uint32_t>(crater.id) ^
20 8497088 PcgHash(static_cast<std::uint32_t>(crater.id >> 32) ^ seed));
21 }
22
23 /// Whether the simple profile shapes `crater` in `state`: not where the table or the complex
24 /// form does.
25 1775188 bool ShapesSimply(const CraterShapeKernel& kernel, double diameter, const CraterState& state) {
26 1775188 const CraterProfileKernel& p = kernel.profile;
27
4/4
✓ Branch 0 taken 1615180 times.
✓ Branch 1 taken 160008 times.
✓ Branch 2 taken 1601621 times.
✓ Branch 3 taken 13559 times.
1775188 if (p.diffused == 1u && state.diffusion > 0.0) {
28 1601621 return false;
29 }
30
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 173567 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
173567 return !(p.complex == 1u && diameter >= static_cast<double>(p.transitionDiameter));
31 }
32
33 } // namespace
34
35 1499330 std::optional<CraterShapeKernel> MakeCraterShapeKernel(const CraterProfile& profile,
36 const CraterApplyOptions& options) {
37
2/2
✓ Branch 1 taken 482291 times.
✓ Branch 2 taken 1017039 times.
1499330 if (options.surface.IsBody()) {
38 482291 return std::nullopt;
39 }
40 1017039 CraterShapeKernel k;
41 1017039 const CraterProfile* fresh = &profile;
42
3/4
✓ Branch 0 taken 1017039 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 103719 times.
✓ Branch 3 taken 913320 times.
1017039 if (const auto* diffused = dynamic_cast<const DiffusedProfile*>(&profile)) {
43 103719 k.profile.diffused = 1u;
44 103719 k.profile.diffusedExtent = static_cast<float>(0.5 * diffused->ReachRadii());
45 103719 k.profile.diffusedCells = static_cast<std::uint32_t>(diffused->Cells());
46 103719 k.profile.agesOffset = 0u;
47
1/1
✓ Branch 1 taken 103719 times.
103719 k.profile.ageCount = static_cast<std::uint32_t>(diffused->Ages().size());
48 103719 fresh = &diffused->Fresh();
49 }
50
3/4
✓ Branch 0 taken 1017039 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100803 times.
✓ Branch 3 taken 916236 times.
1017039 if (const auto* complex = dynamic_cast<const ComplexCraterProfile*>(fresh)) {
51 100803 const ComplexCraterShape& shape = complex->Shape();
52
2/2
✓ Branch 1 taken 33600 times.
✓ Branch 2 taken 67203 times.
100803 const KilometrePowerLaw width = shape.peakDiameter ? *shape.peakDiameter : shape.peakVolume;
53 100803 k.profile.complex = 1u;
54 100803 k.profile.transitionDiameter = static_cast<float>(shape.transitionDiameter);
55 100803 k.profile.floorCoefficient = static_cast<float>(shape.floorDiameter.coefficient);
56 100803 k.profile.floorExponent = static_cast<float>(shape.floorDiameter.exponent);
57 100803 k.profile.peakHeightCoefficient = static_cast<float>(shape.peakHeight.coefficient);
58 100803 k.profile.peakHeightExponent = static_cast<float>(shape.peakHeight.exponent);
59 100803 k.profile.peakWidthCoefficient = static_cast<float>(width.coefficient);
60 100803 k.profile.peakWidthExponent = static_cast<float>(width.exponent);
61
2/2
✓ Branch 1 taken 33600 times.
✓ Branch 2 taken 67203 times.
100803 k.profile.peakFromVolume = shape.peakDiameter ? 0u : 1u;
62 100803 k.profile.peakFitMaxDiameter = static_cast<float>(shape.peakFitMaxDiameter);
63 100803 k.profile.ejectaExponent = static_cast<float>(shape.ejectaExponent);
64 100803 k.profile.complexReachRadii = static_cast<float>(shape.reachRadii);
65 100803 fresh = &complex->Simple();
66 }
67
3/4
✓ Branch 0 taken 1017039 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 294013 times.
✓ Branch 3 taken 723026 times.
1017039 if (const auto* ft = dynamic_cast<const FassettThomsonProfile*>(fresh)) {
68 294013 k.profile.simple = CraterProfileKind::FassettThomson;
69 294013 k.profile.rim = static_cast<std::uint32_t>(ft->Rim());
70
3/4
✓ Branch 0 taken 723026 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 152232 times.
✓ Branch 3 taken 570794 times.
723026 } else if (dynamic_cast<const MartinParkesDunstanProfile*>(fresh) != nullptr) {
71 152232 k.profile.simple = CraterProfileKind::MartinParkesDunstan;
72 } else {
73 570794 return std::nullopt;
74 }
75
1/1
✓ Branch 1 taken 446245 times.
446245 k.reachRadii = static_cast<float>(CraterReachRadii(profile, options));
76
1/1
✓ Branch 1 taken 446245 times.
446245 k.profileReachRadii = static_cast<float>(profile.ReachRadii());
77 446245 k.blendStart = static_cast<float>(options.blend.startRadii);
78 446245 k.blendEnd = static_cast<float>(options.blend.endRadii);
79 446245 k.blendShape = static_cast<std::uint32_t>(options.blend.shape);
80 446245 k.interiorReplacement = static_cast<float>(options.interiorReplacement);
81 446245 k.mantling = static_cast<float>(options.texture.mantling);
82 446245 k.ejectaReachRadii = static_cast<float>(options.texture.ejectaReachRadii);
83 446245 const RimSmoothing& rim = options.rimSmoothing;
84 446245 k.rimSigma = static_cast<float>(rim.sigmaRadii);
85 446245 k.rimInner = static_cast<float>(rim.innerRadii);
86 446245 k.rimOuter = static_cast<float>(rim.outerRadii);
87 446245 k.rimStrength = static_cast<float>(rim.strength);
88 446245 k.rimShape = static_cast<std::uint32_t>(rim.shape);
89 446245 const CraterNoise& noise = options.noise;
90 446245 k.noiseAmplitude = static_cast<float>(noise.amplitude);
91 446245 k.noiseWavelength = static_cast<float>(noise.wavelengthRadii);
92 446245 k.noiseOctaves = noise.octaves;
93 446245 k.noiseGain = static_cast<float>(noise.gain);
94 446245 k.noiseRimAmplitude = static_cast<float>(noise.rimAmplitude);
95 446245 k.noiseRimWavelength = static_cast<float>(noise.rimWavelengthRadii);
96 446245 k.noiseRimInner = static_cast<float>(noise.rimInnerRadii);
97 446245 k.noiseRimOuter = static_cast<float>(noise.rimOuterRadii);
98 446245 const CraterTexture& texture = options.texture;
99 446245 k.wallStreaks = static_cast<float>(texture.wallStreaks);
100 446245 k.wallStreakWidth = static_cast<float>(texture.wallStreakWidthRadii);
101 446245 k.ejecta = static_cast<float>(texture.ejecta);
102 446245 k.ejectaLineation = static_cast<float>(texture.ejectaLineationRadii);
103 446245 k.minFreshness = static_cast<float>(texture.minFreshness);
104 446245 return k;
105 }
106
107 448966 CraterKernelBatch MakeCraterKernelBatch(const CraterShapeKernel& kernel,
108 const CraterProfile& profile,
109 const std::vector<PreparedCrater>& prepared,
110 const std::vector<std::size_t>& craters,
111 const CraterApplyOptions& options) {
112 448966 CraterKernelBatch batch;
113
1/2
✓ Branch 0 taken 448966 times.
✗ Branch 1 not taken.
448966 const auto* diffused = dynamic_cast<const DiffusedProfile*>(&profile);
114
3/4
✓ Branch 0 taken 106024 times.
✓ Branch 1 taken 342942 times.
✓ Branch 2 taken 106024 times.
✗ Branch 3 not taken.
448966 if (kernel.profile.diffused == 1u && diffused != nullptr) {
115
3/3
✓ Branch 1 taken 106024 times.
✓ Branch 7 taken 17069864 times.
✓ Branch 8 taken 106024 times.
17175888 for (const double age : diffused->Ages()) {
116
1/1
✓ Branch 1 taken 17069864 times.
17069864 batch.data.push_back(static_cast<float>(age));
117 }
118 }
119 448966 std::map<const std::vector<float>*, std::uint32_t> tables;
120
1/1
✓ Branch 2 taken 448966 times.
448966 batch.records.reserve(craters.size());
121
2/2
✓ Branch 5 taken 2124273 times.
✓ Branch 6 taken 448965 times.
2573238 for (const std::size_t k : craters) {
122 2124273 const PreparedCrater& p = prepared[k];
123 2124273 const CraterState& state = p.state;
124 2124273 const double diameter = p.crater.diameter;
125
6/6
✓ Branch 0 taken 1775188 times.
✓ Branch 1 taken 349085 times.
✓ Branch 2 taken 173567 times.
✓ Branch 3 taken 1601621 times.
✓ Branch 4 taken 173567 times.
✓ Branch 5 taken 1950706 times.
3899461 if (kernel.profile.simple == CraterProfileKind::MartinParkesDunstan &&
126 1775188 ShapesSimply(kernel, diameter, state)) {
127 173567 const CraterMorphometry& shaped =
128
2/2
✓ Branch 0 taken 13559 times.
✓ Branch 1 taken 160008 times.
173567 kernel.profile.diffused == 1u ? state.fresh : state.current;
129
2/4
✓ Branch 0 taken 173567 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 173567 times.
✗ Branch 3 not taken.
173567 if (!(shaped.depthRatio > 0.0 && shaped.rimHeightRatio >= 0.0 &&
130
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 173566 times.
173567 shaped.rimHeightRatio <= state.fresh.rimHeightRatio)) {
131 throw std::invalid_argument("Crater state needs a positive depth and 0 <= rim "
132
1/1
✓ Branch 2 taken 1 time.
1 "height <= fresh rim height");
133 }
134 }
135 2124272 CraterRecord r;
136 2124272 r.diameter = static_cast<float>(diameter);
137 2124272 r.resolution = static_cast<float>(p.resolution);
138 2124272 r.freshDepth = static_cast<float>(state.fresh.depthRatio);
139 2124272 r.freshRim = static_cast<float>(state.fresh.rimHeightRatio);
140 2124272 r.currentDepth = static_cast<float>(state.current.depthRatio);
141 2124272 r.currentRim = static_cast<float>(state.current.rimHeightRatio);
142 2124272 r.diffusion = static_cast<float>(state.diffusion);
143 2124272 const CraterOutline& outline = p.outline;
144 2124272 r.ellipticity = static_cast<float>(outline.ellipticity);
145 2124272 r.heading = static_cast<float>(outline.heading);
146 2124272 r.firstHarmonic = static_cast<std::uint32_t>(outline.firstHarmonic);
147 2124272 r.harmonicCount = static_cast<std::uint32_t>(outline.amplitudes.size());
148 2124272 r.harmonicOffset = static_cast<std::uint32_t>(batch.data.size());
149
2/2
✓ Branch 1 taken 217008 times.
✓ Branch 2 taken 2124272 times.
2341280 for (std::size_t n = 0; n < outline.amplitudes.size(); ++n) {
150
1/1
✓ Branch 2 taken 217008 times.
217008 batch.data.push_back(static_cast<float>(outline.amplitudes[n]));
151
1/1
✓ Branch 2 taken 217008 times.
217008 batch.data.push_back(static_cast<float>(outline.phases[n]));
152 }
153 2124272 r.tableCount = static_cast<std::uint32_t>(outline.table.size());
154 2124272 r.tableOffset = static_cast<std::uint32_t>(batch.data.size());
155
2/2
✓ Branch 4 taken 2048000 times.
✓ Branch 5 taken 2124272 times.
4172272 for (const double deviation : outline.table) {
156
1/1
✓ Branch 1 taken 2048000 times.
2048000 batch.data.push_back(static_cast<float>(deviation));
157 }
158 2124272 r.markCount = static_cast<std::uint32_t>(outline.marks.size());
159 2124272 r.markOffset = static_cast<std::uint32_t>(batch.data.size());
160
2/2
✓ Branch 1 taken 4709 times.
✓ Branch 2 taken 2119563 times.
2124272 if (!outline.marks.empty()) {
161 4709 for (const double radii :
162
2/2
✓ Branch 2 taken 14127 times.
✓ Branch 3 taken 4709 times.
23545 {outline.marksInnerRadii, outline.marksOuterRadii, outline.marksFadeRadii}) {
163
1/1
✓ Branch 1 taken 14127 times.
14127 batch.data.push_back(static_cast<float>(radii));
164 }
165
2/2
✓ Branch 4 taken 211905 times.
✓ Branch 5 taken 4709 times.
216614 for (const double knot : outline.marks) {
166
1/1
✓ Branch 1 taken 211905 times.
211905 batch.data.push_back(static_cast<float>(knot));
167 }
168 }
169
5/6
✓ Branch 0 taken 1688254 times.
✓ Branch 1 taken 436018 times.
✓ Branch 2 taken 1688254 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1652167 times.
✓ Branch 5 taken 36087 times.
2124272 if (kernel.profile.diffused == 1u && diffused != nullptr && state.diffusion > 0.0) {
170 const std::shared_ptr<const std::vector<float>> table =
171
1/1
✓ Branch 1 taken 1652167 times.
1652167 diffused->HeightTable(state.fresh, diameter);
172 1652167 const auto [at, added] =
173
1/1
✓ Branch 3 taken 1652167 times.
1652167 tables.try_emplace(table.get(), static_cast<std::uint32_t>(batch.data.size()));
174
2/2
✓ Branch 0 taken 85822 times.
✓ Branch 1 taken 1566345 times.
1652167 if (added) {
175
1/1
✓ Branch 7 taken 85822 times.
85822 batch.data.insert(batch.data.end(), table->begin(), table->end());
176 }
177 1652167 r.diffusionOffset = at->second;
178 1652167 }
179
2/2
✓ Branch 1 taken 487853 times.
✓ Branch 2 taken 1636419 times.
2124272 if (p.datum) {
180 487853 r.hasDatum = 1u;
181 487853 r.datumA = static_cast<float>(p.datum->a);
182 487853 r.datumB = static_cast<float>(p.datum->b);
183 487853 r.datumC = static_cast<float>(p.datum->c);
184 }
185 2124272 r.shiftX = static_cast<float>(p.slope.shift.x);
186 2124272 r.shiftY = static_cast<float>(p.slope.shift.y);
187 2124272 r.upslopeX = static_cast<float>(p.slope.upslope.x);
188 2124272 r.upslopeY = static_cast<float>(p.slope.upslope.y);
189 2124272 r.noiseKey = CraterKey(p.crater, options.noise.seed);
190 2124272 r.textureKey = CraterKey(p.crater, options.texture.seed ^ 0x54455854u);
191
1/1
✓ Branch 1 taken 2124272 times.
2124272 batch.records.push_back(r);
192 }
193 897930 return batch;
194 448967 }
195
196 } // namespace terraingen
197