layers/transforms.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief Height transforms as layers: scale and offset, clamp, and a function of your own. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/layers/layer.h" | ||
| 6 | |||
| 7 | #include <functional> | ||
| 8 | #include <optional> | ||
| 9 | |||
| 10 | namespace terraingen { | ||
| 11 | |||
| 12 | /// Scales and shifts the heights so far: height * `scale` + `offset`. | ||
| 13 | class ScaleLayer final : public FormulaLayer { | ||
| 14 | public: | ||
| 15 | /// @param scale Factor on the heights (vertical exaggeration). | ||
| 16 | /// @param offset Added after scaling, in metres. | ||
| 17 | /// @throws std::invalid_argument unless `scale` and `offset` are finite. | ||
| 18 | ScaleLayer(double scale, double offset = 0.0); | ||
| 19 | |||
| 20 | /// The factor on the heights. | ||
| 21 | 1 | double Scale() const { | |
| 22 | 1 | return scale_; | |
| 23 | } | ||
| 24 | /// The shift after scaling, in metres. | ||
| 25 | 1 | double Offset() const { | |
| 26 | 1 | return offset_; | |
| 27 | } | ||
| 28 | |||
| 29 | protected: | ||
| 30 | float HeightAt(float height, double x, double y, double spacing, | ||
| 31 | const Ground* ground) const override; | ||
| 32 | |||
| 33 | private: | ||
| 34 | double scale_; | ||
| 35 | double offset_; | ||
| 36 | }; | ||
| 37 | |||
| 38 | /// Clamps the heights so far to [`min`, `max`], either bound optional. | ||
| 39 | class ClampLayer final : public FormulaLayer { | ||
| 40 | public: | ||
| 41 | /// @param min The lowest height kept, in metres; none for no floor. | ||
| 42 | /// @param max The highest height kept, in metres; none for no cap. | ||
| 43 | /// @throws std::invalid_argument for a bound that is not finite or `min` above `max`. | ||
| 44 | ClampLayer(std::optional<double> min, std::optional<double> max); | ||
| 45 | |||
| 46 | /// The lowest height kept, in metres; none for no floor. | ||
| 47 | 1 | std::optional<double> Min() const { | |
| 48 | 1 | return min_; | |
| 49 | } | ||
| 50 | /// The highest height kept, in metres; none for no cap. | ||
| 51 | 1 | std::optional<double> Max() const { | |
| 52 | 1 | return max_; | |
| 53 | } | ||
| 54 | |||
| 55 | protected: | ||
| 56 | float HeightAt(float height, double x, double y, double spacing, | ||
| 57 | const Ground* ground) const override; | ||
| 58 | |||
| 59 | private: | ||
| 60 | std::optional<double> min_; | ||
| 61 | std::optional<double> max_; | ||
| 62 | }; | ||
| 63 | |||
| 64 | /// The new height at (`x`, `y`) sampled every `spacing` metres given the `height` so far; must be | ||
| 65 | /// deterministic and thread-safe. | ||
| 66 | using HeightFunction = std::function<double(double x, double y, double spacing, double height)>; | ||
| 67 | |||
| 68 | /// A layer from a function of position, sample spacing and the height so far. | ||
| 69 | class FunctionLayer final : public FormulaLayer { | ||
| 70 | public: | ||
| 71 | /// @param surface What the terrain lies on, which turns a grid's cell size into metres. | ||
| 72 | /// @throws std::invalid_argument for an empty `function`. | ||
| 73 | explicit FunctionLayer(HeightFunction function, Surface surface = {}); | ||
| 74 | |||
| 75 | protected: | ||
| 76 | float HeightAt(float height, double x, double y, double spacing, | ||
| 77 | const Ground* ground) const override; | ||
| 78 | |||
| 79 | private: | ||
| 80 | HeightFunction function_; | ||
| 81 | }; | ||
| 82 | |||
| 83 | } // namespace terraingen | ||
| 84 |