distribution/minimum.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "terraingen/distribution/minimum.h" | ||
| 2 | |||
| 3 | #include "terraingen/distribution/combined.h" | ||
| 4 | |||
| 5 | #include <cmath> | ||
| 6 | #include <stdexcept> | ||
| 7 | #include <utility> | ||
| 8 | |||
| 9 | namespace terraingen { | ||
| 10 | |||
| 11 | namespace { | ||
| 12 | |||
| 13 | SfdKind | ||
| 14 | 850 | CommonKind(const std::vector<std::shared_ptr<const SizeFrequencyDistribution>>& distributions) { | |
| 15 | 850 | std::vector<const SizeFrequencyDistribution*> pointers; | |
| 16 | 2542 | for (const auto& distribution : distributions) { | |
| 17 | 1692 | pointers.push_back(distribution.get()); | |
| 18 | } | ||
| 19 | 1700 | return detail::CommonKind(pointers, "A minimum"); | |
| 20 | 850 | } | |
| 21 | |||
| 22 | /// The intersection of the inputs' valid ranges, whether or not they allow extrapolation. | ||
| 23 | 429 | DiameterRange IntersectRanges( | |
| 24 | const std::vector<std::shared_ptr<const SizeFrequencyDistribution>>& distributions) { | ||
| 25 | 429 | CommonKind(distributions); | |
| 26 | 422 | DiameterRange range; | |
| 27 | 1266 | for (const auto& distribution : distributions) { | |
| 28 | 844 | range.min = std::fmax(range.min, distribution->ValidRange().min); | |
| 29 | 844 | range.max = std::fmin(range.max, distribution->ValidRange().max); | |
| 30 | } | ||
| 31 | 422 | if (!(range.max > range.min)) { | |
| 32 | 1 | throw std::invalid_argument("The distributions' valid ranges do not overlap"); | |
| 33 | } | ||
| 34 | 421 | return range; | |
| 35 | } | ||
| 36 | |||
| 37 | } // namespace | ||
| 38 | |||
| 39 | 429 | MinimumSfd::MinimumSfd(std::vector<std::shared_ptr<const SizeFrequencyDistribution>> distributions) | |
| 40 | : SizeFrequencyDistribution(CommonKind(distributions), IntersectRanges(distributions)), | ||
| 41 | 429 | distributions_(std::move(distributions)) {} | |
| 42 | |||
| 43 | 2 | const SizeFrequencyDistribution& MinimumSfd::LowestAt(double diameter) const { | |
| 44 | 2 | const SizeFrequencyDistribution* lowest = distributions_.front().get(); | |
| 45 | 2 | double value = CumulativeOf(*lowest, diameter); | |
| 46 | 4 | for (std::size_t n = 1; n < distributions_.size(); ++n) { | |
| 47 | 2 | const auto& distribution = distributions_[n]; | |
| 48 | 2 | const double candidate = CumulativeOf(*distribution, diameter); | |
| 49 | 2 | if (candidate < value) { | |
| 50 | 1 | value = candidate; | |
| 51 | 1 | lowest = distribution.get(); | |
| 52 | } | ||
| 53 | } | ||
| 54 | 2 | return *lowest; | |
| 55 | } | ||
| 56 | |||
| 57 | 6485805 | double MinimumSfd::CumulativeAt(double diameter) const { | |
| 58 | 6485805 | double value = CumulativeOf(*distributions_.front(), diameter); | |
| 59 | 12971610 | for (std::size_t n = 1; n < distributions_.size(); ++n) { | |
| 60 | 6485805 | const double candidate = CumulativeOf(*distributions_[n], diameter); | |
| 61 | 6485805 | if (candidate < value) { | |
| 62 | 5954593 | value = candidate; | |
| 63 | } | ||
| 64 | } | ||
| 65 | 6485805 | return value; | |
| 66 | } | ||
| 67 | |||
| 68 | 2 | double MinimumSfd::IncrementalAt(double diameter) const { | |
| 69 | 2 | return IncrementalOf(LowestAt(diameter), diameter); | |
| 70 | } | ||
| 71 | |||
| 72 | } // namespace terraingen | ||
| 73 |