layers/pavement.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief `PavementLayer`, fractured bedrock: polygonal plates parted by cracks or raised ridges. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/layers/exposure.h" | ||
| 6 | #include "terraingen/layers/fade.h" | ||
| 7 | #include "terraingen/layers/layer.h" | ||
| 8 | #include "terraingen/layers/material.h" | ||
| 9 | #include "terraingen/util/geometry.h" | ||
| 10 | |||
| 11 | #include <cstdint> | ||
| 12 | #include <optional> | ||
| 13 | #include <vector> | ||
| 14 | |||
| 15 | namespace terraingen { | ||
| 16 | |||
| 17 | /// The plates and cracks of a `PavementLayer`. Lengths are in metres, angles in radians. | ||
| 18 | struct PavementOptions { | ||
| 19 | 4 | double plateSize = 1.0; ///< Mean plate width: the spacing of the plates' Voronoi sites. | |
| 20 | 4 | double jitter = 1.0; ///< How far sites stray from a square lattice, in [0, 1]. | |
| 21 | 4 | double warp = 0.15; ///< Bend of the plate edges, in plate sizes. | |
| 22 | 4 | double crackWidth = 0.05; ///< Width of the crack between two plates. | |
| 23 | 4 | double crackDepth = 0.05; ///< Depth of a crack, or height of a ridge with `raised`. | |
| 24 | 4 | bool raised = false; ///< Whether plates are parted by raised ridges, not cracks. | |
| 25 | 4 | double edgeRounding = 0.02; ///< Width of the rounded shoulder beside each crack. | |
| 26 | 4 | double maxTilt = 0.05; ///< Largest tilt of a plate. | |
| 27 | 4 | double maxStep = 0.03; ///< Largest height offset of a plate, up or down. | |
| 28 | /// Crack octaves: each finer octave splits the plates again into plates `lacunarity` times | ||
| 29 | /// smaller, with cracks, rounding, tilts and steps `gain` times the octave before. | ||
| 30 | 4 | int octaves = 1; | |
| 31 | 4 | double lacunarity = 2.0; ///< Plate size ratio between octaves, above 1. | |
| 32 | 4 | double gain = 0.5; ///< Crack and plate relief ratio between octaves, in (0, 1]. | |
| 33 | 4 | std::uint32_t seed = 1; ///< Varies the plates. | |
| 34 | /// When set, plates show where the ground beneath is bedrock (`ExposureField`), fading out | ||
| 35 | /// over soil. | ||
| 36 | 4 | std::optional<ExposureParams> exposure; | |
| 37 | 4 | double exposureSpacing = 1.0; ///< Spacing the ground is read at for the exposure field. | |
| 38 | /// On a body, the surface point whose tangent frame the plates are laid out in. | ||
| 39 | 4 | Vec2d anchor{}; | |
| 40 | 4 | ResolutionFade fade{}; ///< How plates and cracks too fine for the spacing fade out. | |
| 41 | |||
| 42 | 4 | bool operator==(const PavementOptions&) const = default; | |
| 43 | }; | ||
| 44 | |||
| 45 | /// Checks pavement options. | ||
| 46 | /// @throws std::invalid_argument for a plate size, crack width or exposure spacing that is not | ||
| 47 | /// positive and finite, a negative crack depth, edge rounding, tilt or step, a tilt of 90 deg or | ||
| 48 | /// more, a jitter outside [0, 1], a negative warp, octaves outside 1 to 8, a lacunarity not above | ||
| 49 | /// 1, a gain outside (0, 1], or invalid exposure or fade. | ||
| 50 | void ValidatePavementOptions(const PavementOptions& options); | ||
| 51 | |||
| 52 | /// The desiccation ridges of the Old Soaker slab in Gale crater (Stein et al. 2018): 2 cm | ||
| 53 | /// polygons parted by 5 mm high ridges about 2 mm wide (from ridges covering about 20 % of the | ||
| 54 | /// slab), flat and untilted. The polygons there are mostly four-sided with T-junctions; Voronoi | ||
| 55 | /// plates meet at Y-junctions. | ||
| 56 | PavementOptions MarsDesiccationRidges(); | ||
| 57 | |||
| 58 | /// Fractured bedrock pavement added to the terrain: Voronoi plates, each flat with its own tilt | ||
| 59 | /// and height step, parted by cracks (or ridges) with rounded shoulders, and split again by finer | ||
| 60 | /// octaves of cracks that end at the cracks before them; each octave fades out where too fine for | ||
| 61 | /// the spacing. Plate heights blend | ||
| 62 | /// across each crack, so the surface has no steps. A function of position only, so grids, tiles | ||
| 63 | /// and points agree; it lays bedrock over the material map. | ||
| 64 | class PavementLayer final : public FormulaLayer, public MaterialSource { | ||
| 65 | public: | ||
| 66 | /// On a body, plates are laid out in the tangent frame of `options.anchor`. Applying the layer | ||
| 67 | /// with the exposure field enabled needs `context.ground`. | ||
| 68 | /// @throws std::invalid_argument as `ValidatePavementOptions`. | ||
| 69 | explicit PavementLayer(PavementOptions options, Surface surface = {}); | ||
| 70 | |||
| 71 | /// The pavement's relief at world (x, y), every octave summed, without exposure or fading (m). | ||
| 72 | double ReliefAt(double x, double y) const; | ||
| 73 | |||
| 74 | /// The distance from world (x, y) to the nearest edge of the coarsest plates (m). | ||
| 75 | double EdgeDistanceAt(double x, double y) const; | ||
| 76 | |||
| 77 | /// The options the layer was made with. | ||
| 78 | ✗ | const PavementOptions& Options() const { | |
| 79 | ✗ | return options_; | |
| 80 | } | ||
| 81 | |||
| 82 | 3 | MaterialClass Material() const override { | |
| 83 | 3 | return MaterialClass::Bedrock; | |
| 84 | } | ||
| 85 | /// How fully the pavement covers (x, y): 1, or the exposure of the ground beneath. | ||
| 86 | /// @throws std::invalid_argument if the exposure field is enabled and `ground` is null. | ||
| 87 | double MaterialCoverAt(double x, double y, double spacing, const Ground* ground) const override; | ||
| 88 | |||
| 89 | protected: | ||
| 90 | float HeightAt(float height, double x, double y, double spacing, | ||
| 91 | const Ground* ground) const override; | ||
| 92 | void CheckContext(const LayerContext& context) const override; | ||
| 93 | |||
| 94 | private: | ||
| 95 | /// One crack octave: its plate size, crack and plate relief, and seed. | ||
| 96 | struct Level { | ||
| 97 | double size = 1.0; | ||
| 98 | double crackWidth = 0.0; | ||
| 99 | double crackDepth = 0.0; | ||
| 100 | double rounding = 0.0; | ||
| 101 | double maxTilt = 0.0; | ||
| 102 | double maxStep = 0.0; | ||
| 103 | std::uint32_t seed = 0; | ||
| 104 | }; | ||
| 105 | /// The plate of one octave containing planar point `q`: its relief, distance to its nearest | ||
| 106 | /// edge, how far it lies inside the plate rather than in its crack (0 on an edge, 1 past the | ||
| 107 | /// shoulder), and an id that seeds the finer octave's plates within it. | ||
| 108 | struct Plate { | ||
| 109 | double relief = 0.0; | ||
| 110 | double edge = 0.0; | ||
| 111 | double interior = 1.0; | ||
| 112 | std::uint32_t id = 0; | ||
| 113 | }; | ||
| 114 | bool Planar(double x, double y, Vec2d& planar) const; | ||
| 115 | Plate PlateAt(const Vec2d& q, const Level& level, std::uint32_t seed, double crackWeight) const; | ||
| 116 | /// The relief of every octave at planar point `q`, each faded at `spacing`; 0 for none. | ||
| 117 | double Relief(const Vec2d& q, double spacing) const; | ||
| 118 | double Gate(double x, double y, const Ground* ground) const; | ||
| 119 | |||
| 120 | PavementOptions options_; | ||
| 121 | std::optional<ExposureField> exposure_; | ||
| 122 | Vec3d anchorDirection_{}; | ||
| 123 | std::vector<Level> levels_; | ||
| 124 | }; | ||
| 125 | |||
| 126 | } // namespace terraingen | ||
| 127 |