TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
24 / 24
100.0%
Branches:
29 / 50
58.0%
Functions:
2 / 2, 1 excl
100.0%

layers/craters/shaping/irregularity.h
Line Branch Exec Source
1 /// @file
2 /// @brief Irregular, non-circular crater outlines: elongation and rough rims.
3 #pragma once
4
5 #include "terraingen/layers/craters/crater.h"
6 #include "terraingen/layers/craters/generation/population.h"
7 #include "terraingen/random/value_distribution.h"
8 #include "terraingen/util/surface.h"
9
10 #include <cstdint>
11 #include <optional>
12 #include <vector>
13
14 namespace terraingen {
15
16 /// How rough crater rims are drawn.
17 enum class RimRoughnessModel {
18 /// Harmonics `minHarmonic` to `maxHarmonic` with amplitudes falling as k^-`spectralSlope`, of
19 /// RMS `roughness`: a simple, configurable spectrum.
20 PowerLaw,
21 /// The fitted rim crest spectra of fresh lunar craters of Du et al. (2024), scattered as
22 /// measured when `scatter`, tabulated at 1024 angles; outlines deviating by more than
23 /// `maxDeviation` radii are scaled down to it.
24 Du2024,
25 };
26
27 /// Which craters have irregular outlines and the distributions their shapes are drawn from,
28 /// per crater from its ID.
29 ///
30 /// The rim lies at R s(theta) and the whole profile is stretched by s; s is an area-preserving
31 /// ellipse for `elongatedShare` of selected craters, times 1 plus rim harmonics for `roughShare`.
32 struct CraterIrregularity {
33 39 bool enabled = false; ///< Off: every crater is round.
34 39 std::uint32_t seed = 0; ///< Varies the outlines.
35 /// The craters that can be irregular; manual craters are left round by default.
36 39 CraterSelection selection{.manual = false};
37
38 39 double roughShare = 1.0; ///< Share of selected craters with rough outlines.
39 39 RimRoughnessModel model = RimRoughnessModel::PowerLaw; ///< How rough rims are drawn.
40 39 bool scatter = true; ///< With `Du2024`, scatter each crater's spectrum as measured.
41 39 double maxDeviation = 0.3; ///< With `Du2024`, the largest deviation kept, in radii.
42 /// With `PowerLaw`, the outline's RMS deviation from a circle, in radii.
43 39 ValueDistribution roughness{ValueDistribution::Kind::Uniform, 0.01, 0.03};
44 /// With `PowerLaw`, the exponent amplitudes fall with: A_k ~ k^-slope.
45 39 ValueDistribution spectralSlope{ValueDistribution::Kind::Constant, 1.5};
46 39 int minHarmonic = 2; ///< With `PowerLaw`, the lowest harmonic.
47 39 int maxHarmonic = 12; ///< With `PowerLaw`, the highest harmonic.
48
49 39 double elongatedShare = 0.054; ///< Share of selected craters that are elliptical.
50 /// Long over short rim-to-rim diameter of elliptical craters; at least 1.
51 39 ValueDistribution ellipticity{ValueDistribution::Kind::Uniform, 1.1, 1.5};
52 /// Heading of the long axis, radians counter-clockwise from +x, spread by up to
53 /// `headingSpread` either way; unset for random headings.
54 39 std::optional<double> heading;
55 39 double headingSpread = 0.0; ///< Spread of `heading` either way, in radians.
56
57 /// Share of selected craters with radial marks: the wall's profile is read nearer to or
58 /// farther from the centre by a shift that varies smoothly around the crater, leaving ridges
59 /// and grooves down the wall that are strongest where it is steepest. No published
60 /// measurements of such marks are known, so the defaults are set by eye.
61 39 double marksShare = 0.0;
62 /// Largest shift of the marks, in radii, drawn per crater; each knot is uniform within it.
63 39 ValueDistribution marksAmplitude{ValueDistribution::Kind::Uniform, 0.0, 0.005};
64 39 int marksKnots = 45; ///< Random shifts around the crater the marks pass through smoothly.
65 39 double marksInnerRadii = 0.3; ///< Where the marks reach full strength going out, in radii.
66 39 double marksOuterRadii = 0.9; ///< Where the marks start to fade going out, in radii.
67 39 double marksFadeRadii = 0.1; ///< Width of the fades either side, in radii.
68
69
21/42
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 39 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 39 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 39 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 39 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 39 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 39 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 39 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 39 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 39 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 39 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 39 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 39 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 39 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 39 times.
✗ Branch 40 not taken.
✓ Branch 41 taken 39 times.
✗ Branch 42 not taken.
✓ Branch 43 taken 39 times.
✗ Branch 44 not taken.
✓ Branch 45 taken 39 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 39 times.
39 bool operator==(const CraterIrregularity&) const = default;
70 };
71
72 /// Checks irregularity settings.
73 /// @throws std::invalid_argument for invalid distributions or selection, shares outside [0, 1],
74 /// harmonics outside 1 <= min <= max <= 64, a roughness that could fold the rim (its highest value
75 /// times sqrt(2 n), n harmonics, at least 0.5), an ellipticity below 1, a non-finite heading or a
76 /// negative or non-finite spread, a `maxDeviation` outside (0, 0.5], fewer than 3 or more than
77 /// 1024 mark knots, a mark window that is not 0 <= inner - fade, inner <= outer and outer + fade
78 /// <= 1 with a positive fade, or a mark amplitude that is negative or large enough to fold the
79 /// wall (at least fade / 3.75).
80 void ValidateCraterIrregularity(const CraterIrregularity& irregularity);
81
82 /// One crater's outline: the factor its rim radius and profile are stretched by in each
83 /// direction.
84 struct CraterOutline {
85 double ellipticity = 1.0; ///< Long over short axis; 1 for none.
86 double heading = 0.0; ///< Long axis, radians counter-clockwise from +x.
87 std::vector<double> amplitudes; ///< A_k from k = `firstHarmonic`.
88 std::vector<double> phases; ///< phi_k, in step with `amplitudes`.
89 int firstHarmonic = 2; ///< The harmonic of `amplitudes[0]`.
90 /// The rim's deviation from a circle at angles 2 pi n / size, interpolated linearly, in place
91 /// of `amplitudes` when not empty.
92 std::vector<double> table;
93 /// Radial shifts of the wall, in radii, at angles 2 pi n / size, passed through by a periodic
94 /// Catmull-Rom spline; empty for no marks.
95 std::vector<double> marks;
96 double marksInnerRadii = 0.3; ///< Where the marks reach full strength, in radii.
97 double marksOuterRadii = 0.9; ///< Where the marks start to fade, in radii.
98 double marksFadeRadii = 0.1; ///< Width of the fades, in radii.
99
100 /// The factor the rim radius is stretched by toward (`dx`, `dy`) metres east and north of the
101 /// centre; 1 for a round crater.
102 double Scale(double dx, double dy) const;
103
104 /// The shift in radii the marks add at `radii` from the centre toward (`dx`, `dy`); 0 outside
105 /// the marks' window, which ends inside the rim.
106 double MarkShift(double dx, double dy, double radii) const;
107
108 /// An upper bound of `Scale` in any direction.
109 double MaxScale() const;
110
111 /// Whether the outline is a circle: no ellipticity, harmonics, table or marks.
112 13050373 bool Round() const {
113
8/8
✓ Branch 0 taken 10877907 times.
✓ Branch 1 taken 2172466 times.
✓ Branch 3 taken 10300005 times.
✓ Branch 4 taken 577902 times.
✓ Branch 6 taken 10300003 times.
✓ Branch 7 taken 2 times.
✓ Branch 9 taken 10223072 times.
✓ Branch 10 taken 76931 times.
13050373 return ellipticity == 1.0 && amplitudes.empty() && table.empty() && marks.empty();
114 }
115 };
116
117 /// The outline `irregularity` gives a crater, seeded by its ID; round unless irregularity is
118 /// enabled and the crater selected.
119 CraterOutline OutlineOf(const Crater& crater, const CraterIrregularity& irregularity);
120
121 /// The largest stretch any crater's outline can have, to widen footprints by; 1 when disabled.
122 double MaxOutlineScale(const CraterIrregularity& irregularity);
123
124 /// The distance in metres at which a crater's round profile is read at surface (x, y): the true
125 /// distance over the stretch of its `outline` (`OutlineOf`) in that direction, shifted by its
126 /// marks.
127 double CraterProfileDistance(const Crater& crater, const CraterOutline& outline, double x, double y,
128 const Surface& surface = {});
129
130 /// `CraterProfileDistance` for a point `offset` metres east and north of the crater's centre in
131 /// its local frame.
132 double CraterProfileDistance(const Crater& crater, const CraterOutline& outline,
133 const Vec2d& offset);
134
135 } // namespace terraingen
136