layers/craters/shaping/apply_options.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief How craters are applied to the terrain: their order, datum, blend, outlines and rims. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/layers/craters/generation/population.h" | ||
| 6 | #include "terraingen/layers/craters/shaping/irregularity.h" | ||
| 7 | #include "terraingen/layers/craters/shaping/slope.h" | ||
| 8 | #include "terraingen/layers/fade.h" | ||
| 9 | #include "terraingen/util/surface.h" | ||
| 10 | |||
| 11 | #include <cstddef> | ||
| 12 | #include <cstdint> | ||
| 13 | #include <vector> | ||
| 14 | |||
| 15 | namespace terraingen { | ||
| 16 | |||
| 17 | /// The order in which overlapping craters are applied; later craters overprint earlier ones. | ||
| 18 | enum class CraterOrder { | ||
| 19 | OldestFirst, ///< Decreasing age, then decreasing diameter: the physical order. | ||
| 20 | LargestFirst, ///< Decreasing diameter, then decreasing age. | ||
| 21 | }; | ||
| 22 | |||
| 23 | /// The reference surface a crater's interior is cut relative to. | ||
| 24 | enum class CraterDatum { | ||
| 25 | None, ///< No datum: the profile is added onto the terrain everywhere. | ||
| 26 | Plane, ///< Least-squares plane over the fit footprint; keeps regional slopes. | ||
| 27 | MeanHeight, ///< Flat datum at the mean height over the fit footprint. | ||
| 28 | CentreHeight, ///< Flat datum at the terrain height under the crater centre. | ||
| 29 | }; | ||
| 30 | |||
| 31 | /// Where a crater's replaced interior blends into the surrounding terrain, in crater radii. | ||
| 32 | struct CraterBlend { | ||
| 33 | 39 | double startRadii = 0.8; ///< Interior weight is 1 up to here. | |
| 34 | 39 | double endRadii = 1.2; ///< And 0 from here; above `startRadii`. | |
| 35 | 39 | BlendShape shape = BlendShape::Smootherstep; ///< The curve in between. | |
| 36 | |||
| 37 | /// The interior weight at `radii` crater radii from the centre: 1 up to `startRadii`, 0 from | ||
| 38 | /// `endRadii`, and `shape` in between. | ||
| 39 | 236223 | double Weight(double radii) const { | |
| 40 | 236223 | return Falloff(radii, startRadii, endRadii, shape); | |
| 41 | } | ||
| 42 | |||
| 43 | 39 | bool operator==(const CraterBlend&) const = default; | |
| 44 | }; | ||
| 45 | |||
| 46 | /// How crater rims are rounded: near the rim, the profile is blended toward itself smoothed across | ||
| 47 | /// distance by a Gaussian, with full weight at the rim fading to none at the band's edges. | ||
| 48 | struct RimSmoothing { | ||
| 49 | /// Gaussian standard deviation in crater radii; 0 leaves rims sharp. | ||
| 50 | 40 | double sigmaRadii = 0.0; | |
| 51 | 40 | double innerRadii = 0.8; ///< Inner edge of the smoothed band, in crater radii; in [0, 1). | |
| 52 | 40 | double outerRadii = 1.2; ///< Outer edge of the smoothed band, in crater radii; above 1. | |
| 53 | 40 | BlendShape shape = BlendShape::Smootherstep; ///< How the weight falls toward the edges. | |
| 54 | 40 | double strength = 1.0; ///< Share of the smoothed height used at the rim, in [0, 1]. | |
| 55 | |||
| 56 | /// The smoothing weight at `radii` crater radii from the centre: `strength` at the rim, 0 from | ||
| 57 | /// the band's edges and when `sigmaRadii` is 0. | ||
| 58 | double Weight(double radii) const; | ||
| 59 | |||
| 60 | 40 | bool operator==(const RimSmoothing&) const = default; | |
| 61 | }; | ||
| 62 | |||
| 63 | /// Checks rim smoothing settings. | ||
| 64 | /// @throws std::invalid_argument for a negative or non-finite `sigmaRadii`, a `strength` outside | ||
| 65 | /// [0, 1], or a band that does not satisfy 0 <= `innerRadii` < 1 < `outerRadii`. | ||
| 66 | void ValidateRimSmoothing(const RimSmoothing& smoothing); | ||
| 67 | |||
| 68 | /// Fractal noise added to each crater, keyed to its ID so tiles and point queries agree: over the | ||
| 69 | /// whole footprint, fading out to nothing at the profile's reach, and in a band around the rim. | ||
| 70 | /// Amplitudes are shares of the crater's diameter, so the noise scales with the crater. | ||
| 71 | struct CraterNoise { | ||
| 72 | 39 | double amplitude = 0.0; ///< Footprint noise amplitude over the diameter; 0 adds none. | |
| 73 | 39 | double wavelengthRadii = 0.5; ///< Wavelength of its first octave, in crater radii. | |
| 74 | 39 | int octaves = 4; ///< Octaves of both noises, 1 to 12. | |
| 75 | 39 | double gain = 0.5; ///< Weight ratio between successive octaves; positive. | |
| 76 | 39 | double rimAmplitude = 0.0; ///< Rim noise amplitude over the diameter; 0 adds none. | |
| 77 | 39 | double rimWavelengthRadii = 0.1; ///< Wavelength of its first octave, in crater radii. | |
| 78 | 39 | double rimInnerRadii = 0.8; ///< Inner edge of the rim band, in crater radii; in [0, 1). | |
| 79 | 39 | double rimOuterRadii = 1.2; ///< Outer edge of the rim band, in crater radii; above 1. | |
| 80 | 39 | std::uint32_t seed = 0; ///< Varies the noise of every crater. | |
| 81 | |||
| 82 | 39 | bool operator==(const CraterNoise&) const = default; | |
| 83 | }; | ||
| 84 | |||
| 85 | /// Checks crater noise settings. | ||
| 86 | /// @throws std::invalid_argument for a negative or non-finite amplitude, a non-positive | ||
| 87 | /// wavelength or gain, octaves outside 1 to 12, or a rim band that does not satisfy | ||
| 88 | /// 0 <= `rimInnerRadii` < 1 < `rimOuterRadii`. | ||
| 89 | void ValidateCraterNoise(const CraterNoise& noise); | ||
| 90 | |||
| 91 | /// The texture of a crater's walls and ejecta, keyed to its ID: radial gullies down the inner | ||
| 92 | /// wall, hummocky ejecta lineated away from the rim, and older relief buried under the ejecta. | ||
| 93 | /// Ejecta follow McGetchin et al.'s (1973) thickness 0.14 R^0.74 (r / R)^-3 m, tapered to nothing | ||
| 94 | /// at `ejectaReachRadii`. Gullies and ejecta texture fade as the crater wears; burial stays. | ||
| 95 | struct CraterTexture { | ||
| 96 | 39 | double wallStreaks = 0.0; ///< Gully amplitude over the diameter; 0 adds none. | |
| 97 | 39 | double wallStreakWidthRadii = 0.15; ///< Width of the gullies across the wall, in radii. | |
| 98 | 39 | double ejecta = 0.0; ///< Ejecta texture amplitude over the ejecta thickness; 0 adds none. | |
| 99 | 39 | double ejectaLineationRadii = 0.15; ///< Width of the lineations across, in radii at the rim. | |
| 100 | /// Share of older relief the ejecta replace by the crater's datum at the rim, falling with | ||
| 101 | /// their thickness; 0 buries nothing, and without a datum nothing is buried. | ||
| 102 | 39 | double mantling = 0.0; | |
| 103 | 39 | double ejectaReachRadii = 3.0; ///< How far ejecta texture and burial reach, in radii. | |
| 104 | /// Freshness (`CraterState::Freshness`) at or below which gullies and ejecta texture are gone, | ||
| 105 | /// in [0, 1); they fade in along a smoothstep above it. | ||
| 106 | 39 | double minFreshness = 0.5; | |
| 107 | 39 | std::uint32_t seed = 0; ///< Varies the texture of every crater. | |
| 108 | |||
| 109 | /// Whether anything is drawn beyond the profile: ejecta texture or burial. | ||
| 110 | 1773812 | bool ReachesBeyondRim() const { | |
| 111 | 1773812 | return ejecta > 0.0 || mantling > 0.0; | |
| 112 | } | ||
| 113 | |||
| 114 | 39 | bool operator==(const CraterTexture&) const = default; | |
| 115 | }; | ||
| 116 | |||
| 117 | /// Checks crater texture settings. | ||
| 118 | /// @throws std::invalid_argument for a negative or non-finite amplitude, a non-positive width, a | ||
| 119 | /// mantling outside [0, 1], a reach of 1 radius or less, or a freshness outside [0, 1). | ||
| 120 | void ValidateCraterTexture(const CraterTexture& texture); | ||
| 121 | |||
| 122 | /// McGetchin et al.'s (1973) ejecta thickness at `radii` crater radii over that at the rim, | ||
| 123 | /// (r / R)^-3, tapered linearly in it to nothing at `reachRadii`; 1 within the rim. | ||
| 124 | double EjectaThicknessShare(double radii, double reachRadii); | ||
| 125 | |||
| 126 | /// How `ApplyCraters` shapes craters into the terrain. | ||
| 127 | struct CraterApplyOptions { | ||
| 128 | 39 | CraterOrder order = CraterOrder::OldestFirst; ///< Which craters overprint which. | |
| 129 | /// How craters too small to resolve at the sample spacing fade out. | ||
| 130 | 39 | ResolutionFade fade{}; | |
| 131 | /// Reference surface for the interior (`FitCraterDatum`); with `None` craters are purely | ||
| 132 | /// additive and the datum settings below are unused. | ||
| 133 | 39 | CraterDatum datum = CraterDatum::None; | |
| 134 | /// Footprint the datum is fitted over, in crater radii. | ||
| 135 | 39 | double datumFitRadii = 1.0; | |
| 136 | /// Share of the interior replaced by datum plus profile, in [0, 1]: 1 erases older relief, 0 | ||
| 137 | /// keeps it. | ||
| 138 | 39 | double interiorReplacement = 1.0; | |
| 139 | 39 | CraterBlend blend{}; ///< Where the replaced interior blends out. | |
| 140 | /// Irregular, non-circular outlines; off by default. | ||
| 141 | 39 | CraterIrregularity irregularity{}; | |
| 142 | 39 | RimSmoothing rimSmoothing{}; ///< Rounded rims; off by default. | |
| 143 | 39 | CraterNoise noise{}; ///< Fractal noise over each crater; off by default. | |
| 144 | 39 | CraterTexture texture{}; ///< Wall gullies, ejecta texture and burial; off by default. | |
| 145 | /// Floors offset downslope, rims lowered upslope and faster wear on the slope of the ground | ||
| 146 | /// beneath the layer; needs the `Plane` datum. | ||
| 147 | 39 | CraterSlopeResponse slope{}; | |
| 148 | /// What craters are shaped on; on a sphere, centres and rasters are longitude and latitude and | ||
| 149 | /// each crater is shaped in its local frame, spacings in metres. | ||
| 150 | 39 | Surface surface{}; | |
| 151 | |||
| 152 | 39 | bool operator==(const CraterApplyOptions&) const = default; | |
| 153 | }; | ||
| 154 | |||
| 155 | /// Checks crater apply options. | ||
| 156 | /// @throws std::invalid_argument for an invalid `fade`, `irregularity`, `rimSmoothing` or `slope`, | ||
| 157 | /// a slope response without the `Plane` datum, a | ||
| 158 | /// non-positive `datumFitRadii`, an `interiorReplacement` outside [0, 1], or a blend that does not | ||
| 159 | /// satisfy 0 <= `startRadii` < `endRadii`. | ||
| 160 | void ValidateCraterApplyOptions(const CraterApplyOptions& options); | ||
| 161 | |||
| 162 | /// Indices into `craters` in the order they are applied; ties fall to age, then diameter, then | ||
| 163 | /// the smaller ID. | ||
| 164 | std::vector<std::size_t> CraterApplyOrder(const CraterList& craters, CraterOrder order); | ||
| 165 | |||
| 166 | } // namespace terraingen | ||
| 167 |