sources/source_chain.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "terraingen/sources/source_chain.h" | ||
| 2 | |||
| 3 | #include <cmath> | ||
| 4 | #include <stdexcept> | ||
| 5 | #include <utility> | ||
| 6 | |||
| 7 | namespace terraingen { | ||
| 8 | |||
| 9 | 11 | SourceChain::SourceChain(std::vector<std::shared_ptr<const Source>> sources) | |
| 10 | 11 | : sources_(std::move(sources)) { | |
| 11 | 11 | if (sources_.empty()) { | |
| 12 | 1 | throw std::invalid_argument("A source chain needs at least one source"); | |
| 13 | } | ||
| 14 | 28 | for (const auto& source : sources_) { | |
| 15 | 19 | if (!source) { | |
| 16 | 1 | throw std::invalid_argument("A source chain cannot hold a null source"); | |
| 17 | } | ||
| 18 | } | ||
| 19 | 13 | } | |
| 20 | |||
| 21 | namespace { | ||
| 22 | |||
| 23 | /// Whether `value` of `raster` has no data: NaN, as `HeightAt` reports it, or the raster's no-data | ||
| 24 | /// value. | ||
| 25 | 349533 | bool Missing(const Raster<float>& raster, float value) { | |
| 26 | 349533 | return std::isnan(value) || raster.IsNoData(value); | |
| 27 | } | ||
| 28 | |||
| 29 | } // namespace | ||
| 30 | |||
| 31 | 7 | void SourceChain::Fill(Raster<float>& heights) const { | |
| 32 | 7 | sources_.front()->Fill(heights); | |
| 33 | 13 | for (std::size_t n = 1; n < sources_.size(); ++n) { | |
| 34 | 8 | bool missing = false; | |
| 35 | 270977 | for (const float value : heights.Values()) { | |
| 36 | 270975 | if (Missing(heights, value)) { | |
| 37 | 6 | missing = true; | |
| 38 | 6 | break; | |
| 39 | } | ||
| 40 | } | ||
| 41 | 8 | if (!missing) { | |
| 42 | 2 | return; | |
| 43 | } | ||
| 44 | 6 | Raster<float> next(heights.Width(), heights.Height()); | |
| 45 | 6 | next.SetTransform(heights.Transform()); | |
| 46 | 6 | sources_[n]->Fill(next); | |
| 47 | 67447 | for (std::size_t i = 0; i < heights.Size(); ++i) { | |
| 48 | 67441 | float& cell = heights.Values()[i]; | |
| 49 | 67441 | const float value = next.Values()[i]; | |
| 50 | 67441 | if (Missing(heights, cell) && !Missing(next, value)) { | |
| 51 | 11085 | cell = value; | |
| 52 | } | ||
| 53 | } | ||
| 54 | 6 | } | |
| 55 | } | ||
| 56 | |||
| 57 | 97 | float SourceChain::HeightAt(double x, double y) const { | |
| 58 | 163 | for (const auto& source : sources_) { | |
| 59 | 147 | const float height = source->HeightAt(x, y); | |
| 60 | 147 | if (!std::isnan(height)) { | |
| 61 | 81 | return height; | |
| 62 | } | ||
| 63 | } | ||
| 64 | 16 | return std::nanf(""); | |
| 65 | } | ||
| 66 | |||
| 67 | } // namespace terraingen | ||
| 68 |