layers/craters/shaping/apply_options.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "terraingen/layers/craters/shaping/apply_options.h" | ||
| 2 | |||
| 3 | #include "terraingen/util/checks.h" | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cmath> | ||
| 7 | #include <numeric> | ||
| 8 | #include <stdexcept> | ||
| 9 | |||
| 10 | namespace terraingen { | ||
| 11 | |||
| 12 | 790049 | double RimSmoothing::Weight(double radii) const { | |
| 13 | 790049 | if (sigmaRadii == 0.0) { | |
| 14 | 714185 | return 0.0; | |
| 15 | } | ||
| 16 | 75864 | if (radii <= 1.0) { | |
| 17 | 32024 | return strength * Falloff(2.0 - radii, 1.0, 2.0 - innerRadii, shape); | |
| 18 | } | ||
| 19 | 43840 | return strength * Falloff(radii, 1.0, outerRadii, shape); | |
| 20 | } | ||
| 21 | |||
| 22 | 246704 | void ValidateRimSmoothing(const RimSmoothing& smoothing) { | |
| 23 | 246704 | RequireNonNegative(smoothing.sigmaRadii, "Rim smoothing sigma"); | |
| 24 | 246704 | if (!(smoothing.strength >= 0.0 && smoothing.strength <= 1.0)) { | |
| 25 | 2 | throw std::invalid_argument("Rim smoothing strength must be between 0 and 1"); | |
| 26 | } | ||
| 27 | 493403 | if (!(smoothing.innerRadii >= 0.0 && smoothing.innerRadii < 1.0 && smoothing.outerRadii > 1.0 && | |
| 28 | 246701 | std::isfinite(smoothing.outerRadii))) { | |
| 29 | 1 | throw std::invalid_argument("Rim smoothing band must satisfy 0 <= inner < 1 < outer"); | |
| 30 | } | ||
| 31 | 246701 | } | |
| 32 | |||
| 33 | 246713 | void ValidateCraterNoise(const CraterNoise& noise) { | |
| 34 | 246713 | RequireNonNegative(noise.amplitude, "Crater noise amplitude"); | |
| 35 | 246712 | RequireNonNegative(noise.rimAmplitude, "Crater rim noise amplitude"); | |
| 36 | 246712 | RequirePositive(noise.wavelengthRadii, "Crater noise wavelength"); | |
| 37 | 246711 | RequirePositive(noise.rimWavelengthRadii, "Crater rim noise wavelength"); | |
| 38 | 246711 | RequirePositive(noise.gain, "Crater noise gain"); | |
| 39 | 246711 | if (noise.octaves < 1 || noise.octaves > 12) { | |
| 40 | 3 | throw std::invalid_argument("Crater noise needs 1 to 12 octaves"); | |
| 41 | } | ||
| 42 | 493415 | if (!(noise.rimInnerRadii >= 0.0 && noise.rimInnerRadii < 1.0 && noise.rimOuterRadii > 1.0 && | |
| 43 | 246707 | std::isfinite(noise.rimOuterRadii))) { | |
| 44 | 1 | throw std::invalid_argument("Crater rim noise band must satisfy 0 <= inner < 1 < outer"); | |
| 45 | } | ||
| 46 | 246707 | } | |
| 47 | |||
| 48 | 246711 | void ValidateCraterTexture(const CraterTexture& texture) { | |
| 49 | 246711 | RequireNonNegative(texture.wallStreaks, "Crater wall streak amplitude"); | |
| 50 | 246711 | RequireNonNegative(texture.ejecta, "Crater ejecta texture amplitude"); | |
| 51 | 246711 | RequirePositive(texture.wallStreakWidthRadii, "Crater wall streak width"); | |
| 52 | 246710 | RequirePositive(texture.ejectaLineationRadii, "Crater ejecta lineation width"); | |
| 53 | 246710 | if (!(texture.mantling >= 0.0 && texture.mantling <= 1.0)) { | |
| 54 | 2 | throw std::invalid_argument("Crater ejecta mantling must be in [0, 1]"); | |
| 55 | } | ||
| 56 | 246708 | if (!(texture.ejectaReachRadii > 1.0 && std::isfinite(texture.ejectaReachRadii))) { | |
| 57 | 1 | throw std::invalid_argument("Crater ejecta must reach beyond 1 radius"); | |
| 58 | } | ||
| 59 | 246707 | if (!(texture.minFreshness >= 0.0 && texture.minFreshness < 1.0)) { | |
| 60 | 1 | throw std::invalid_argument("Crater texture minFreshness must be in [0, 1)"); | |
| 61 | } | ||
| 62 | 246706 | } | |
| 63 | |||
| 64 | 54006 | double EjectaThicknessShare(double radii, double reachRadii) { | |
| 65 | 54006 | if (radii <= 1.0) { | |
| 66 | 3 | return 1.0; | |
| 67 | } | ||
| 68 | 54003 | if (radii >= reachRadii) { | |
| 69 | 1 | return 0.0; | |
| 70 | } | ||
| 71 | 54002 | const double atReach = 1.0 / (reachRadii * reachRadii * reachRadii); | |
| 72 | 54002 | return (1.0 / (radii * radii * radii) - atReach) / (1.0 - atReach); | |
| 73 | } | ||
| 74 | |||
| 75 | 246709 | void ValidateCraterApplyOptions(const CraterApplyOptions& options) { | |
| 76 | 246709 | ValidateCraterNoise(options.noise); | |
| 77 | 246707 | ValidateCraterTexture(options.texture); | |
| 78 | 246706 | ValidateResolutionFade(options.fade); | |
| 79 | 246703 | ValidateCraterIrregularity(options.irregularity); | |
| 80 | 246703 | ValidateRimSmoothing(options.rimSmoothing); | |
| 81 | 246701 | ValidateCraterSlopeResponse(options.slope); | |
| 82 | 246715 | if ((options.slope.enabled || options.slope.criticalGradient) && | |
| 83 | 14 | options.datum != CraterDatum::Plane) { | |
| 84 | 3 | throw std::invalid_argument("A crater slope response needs the plane datum"); | |
| 85 | } | ||
| 86 | 246698 | RequirePositive(options.datumFitRadii, "datumFitRadii"); | |
| 87 | 246697 | if (!(options.interiorReplacement >= 0.0 && options.interiorReplacement <= 1.0)) { | |
| 88 | 4 | throw std::invalid_argument("interiorReplacement must be between 0 and 1"); | |
| 89 | } | ||
| 90 | 246693 | const CraterBlend& blend = options.blend; | |
| 91 | 493386 | if (!(std::isfinite(blend.startRadii) && std::isfinite(blend.endRadii) && | |
| 92 | 246693 | blend.startRadii >= 0.0 && blend.endRadii > blend.startRadii)) { | |
| 93 | 2 | throw std::invalid_argument("Crater blend must satisfy 0 <= startRadii < endRadii"); | |
| 94 | } | ||
| 95 | 246691 | } | |
| 96 | |||
| 97 | 129838 | std::vector<std::size_t> CraterApplyOrder(const CraterList& craters, CraterOrder order) { | |
| 98 | 129838 | std::vector<std::size_t> indices(craters.Size()); | |
| 99 | 129838 | std::iota(indices.begin(), indices.end(), std::size_t{0}); | |
| 100 | 129838 | const auto& age = craters.AgesGyr(); | |
| 101 | 129838 | const auto& diameter = craters.Diameters(); | |
| 102 | 129838 | const auto& id = craters.Ids(); | |
| 103 | 129838 | std::sort(indices.begin(), indices.end(), [&](std::size_t a, std::size_t b) { | |
| 104 | 87813530 | if (order == CraterOrder::OldestFirst && age[a] != age[b]) { | |
| 105 | 87622681 | return age[a] > age[b]; | |
| 106 | } | ||
| 107 | 190849 | if (diameter[a] != diameter[b]) { | |
| 108 | 187468 | return diameter[a] > diameter[b]; | |
| 109 | } | ||
| 110 | 3381 | if (age[a] != age[b]) { | |
| 111 | 3 | return age[a] > age[b]; | |
| 112 | } | ||
| 113 | 3378 | return id[a] < id[b]; | |
| 114 | }); | ||
| 115 | 129838 | return indices; | |
| 116 | } | ||
| 117 | |||
| 118 | } // namespace terraingen | ||
| 119 |