TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
81 / 81
100.0%
Branches:
73 / 146
50.0%
Functions:
8 / 8, 1 excl
100.0%

albedo/crater_albedo.h
Line Branch Exec Source
1 /// @file
2 /// @brief Bright, immature ejecta, interiors and rays around fresh craters.
3 #pragma once
4
5 #include "terraingen/albedo/albedo.h"
6 #include "terraingen/albedo/maturity.h"
7 #include "terraingen/layers/craters/crater.h"
8 #include "terraingen/layers/craters/crater_layer.h"
9 #include "terraingen/layers/craters/rays.h"
10 #include "terraingen/layers/craters/shaping/irregularity.h"
11 #include "terraingen/layers/fade.h"
12 #include "terraingen/random/value_distribution.h"
13
14 #include <cstdint>
15 #include <memory>
16 #include <optional>
17 #include <vector>
18
19 namespace terraingen {
20
21 /// How long a crater keeps its immature, bright material, by diameter, after Werner and
22 /// Medvedev (2010): `smallMyr` up to `smallDiameter`, a power law of diameter up to `midDiameter`,
23 /// `midMyr` up to `largeDiameter` and `largeMyr` beyond, every time multiplied by `scale`.
24 struct RayRetention {
25 3 double smallDiameter = 1000.0; ///< At or below this diameter (m), `smallMyr`.
26 3 double smallMyr = 5.0; ///< Retention of small craters, Myr.
27 3 double midDiameter = 5000.0; ///< From this diameter (m) to `largeDiameter`, `midMyr`.
28 3 double midMyr = 750.0; ///< Retention of mid-sized craters, Myr.
29 3 double largeDiameter = 50000.0; ///< Above this diameter (m), `largeMyr`.
30 3 double largeMyr = 750.0; ///< Retention of large craters, Myr.
31 3 double scale = 1.0; ///< Multiplies every time.
32
33 /// The retention time in Myr of a crater `diameter` metres across.
34 double Myr(double diameter) const;
35
36
7/14
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
3 bool operator==(const RayRetention&) const = default;
37 };
38
39 /// Checks ray retention settings.
40 /// @throws std::invalid_argument unless the diameters are positive and increasing and the times
41 /// and scale positive, all finite.
42 void ValidateRayRetention(const RayRetention& retention);
43
44 /// How oblique impacts shape a crater's rays. Each crater gets an impact angle from the
45 /// horizontal with P(< theta) = sin^2 theta and a downrange direction, `heading` or uniform at
46 /// random.
47 struct ObliqueImpacts {
48 3 bool enabled = true; ///< Whether impacts can be oblique; otherwise all vertical.
49 3 std::optional<double> heading; ///< Downrange, radians counter-clockwise from east.
50 3 double asymmetricDegrees = 45.0; ///< Below this angle rays are longer downrange.
51 3 double forbiddenDegrees = 25.0; ///< Below this angle rays near uprange are dropped.
52 3 double butterflyDegrees = 10.0; ///< Below this angle rays near downrange are dropped too.
53 /// Downrange over uprange ejection speed, at least 1.
54 3 ValueDistribution downrangeSpeedRatio{ValueDistribution::Kind::Uniform, 1.2, 1.4};
55 3 double zoneHalfWidthDegrees = 45.0; ///< Half width of a forbidden zone, in [0, 180].
56
57 /// The most a ray's length can be multiplied by: (1 + a)^2 / (1 + a^2 / 2) for the highest
58 /// speed ratio's asymmetry a; 1 when disabled.
59 double MaxStretch() const;
60
61
7/14
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
3 bool operator==(const ObliqueImpacts&) const = default;
62 };
63
64 /// The impact that formed a crater, as `ObliqueImpacts` draws it.
65 struct CraterImpact {
66 double angleDegrees = 90.0; ///< From the horizontal.
67 double heading = 0.0; ///< Downrange, radians counter-clockwise from east.
68 double speedRatio = 1.0; ///< Downrange over uprange ejection speed.
69 };
70
71 /// Checks oblique impact settings.
72 /// @throws std::invalid_argument for an invalid speed ratio distribution or one that can be below
73 /// 1, angles outside [0, 90] or out of order (butterfly <= forbidden <= asymmetric), a zone half
74 /// width outside [0, 180], or a heading that is not finite.
75 void ValidateObliqueImpacts(const ObliqueImpacts& oblique);
76
77 /// The rays of a crater: narrow streaks of immature material running out from the rim,
78 /// after Elliott et al. (2018), at uniform azimuths, fading linearly to their ends and broken by
79 /// value noise.
80 struct CraterRays {
81 3 bool enabled = true; ///< Whether craters have rays.
82 /// Rays per crater, 0 to 64.
83 3 ValueDistribution count{ValueDistribution::Kind::Normal, 10.7, 3.1, 6.0, 20.0};
84 3 double lengthCoefficient = 6.59; ///< Coefficient of `ElliottMedianRayLength`.
85 3 double lengthExponent = 1.27; ///< Exponent of `ElliottMedianRayLength`.
86 /// Natural log of a ray's length over the median.
87 3 ValueDistribution lengthSpread{ValueDistribution::Kind::Uniform, -0.356, 0.468};
88 /// Angular width 2 radii from the centre, in (0, 180) degrees; the width there holds beyond.
89 3 ValueDistribution widthDegrees{ValueDistribution::Kind::Normal, 22.0, 8.3, 5.4, 38.6};
90 3 double excess = 0.048; ///< Maturity excess at the rim, in OMAT; >= 0.
91 3 double patchiness = 0.5; ///< Most of the excess the noise takes away, in [0, 1].
92 3 double patchRadii = 0.5; ///< Noise wavelength, in crater radii; positive.
93 3 ObliqueImpacts oblique{}; ///< How oblique impacts shape the rays.
94 /// Takes the rays' number, directions and widths from this layout (`RayDirections`) in place
95 /// of `count` and `widthDegrees`, so they lie over secondaries with the same layout; unset
96 /// draws them per crater as before.
97 3 std::optional<RayLayout> layout;
98
99 /// The median ray length from the centre, in metres, of a crater `diameter` metres across.
100 double MedianLength(double diameter) const;
101
102
11/22
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 3 times.
3 bool operator==(const CraterRays&) const = default;
103 };
104
105 /// Checks ray settings.
106 /// @throws std::invalid_argument for invalid distributions, a count that can be below 0 or above
107 /// 64, widths outside (0, 180) degrees, a non-positive coefficient or exponent, a negative excess,
108 /// a patchiness outside [0, 1], a non-positive patch wavelength or an invalid layout.
109 void ValidateCraterRays(const CraterRays& rays);
110
111 /// The texture of fresh craters' bright material, keyed to each crater and off by default: radial
112 /// streaks breaking ejecta, rays, interiors and the bright proximal reflectance zone into
113 /// filaments, a lobed ejecta edge, and walls brighter than floors.
114 struct CraterAlbedoTexture {
115 /// Share of the excess the radial streaks take away between filaments, in [0, 1]; 0 for none.
116 3 double streaks = 0.0;
117 3 double streakWidthDegrees = 3.0; ///< Typical width of a filament around the crater; positive.
118 3 double streakLengthRadii = 1.5; ///< Typical length of a filament outward, in radii; positive.
119 /// How far beyond the rim the ejecta stay continuous before breaking into filaments, in radii;
120 /// the streaks ramp in over that distance, and 0 streaks them from the rim.
121 3 double continuousRadii = 0.0;
122 /// How far the ejecta's edge wanders in and out, as a share of its reach, in [0, 0.9]; 0 keeps
123 /// it circular.
124 3 double lobes = 0.0;
125 3 int lobeCount = 8; ///< Typical number of lobes around a crater, 1 to 64.
126 3 double floorShare = 1.0; ///< Interior excess on the floor over that at the rim, in [0, 1].
127 3 std::uint32_t seed = 0; ///< Varies every crater's texture.
128
129
8/16
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
3 bool operator==(const CraterAlbedoTexture&) const = default;
130 };
131
132 /// Checks crater albedo texture settings.
133 /// @throws std::invalid_argument for streaks or a floor share outside [0, 1], lobes outside
134 /// [0, 0.9], a lobe count outside 1 to 64, a non-positive streak width or length, or a
135 /// negative continuous reach.
136 void ValidateCraterAlbedoTexture(const CraterAlbedoTexture& texture);
137
138 /// One reflectance zone around new small craters: a share of craters has it, it changes the
139 /// reflectance relative to the pre-impact surface by `change`, and it reaches
140 /// `coefficient` D^`exponent` metres from the centre times `scale`, both drawn per crater, with
141 /// a ragged edge of fingers pulled in by up to `raggedness` of the reach, lasting `retentionMyr`.
142 struct ReflectanceZone {
143 12 double share = 1.0; ///< Share of craters with the zone, in [0, 1].
144 12 ValueDistribution change{}; ///< Relative reflectance change, above -1.
145 12 double coefficient = 1.0; ///< Reach law coefficient, m; positive.
146 12 double exponent = 1.0; ///< Reach law exponent; positive.
147 12 ValueDistribution scale{}; ///< Reach multiplier; positive and bounded.
148 12 double raggedness = 0.0; ///< Reach fingers pull in, in [0, 1).
149 12 double fingerWidthDegrees = 10.0; ///< Typical finger width; positive.
150 12 double feather = 0.3; ///< Share of the reach fading out, in (0, 1].
151 /// How long the zone lasts (Myr), fading like the bright material; unset lasts as long as the
152 /// bright material, and a zone outlasting it ends with it.
153 12 std::optional<double> retentionMyr;
154
155
9/18
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 12 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 12 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 12 times.
12 bool operator==(const ReflectanceZone&) const = default;
156 };
157
158 /// Checks a reflectance zone.
159 /// @throws std::invalid_argument for a share outside [0, 1], an invalid change that can reach -1,
160 /// a non-positive coefficient or exponent, a scale that can be non-positive or unbounded, a
161 /// raggedness outside [0, 1), a non-positive finger width, a feather outside (0, 1] or a
162 /// non-positive retention time.
163 void ValidateReflectanceZone(const ReflectanceZone& zone);
164
165 /// Topographic shadows in the distal reflectance zones, which form along the surface: rises such
166 /// as crater rims leave the ground behind them untouched (Speyerer et al. 2016). A jet runs out
167 /// along the ground from the rim and cannot drop faster than `jetAngleDegrees`; where the ground
168 /// lies below it the distal zones fade, gone `depth` metres below. The ground is sampled per
169 /// crater on `azimuths` rays of `radialSamples` samples. The angle and depth are illustrative,
170 /// as the sources do not measure them.
171 struct ZoneShadows {
172 3 bool enabled = false; ///< Whether the distal zones have shadows; needs the ground.
173 3 double jetAngleDegrees = 3.0; ///< Steepest descent of the jet, in (0, 90) degrees.
174 3 double depth = 0.5; ///< Depth below the jet of full shadow (m); positive.
175 3 int azimuths = 720; ///< Rays around a crater, 8 to 8192.
176 3 int radialSamples = 400; ///< Samples along a ray, 8 to 8192.
177
178
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
3 bool operator==(const ZoneShadows&) const = default;
179 };
180
181 /// The four reflectance zones around new small craters seen in LROC temporal pairs, after
182 /// Robinson et al. (2015) and Speyerer et al. (2016), off by default. Proximal high (PHRZ) only
183 /// where the crater excavates below the mature regolith, inside proximal low (PLRZ), inside
184 /// distal high (DHRZ) and distal low (DLRZ) in order of reach; inner zones cover outer ones.
185 /// The changes multiply the albedo after the maturity excess. The distal zones and the thin low
186 /// reflectance ejecta live in the top centimetres, which secondaries churn in 8.1e4 years
187 /// (Speyerer et al. 2016), and last that long; the bright, immature PHRZ fades with the bright
188 /// material.
189 struct CraterReflectanceZones {
190 3 bool enabled = false; ///< Whether craters get the zones.
191 3 double maxDiameter = 50.0; ///< Largest crater with zones (m); the fits stop near 43 m.
192 3 double matureDepth = 1.0; ///< Depth of mature regolith (m); not negative.
193 3 double excavationRatio = 0.1; ///< Excavation depth over diameter; positive.
194 /// PHRZ: +12% +/- 9% to a median 1.5 D (mean 2.1 D) from the centre.
195 3 ReflectanceZone proximalHigh{1.0,
196 {ValueDistribution::Kind::Normal, 0.12, 0.09, 0.01, 0.5},
197 1.5,
198 1.0,
199 {ValueDistribution::Kind::LogNormal, 1.0, 0.82, 0.4, 5.0},
200 0.3,
201 25.0,
202 0.3,
203 {}};
204 /// PLRZ: -9% +/- 4%, in nearly all craters, to a median 2.9 D (mean 3.2 D); lasting as long as
205 /// the top centimetres is an inference from Robinson et al.'s (2015) discussion.
206 3 ReflectanceZone proximalLow{1.0,
207 {ValueDistribution::Kind::Normal, -0.09, 0.04, -0.2, -0.01},
208 2.9,
209 1.0,
210 {ValueDistribution::Kind::LogNormal, 1.0, 0.44, 0.5, 3.0},
211 0.3,
212 20.0,
213 0.3,
214 0.081};
215 /// DHRZ: +1% to +4% in 24% of craters, to 0.52 D^2.5 m.
216 3 ReflectanceZone distalHigh{0.24,
217 {ValueDistribution::Kind::Uniform, 0.01, 0.04},
218 0.52,
219 2.5,
220 {ValueDistribution::Kind::Constant, 1.0},
221 0.5,
222 8.0,
223 0.4,
224 0.081};
225 /// DLRZ: -2% to -6% in 84% of craters, ray-like, to 5.03 D^2 m.
226 3 ReflectanceZone distalLow{0.84,
227 {ValueDistribution::Kind::Uniform, -0.06, -0.02},
228 5.03,
229 2.0,
230 {ValueDistribution::Kind::Constant, 1.0},
231 0.6,
232 8.0,
233 0.6,
234 0.081};
235 3 ZoneShadows shadows{}; ///< Shadows of rises in the distal zones; off by default.
236 3 std::uint32_t seed = 0; ///< Varies every crater's zones.
237
238 /// The farthest any zone reaches from the centre of a crater `diameter` metres across.
239 double MaxReach(double diameter) const;
240
241
10/20
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 3 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 3 times.
3 bool operator==(const CraterReflectanceZones&) const = default;
242 };
243
244 /// Checks crater reflectance zones.
245 /// @throws std::invalid_argument for an invalid zone, a non-positive largest diameter or
246 /// excavation ratio, a negative mature depth, or shadows with a jet angle outside (0, 90), a
247 /// non-positive depth, or sample counts outside 8 to 8192.
248 void ValidateCraterReflectanceZones(const CraterReflectanceZones& zones);
249
250 /// The bright material of fresh craters, in optical maturity (OMAT) over the background's:
251 /// an interior excess, ejecta falling as a power of distance, and rays. Excesses fade with age
252 /// over the retention time, add over overlapping craters and are capped; the albedo then moves
253 /// with maturity (`ReflectanceAtMaturity`). The defaults are Tycho's.
254 struct CraterAlbedoOptions {
255 3 std::uint32_t seed = 0; ///< Seed of the per-crater draws.
256 /// The craters with bright material at all.
257 3 CraterSelection selection{};
258 3 double share = 1.0; ///< Share of selected craters with bright material.
259
260 3 double backgroundMaturity = 0.202; ///< OMAT of the background; positive.
261 3 double maxMaturity = 0.42; ///< Cap on OMAT; >= `backgroundMaturity`.
262 3 double interiorExcess = 0.132; ///< Excess inside the rim.
263 3 double ejectaExcess = 0.076; ///< Excess of the ejecta at the rim.
264 3 double ejectaExponent = 3.0; ///< The ejecta excess falls as (r / R)^-this.
265 3 double ejectaReachRadii = 3.0; ///< Where the ejecta excess reaches 0, in radii; > 1.
266 3 CraterRays rays{}; ///< The rays.
267 3 CraterAlbedoTexture texture{}; ///< Filaments, lobes and wall brightness; off by default.
268 3 CraterReflectanceZones zones{}; ///< Zones around new small craters; off by default.
269 3 RayRetention retention{}; ///< Retention time T by diameter.
270 3 double fadeExponent = 1.0; ///< Excesses fade as max(0, 1 - t / T)^this.
271 /// Reflectance of the optical maturity origin (`ReflectanceAtMaturity`).
272 3 double originReflectance = OpticalMaturityOrigin{}.reflectance;
273 3 ResolutionFade fade{}; ///< How craters too small to resolve fade out.
274
275
16/32
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 3 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 3 times.
✗ Branch 26 not taken.
✓ Branch 27 taken 3 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 3 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 3 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 3 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 3 times.
3 bool operator==(const CraterAlbedoOptions&) const = default;
276 };
277
278 /// Checks crater albedo options.
279 /// @throws std::invalid_argument for invalid rays, retention, fade or selection, a share outside
280 /// [0, 1], a background maturity that is not positive or a cap below it, negative excesses, a
281 /// non-positive ejecta exponent, a reach of 1 radius or less, or a non-positive fade exponent.
282 void ValidateCraterAlbedo(const CraterAlbedoOptions& options);
283
284 /// The bright ejecta, interiors and rays of the craters of a `CraterLayer`, as
285 /// `CraterAlbedoOptions` describes, shaped by the craters' irregular outlines where the layer has
286 /// them. The craters come from the layer for the region being evaluated, widened by the longest
287 /// ray, so every grid, tile and point agrees; excesses are summed in crater ID order.
288 class CraterAlbedo final : public AlbedoLayer {
289 public:
290 /// The bright material of the craters of `craters`.
291 /// @throws std::invalid_argument for a null layer or options invalid as `ValidateCraterAlbedo`.
292 CraterAlbedo(std::shared_ptr<const CraterLayer> craters, CraterAlbedoOptions options = {});
293
294 /// Brightens the albedo at one point by the craters' summed excess; NaN stays NaN.
295 void ApplyAt(AlbedoSample& value, std::size_t bands, double x, double y,
296 const AlbedoContext& context) const override;
297
298 /// `ApplyAt` at every cell centre, gathering craters once per block of rows.
299 void Apply(std::vector<Raster<float>>& bands, const AlbedoContext& context) const override;
300
301 /// The excess optical maturity (OMAT) `crater` gives surface point (`x`, `y`) at a sample
302 /// spacing of `spacing` metres.
303 double Excess(const Crater& crater, double x, double y, double spacing) const;
304
305 /// The relative reflectance change the zones of `crater` give surface point (`x`, `y`) at a
306 /// sample spacing of `spacing` metres; 0 without zones. Shadows need `ground`.
307 double ReflectanceChange(const Crater& crater, double x, double y, double spacing,
308 const Ground* ground = nullptr) const;
309
310 /// The impact `crater` came from, drawn from its ID; vertical without oblique impacts.
311 CraterImpact Impact(const Crater& crater) const;
312
313 /// How far from its centre `crater` can brighten the ground: the farthest of its ejecta and
314 /// its rays, in metres; 0 without bright material.
315 double Reach(const Crater& crater) const;
316
317 /// How bright, and for how long.
318 const CraterAlbedoOptions& Options() const {
319 return options_;
320 }
321
322 private:
323 struct Ray;
324 struct Prepared;
325 Prepared Prepare(const Crater& crater, double spacing) const;
326 /// Whether `crater` is selected and drawn to have bright material, from the next uniform of
327 /// `random`.
328 bool Eligible(const Crater& crater, RandomStream& random) const;
329 /// The next ray of `random`, for a crater of median ray length `median` formed by `impact`.
330 Ray DrawRay(RandomStream& random, double median, const CraterImpact& impact,
331 const RayDirection* direction) const;
332 /// Draws the rays of `prepared`, widening its reach to the longest.
333 void AddRays(Prepared& prepared, RandomStream& random) const;
334 /// Draws the reflectance zones of `prepared`, widening its reach to the farthest, for a crater
335 /// with `left` of its bright material's life and a resolution weight of `resolution`.
336 void AddZones(Prepared& prepared, double left, double resolution) const;
337 /// Samples the ground around `prepared` for the shadows of its distal zones over `region`.
338 void AddShadows(Prepared& prepared, const Ground& ground, const Bounds2d& region) const;
339 std::vector<Prepared> Gather(const Bounds2d& region, double spacing,
340 const Ground* ground) const;
341
342 std::shared_ptr<const CraterLayer> craters_;
343 CraterAlbedoOptions options_;
344 };
345
346 } // namespace terraingen
347