layers/craters/shaping/slope.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "terraingen/layers/craters/shaping/slope.h" | ||
| 2 | |||
| 3 | #include "terraingen/layers/fade.h" | ||
| 4 | #include "terraingen/random/stream.h" | ||
| 5 | #include "terraingen/util/checks.h" | ||
| 6 | |||
| 7 | #include <cmath> | ||
| 8 | #include <stdexcept> | ||
| 9 | |||
| 10 | namespace terraingen { | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | |||
| 14 | constexpr std::uint32_t kSlopeStream = 0x534C4F50u; | ||
| 15 | |||
| 16 | /// Where the floor shift starts to fade, in radii. | ||
| 17 | constexpr double kShiftPlateauRadii = 0.3; | ||
| 18 | |||
| 19 | /// The largest floor offset in diameters that keeps the shifted interior from folding. | ||
| 20 | constexpr double kMaxFloorOffset = 0.23; | ||
| 21 | |||
| 22 | } // namespace | ||
| 23 | |||
| 24 | 246708 | void ValidateCraterSlopeResponse(const CraterSlopeResponse& response) { | |
| 25 | 246708 | ValidateValueDistribution(response.floorOffset); | |
| 26 | 493415 | if (!(response.floorOffset.Lowest() >= 0.0 && | |
| 27 | 246707 | response.floorOffset.Highest() < kMaxFloorOffset)) { | |
| 28 | 2 | throw std::invalid_argument("Crater floor offset must be in [0, 0.23) diameters"); | |
| 29 | } | ||
| 30 | 246706 | RequireUnitInterval(response.upslopeRim, "Crater upslopeRim"); | |
| 31 | 246705 | RequirePositive(response.fullSlope, "Crater fullSlope"); | |
| 32 | 246704 | if (response.criticalGradient) { | |
| 33 | 6 | RequirePositive(*response.criticalGradient, "Crater criticalGradient"); | |
| 34 | } | ||
| 35 | 246703 | if (!(std::isfinite(response.maxWearRate) && response.maxWearRate >= 1.0)) { | |
| 36 | 1 | throw std::invalid_argument("Crater maxWearRate must be finite and at least 1"); | |
| 37 | } | ||
| 38 | 246702 | } | |
| 39 | |||
| 40 | 1382 | double SlopeWearRate(const CraterSlopeResponse& response, double east, double north) { | |
| 41 | 1382 | if (!response.criticalGradient) { | |
| 42 | 780 | return 1.0; | |
| 43 | } | ||
| 44 | 602 | const double share = std::hypot(east, north) / *response.criticalGradient; | |
| 45 | 602 | const double room = 1.0 - share * share; | |
| 46 | 602 | return room > 1.0 / response.maxWearRate ? 1.0 / room : response.maxWearRate; | |
| 47 | } | ||
| 48 | |||
| 49 | 2536 | CraterSlopeShape SlopeShape(const Crater& crater, double east, double north, | |
| 50 | const CraterSlopeResponse& response) { | ||
| 51 | 2536 | const double gradient = std::hypot(east, north); | |
| 52 | 2536 | if (!response.enabled || !(gradient > 0.0)) { | |
| 53 | 651 | return {}; | |
| 54 | } | ||
| 55 | 1885 | const double strength = Smoothstep(std::atan(gradient) / response.fullSlope); | |
| 56 | 1885 | const IdWords id = SplitId(crater.id); | |
| 57 | 1885 | RandomStream random(response.seed, kSlopeStream, id.low, id.high); | |
| 58 | 1885 | const double u1 = random.NextDouble(); | |
| 59 | 1885 | const double u2 = random.NextDouble(); | |
| 60 | 1885 | const double offset = strength * response.floorOffset.Sample(u1, u2) * crater.diameter; | |
| 61 | 1885 | const Vec2d up{east / gradient, north / gradient}; | |
| 62 | 1885 | const double removed = strength * (1.0 - response.upslopeRim); | |
| 63 | 1885 | return {{-offset * up.x, -offset * up.y}, {removed * up.x, removed * up.y}}; | |
| 64 | } | ||
| 65 | |||
| 66 | 43203 | Vec2d SlopeShiftedOffset(const CraterSlopeShape& shape, const Vec2d& offset, double radius) { | |
| 67 | 43203 | const double radii = std::hypot(offset.x, offset.y) / radius; | |
| 68 | const double weight = | ||
| 69 | 43203 | 1.0 - Smoothstep((radii - kShiftPlateauRadii) / (1.0 - kShiftPlateauRadii)); | |
| 70 | 43203 | return {offset.x - weight * shape.shift.x, offset.y - weight * shape.shift.y}; | |
| 71 | } | ||
| 72 | |||
| 73 | 15714 | double SlopeRaisedShare(const CraterSlopeShape& shape, const Vec2d& offset) { | |
| 74 | 15714 | const double distance = std::hypot(offset.x, offset.y); | |
| 75 | 15714 | const double removed = std::hypot(shape.upslope.x, shape.upslope.y); | |
| 76 | 15714 | if (!(distance > 0.0) || !(removed > 0.0)) { | |
| 77 | 2 | return 1.0; | |
| 78 | } | ||
| 79 | 15712 | const double cosine = std::fmax(0.0, (shape.upslope.x * offset.x + shape.upslope.y * offset.y) / | |
| 80 | 15712 | (removed * distance)); | |
| 81 | 15712 | return 1.0 - removed * cosine * cosine; | |
| 82 | } | ||
| 83 | |||
| 84 | } // namespace terraingen | ||
| 85 |