TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
9 / 12
75.0%
Branches:
3 / 6
50.0%
Functions:
4 / 4, 1 excl
100.0%

layers/craters/generation/population.h
Line Branch Exec Source
1 /// @file
2 /// @brief Generating crater populations cell by cell, in size bands.
3 #pragma once
4
5 #include "terraingen/distribution/size_frequency.h"
6 #include "terraingen/layers/craters/ages/age_model.h"
7 #include "terraingen/layers/craters/crater.h"
8 #include "terraingen/sources/field.h"
9 #include "terraingen/util/cells.h"
10 #include "terraingen/util/surface.h"
11
12 #include <cstddef>
13 #include <cstdint>
14 #include <functional>
15 #include <limits>
16 #include <memory>
17 #include <string>
18 #include <vector>
19
20 namespace terraingen {
21
22 /// Keeps craters of similar size apart: two conflict when their diameters differ by at most
23 /// `diameterRatio` and their centres are closer than `separation` times the larger diameter.
24 struct CraterSpacing {
25 114806 CraterSpacing() = default;
26 /// Spacing with `diameterRatio` `ratio` and `separation` `minSeparation`.
27 22 CraterSpacing(double ratio, double minSeparation)
28 22 : diameterRatio(ratio), separation(minSeparation) {}
29
30 39 double diameterRatio = 1.5; ///< At least 1.
31 39 double separation = 0.0; ///< In larger diameters; 0 disables spacing.
32 /// Craters at least this large (m) take precedence over smaller ones whatever their ages, as a
33 /// crater layer sets for the craters that throw secondaries a total map measures; infinite
34 /// ranks by age first. Not part of a configuration.
35 39 double outrankFrom = std::numeric_limits<double>::infinity();
36
37 /// Whether spacing applies: a positive `separation`.
38 6360355 bool Enabled() const {
39 6360355 return separation > 0.0;
40 }
41
42
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
39 bool operator==(const CraterSpacing&) const = default;
43 };
44
45 /// A size band of crater generation: diameters [`low`, `high`) metres, from 2^`exponent` to
46 /// 2^(`exponent` + 1) clipped to the requested range.
47 struct CraterBand {
48 int exponent = 0; ///< The band's power of two.
49 double low = 0.0; ///< Smallest diameter (m).
50 double high = 0.0; ///< Largest diameter (m), exclusive.
51 double cellSize = 0.0; ///< Side of the cells the band is drawn in (m).
52
53 bool operator==(const CraterBand&) const = default;
54 };
55
56 /// The bands `GenerateCraters` uses to cover [`dMin`, `dMax`) metres, smallest first.
57 /// @param cellSizeFactor Cell side over each band's largest whole diameter.
58 std::vector<CraterBand> CraterBands(double dMin, double dMax, double cellSizeFactor);
59
60 /// The craters `GenerateCraters` draws in one cell of one band, in the order drawn, before
61 /// regions, manual craters, spacing and caps apply.
62 CraterList GenerateCellCraters(const SurfaceCells& cells, const CraterBand& band,
63 const CellIndex& cell, const SizeFrequencyDistribution& density,
64 const CraterAgeModel& ages, std::uint32_t seed);
65
66 /// Supplies the craters of one cell of one band as `GenerateCellCraters` would, for example from
67 /// a cache; must be thread-safe.
68 using CellCraterSource =
69 std::function<std::shared_ptr<const CraterList>(const CraterBand& band, const CellIndex& cell)>;
70
71 /// The share of generated craters like `crater` that `GenerateCraters` keeps, in [0, 1].
72 using CraterKeepShare = std::function<double(const Crater& crater)>;
73
74 /// Which craters `GenerateCraters` draws, and how.
75 struct CraterGenerationOptions {
76 /// Smallest diameter generated, in metres; must be set to a positive value.
77 double dMin = 0.0;
78 /// Largest diameter (m), exclusive; infinity means the top of the density's valid range, which
79 /// must then be finite.
80 double dMax = std::numeric_limits<double>::infinity();
81 /// Also keep craters centred outside the region within this many radii of it.
82 double marginRadii = 0.0;
83 /// Cell side as a multiple of each band's largest diameter.
84 double cellSizeFactor = 16.0;
85 /// Upper limit on the expected number of craters, to catch requests that would exhaust memory.
86 double maxExpectedCraters = 5e7;
87 /// Removes conflicting craters (`SpacingConflicts`); disabled by default, since it lowers the
88 /// density below `density`.
89 CraterSpacing spacing{};
90 /// Manual craters to merge in: those within the region and margin follow the generated craters,
91 /// flagged and given IDs as `AppendManualCraters` does; with spacing, they remove conflicting
92 /// generated craters.
93 CraterList manual{};
94 /// Keep at most this many generated craters, the largest (ties to the smaller ID); 0 keeps
95 /// all. Manual craters are always kept and do not count. A capped region no longer equals its
96 /// tiles joined; `MinDiameterForCount` bounds counts tile-safely.
97 std::size_t maxCraters = 0;
98 /// Skip bands whose craters are all smaller than this (m) and, with spacing, too small to
99 /// remove a crater this large; craters at or above it are unchanged. 0 generates every band.
100 double minResolvedDiameter = 0.0;
101 /// Skip bands whose craters are all larger than this (m), unless spacing or `maxCraters` is on,
102 /// where larger craters change which smaller ones are kept; craters at or below it are
103 /// unchanged. Infinity generates every band.
104 double maxBandDiameter = std::numeric_limits<double>::infinity();
105 /// Where each cell's craters come from; empty draws them with `GenerateCellCraters`.
106 CellCraterSource cellCraters{};
107 /// The share of generated craters like each one kept, in [0, 1], from its position and size:
108 /// drawing at the density's highest local level and keeping each crater with its share, by a
109 /// uniform keyed to its ID, makes the density vary over the surface. Must be thread-safe and
110 /// depend only on the crater; unset keeps every crater.
111 CraterKeepShare keepShare{};
112 /// The diameter (m) from which `manual` craters are a complete catalog at each point: generated
113 /// craters at least this large centred there are dropped, so the catalog stands in for them
114 /// rather than adding to them. Infinite or NaN where there is no catalog; unset keeps every
115 /// generated crater.
116 std::shared_ptr<const SurfaceField> completeness{};
117 /// What the region and margins are measured on: on a sphere, regions are longitude and
118 /// latitude boxes and margins are metres, and `cells` must be `CubeSphereCells` of its radius.
119 Surface surface{};
120 /// What the drawn features are called in the log: its category and the noun of its counts.
121 std::string logName = "craters";
122 };
123
124 /// The largest diameter generated in metres: `dMax`, or for an infinite `dMax` the top of the
125 /// density's valid range; infinite when both are unbounded.
126 double ResolveDMax(double dMax, const SizeFrequencyDistribution& density);
127
128 /// The smallest diameter in [`dMin`, `dMax`) metres from which `density` expects about `count`
129 /// craters over `area` m^2, found by bisection in log diameter; `dMin` if even that expects fewer.
130 ///
131 /// Raising `dMin` to it bounds the count while keeping the distribution's shape and tile joins.
132 /// @throws std::invalid_argument unless `count` and `area` are positive and finite and
133 /// 0 < `dMin` < `dMax`.
134 /// @throws std::domain_error if the interval leaves the density's valid range.
135 double MinDiameterForCount(const SizeFrequencyDistribution& density, double area, double count,
136 double dMin, double dMax);
137
138 /// Generates the craters of a density whose centres lie in `region` (surface coordinates) or
139 /// within `marginRadii` radii of it.
140 ///
141 /// Craters are drawn per cell of each size band from substreams keyed by (`seed`, band, cell), so
142 /// tiles join exactly, `dMin` and `dMax` do not move craters in whole bands, and the age model
143 /// never moves a crater. Order: band, cell, index.
144 /// @param density A `Density` distribution valid over [`dMin`, `dMax`), or extrapolating.
145 /// @throws std::invalid_argument for invalid options, an empty or non-finite region, a density that
146 /// is not a `Density`, or an expected count above `maxExpectedCraters`.
147 /// @throws std::domain_error if the diameter interval leaves the density's valid range.
148 CraterList GenerateCraters(const SurfaceCells& cells, const Bounds2d& region,
149 const SizeFrequencyDistribution& density, const CraterAgeModel& ages,
150 std::uint32_t seed, const CraterGenerationOptions& options);
151
152 } // namespace terraingen
153