layers/boulders/ejecta_index.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "terraingen/layers/boulders/ejecta_index.h" | ||
| 2 | |||
| 3 | #include <algorithm> | ||
| 4 | #include <cmath> | ||
| 5 | #include <limits> | ||
| 6 | #include <utility> | ||
| 7 | |||
| 8 | namespace terraingen { | ||
| 9 | |||
| 10 | namespace { | ||
| 11 | |||
| 12 | /// The most buckets an index holds per crater, beyond a floor for small lists. | ||
| 13 | constexpr std::size_t kBucketsPerCrater = 16; | ||
| 14 | constexpr std::size_t kMinBuckets = 1024; | ||
| 15 | |||
| 16 | } // namespace | ||
| 17 | |||
| 18 | 6289 | EjectaIndex::EjectaIndex(CraterList craters, const Surface& surface, | |
| 19 | 6289 | const std::function<double(const Crater&)>& reach) | |
| 20 | 6289 | : craters_(std::move(craters)) { | |
| 21 | 6289 | const std::size_t count = craters_.Size(); | |
| 22 | 6289 | all_.resize(count); | |
| 23 | 19695 | for (std::size_t n = 0; n < count; ++n) { | |
| 24 | 13406 | all_[n] = static_cast<std::uint32_t>(n); | |
| 25 | } | ||
| 26 | 6289 | if (surface.IsBody() || count == 0) { | |
| 27 | 6 | return; | |
| 28 | } | ||
| 29 | 6283 | std::vector<Bounds2d> boxes(count); | |
| 30 | 6283 | double minX = std::numeric_limits<double>::infinity(); | |
| 31 | 6283 | double minY = minX; | |
| 32 | 6283 | double maxX = -minX; | |
| 33 | 6283 | double maxY = -minX; | |
| 34 | 6283 | double sum = 0.0; | |
| 35 | 19289 | for (std::size_t n = 0; n < count; ++n) { | |
| 36 | 13006 | const Crater crater = craters_.At(n); | |
| 37 | 13006 | const double r = std::fmax(reach(crater), 0.0); | |
| 38 | 13006 | boxes[n] = {crater.x - r, crater.y - r, crater.x + r, crater.y + r}; | |
| 39 | 13006 | minX = std::fmin(minX, boxes[n].minX); | |
| 40 | 13006 | minY = std::fmin(minY, boxes[n].minY); | |
| 41 | 13006 | maxX = std::fmax(maxX, boxes[n].maxX); | |
| 42 | 13006 | maxY = std::fmax(maxY, boxes[n].maxY); | |
| 43 | 13006 | sum += r; | |
| 44 | } | ||
| 45 | 6283 | const double width = maxX - minX; | |
| 46 | 6283 | const double height = maxY - minY; | |
| 47 | 6283 | const double budget = static_cast<double>(std::max(kMinBuckets, kBucketsPerCrater * count)); | |
| 48 | double cell = | ||
| 49 | 6283 | std::fmax(2.0 * sum / static_cast<double>(count), std::sqrt(width * height / budget)); | |
| 50 | 6283 | if (!(cell > 0.0) || !std::isfinite(cell)) { | |
| 51 | ✗ | cell = std::fmax(std::fmax(width, height), 1.0); | |
| 52 | } | ||
| 53 | 6283 | minX_ = minX; | |
| 54 | 6283 | minY_ = minY; | |
| 55 | 6283 | cell_ = cell; | |
| 56 | 6283 | columns_ = static_cast<std::size_t>(std::floor(width / cell)) + 1; | |
| 57 | 6283 | rows_ = static_cast<std::size_t>(std::floor(height / cell)) + 1; | |
| 58 | 6283 | buckets_.resize(columns_ * rows_); | |
| 59 | 99722 | const auto column = [&](double x) { | |
| 60 | 199444 | return std::min(columns_ - 1, | |
| 61 | 99722 | static_cast<std::size_t>(std::fmax(0.0, std::floor((x - minX_) / cell_)))); | |
| 62 | 6283 | }; | |
| 63 | 50989 | const auto row = [&](double y) { | |
| 64 | 101978 | return std::min(rows_ - 1, | |
| 65 | 50989 | static_cast<std::size_t>(std::fmax(0.0, std::floor((y - minY_) / cell_)))); | |
| 66 | 6283 | }; | |
| 67 | 19289 | for (std::size_t n = 0; n < count; ++n) { | |
| 68 | 37983 | for (std::size_t j = row(boxes[n].minY); j <= row(boxes[n].maxY); ++j) { | |
| 69 | 74745 | for (std::size_t i = column(boxes[n].minX); i <= column(boxes[n].maxX); ++i) { | |
| 70 | 49768 | buckets_[j * columns_ + i].push_back(static_cast<std::uint32_t>(n)); | |
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | 6283 | } | |
| 75 | |||
| 76 | 196862 | const std::vector<std::uint32_t>& EjectaIndex::Near(double x, double y) const { | |
| 77 | 196862 | static const std::vector<std::uint32_t> none; | |
| 78 | 196862 | if (buckets_.empty()) { | |
| 79 | 2 | return all_; | |
| 80 | } | ||
| 81 | 196860 | const double u = std::floor((x - minX_) / cell_); | |
| 82 | 196860 | const double v = std::floor((y - minY_) / cell_); | |
| 83 | 196860 | if (!(u >= 0.0 && v >= 0.0 && u < static_cast<double>(columns_) && | |
| 84 | 196560 | v < static_cast<double>(rows_))) { | |
| 85 | 300 | return none; | |
| 86 | } | ||
| 87 | 196560 | return buckets_[static_cast<std::size_t>(v) * columns_ + static_cast<std::size_t>(u)]; | |
| 88 | } | ||
| 89 | |||
| 90 | } // namespace terraingen | ||
| 91 |