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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 |