#include "ContourLevels.hpp" #include #include namespace geopro::app { namespace { constexpr int kMaxLevels = 100000; // 纯函数自身的 OOM 兜底(UI 另有 ≤50 校验) std::vector normalLevels(double mn, double mx, double interval) { std::vector levels; if (!std::isfinite(mn) || !std::isfinite(mx) || !std::isfinite(interval)) return levels; if (!(interval > 0) || !(mx > mn)) return levels; const double lend = std::ceil((mx - mn) / interval); if (lend > kMaxLevels) return levels; // 极小间隔 → 防爆内存 const int len = static_cast(lend); for (int i = 0; i < len; ++i) levels.push_back(mn + interval * i); return levels; } std::vector logarithmicLevels(double mn, double mx, int logLines) { std::vector levels; if (!std::isfinite(mn) || !std::isfinite(mx)) return levels; // 防 +Inf 致死循环 if (logLines <= 0 || !(mx > 0)) return levels; auto nextPow10 = [](double v) { return std::pow(10.0, std::ceil(std::log10(v))); }; const double A = (mn <= 0) ? 0.1 : std::max(0.1, nextPow10(mn) / 10.0); const double H = nextPow10(mx); std::vector powers; for (double cur = A; cur <= H; cur *= 10.0) powers.push_back(cur); levels.push_back(mn); for (std::size_t i = 0; i + 1 < powers.size(); ++i) { const double start = powers[i], end = powers[i + 1]; const double step = (end - start) / logLines; for (int j = 1; j < logLines; ++j) { const double v = start + step * j; if (v <= mx) levels.push_back(v); } if (end <= mx) levels.push_back(end); } if (!powers.empty() && powers.back() < mx) levels.push_back(mx); std::sort(levels.begin(), levels.end()); return levels; } std::vector equalAreaLevels(double mn, double mx, int cnt, const std::vector& samples) { std::vector levels; if (cnt <= 0) return levels; std::vector z; z.reserve(samples.size()); for (double v : samples) if (std::isfinite(v)) z.push_back(v); if (static_cast(z.size()) >= cnt) { // 分位 std::sort(z.begin(), z.end()); const int chunk = static_cast(z.size()) / cnt; for (int i = 0; i < cnt - 1; ++i) levels.push_back( z[static_cast(std::min(i * chunk, static_cast(z.size()) - 1))]); if (levels.empty() || levels.back() < z.back()) levels.push_back(z.back()); } else { // 兜底:等距 cnt 段(线性) const double step = (mx - mn) / cnt; for (int i = 0; i < cnt; ++i) levels.push_back(mn + step * i); } return levels; } } // namespace std::vector generateContourLevels(const ContourLevelParams& p, const std::vector& samples) { switch (p.method) { case ContourLevelParams::Method::Normal: return normalLevels(p.minValue, p.maxValue, p.interval); case ContourLevelParams::Method::Logarithmic: return logarithmicLevels(p.minValue, p.maxValue, p.logLinesCount); case ContourLevelParams::Method::EqualArea: return equalAreaLevels(p.minValue, p.maxValue, p.equalAreaLayerCount, samples); } return {}; } } // namespace geopro::app