geopro/tests/render/test_contour_bands.cpp

91 lines
3.9 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <gtest/gtest.h>
#include "ContourBands.hpp"
using namespace geopro::core;
using namespace geopro::render;
// 上采样 2x色带边界更密 → 多边形数应多于不上采样。
TEST(ContourBands, UpsampleIncreasesDetail) {
Grid g(3, 3);
g.x = {0, 1, 2}; g.y = {0, 1, 2};
for (int j = 0; j < 3; ++j)
for (int i = 0; i < 3; ++i) g.valueAt(i, j) = static_cast<double>(i * i + j);
g.vmin = 0; g.vmax = 6;
ColorScale cs;
cs.addStop(0, Rgba{0,0,255,255}); cs.addStop(3, Rgba{0,255,0,255}); cs.addStop(6, Rgba{255,0,0,255});
ContourOptions a; a.upsample = 1; a.smooth = 0;
ContourOptions b; b.upsample = 2; b.smooth = 0;
auto ra = buildContourBands(g, cs, a);
auto rb = buildContourBands(g, cs, b);
EXPECT_GT(rb.bands.size(), ra.bands.size());
}
// 含 NaN 无效角的网格:裁剪后该角不应被任何色带覆盖(所有多边形顶点远离该角)。
TEST(ContourBands, ClipsNaNRegion) {
Grid g(3, 3);
g.x = {0, 1, 2}; g.y = {0, 1, 2};
for (int j = 0; j < 3; ++j) for (int i = 0; i < 3; ++i) g.valueAt(i, j) = 5.0;
g.valueAt(2, 2) = std::nan(""); // 右上角无效
g.vmin = 0; g.vmax = 10;
ColorScale cs; cs.addStop(0, Rgba{0,0,255,255}); cs.addStop(10, Rgba{255,0,0,255});
ContourOptions opt; opt.upsample = 1; opt.smooth = 0;
auto r = buildContourBands(g, cs, opt);
bool coversCorner = false;
for (const auto& b : r.bands)
for (const auto& p : b.ring)
if (p.x > 1.5 && p.y > 1.5) coversCorner = true;
EXPECT_FALSE(coversCorner);
}
// 2x2 平滑梯度网格 + 2 段色阶 → 至少 1 个色带多边形,多边形顶点 >=3。
TEST(ContourBands, ProducesNonEmptyBands) {
Grid g(3, 3);
g.x = {0, 1, 2}; g.y = {0, 1, 2};
for (int j = 0; j < 3; ++j)
for (int i = 0; i < 3; ++i) g.valueAt(i, j) = static_cast<double>(i + j); // 0..4
g.vmin = 0; g.vmax = 4;
ColorScale cs;
cs.addStop(0.0, Rgba{0, 0, 255, 255});
cs.addStop(2.0, Rgba{0, 255, 0, 255});
cs.addStop(4.0, Rgba{255, 0, 0, 255});
ContourOptions opt; opt.upsample = 1; opt.smooth = 0;
auto r = buildContourBands(g, cs, opt);
ASSERT_FALSE(r.bands.empty());
for (const auto& b : r.bands) EXPECT_GE(b.ring.size(), 3u);
}
// 诊断:等值线(lines)应非空——网格跨越多个色阶级时应产生等值线。
TEST(ContourBands, ProducesContourLines) {
Grid g(10, 10);
g.x.resize(10); g.y.resize(10);
for (int i = 0; i < 10; ++i) { g.x[i] = i; g.y[i] = i; }
for (int j = 0; j < 10; ++j)
for (int i = 0; i < 10; ++i) g.valueAt(i, j) = i + j; // 0..18
g.vmin = 0; g.vmax = 18;
ColorScale cs;
cs.addStop(0, Rgba{0,0,255,255}); cs.addStop(6, Rgba{0,255,0,255});
cs.addStop(12, Rgba{255,255,0,255}); cs.addStop(18, Rgba{255,0,0,255});
ContourOptions opt; opt.upsample = 1; opt.smooth = 0; opt.makeLines = true;
auto r = buildContourBands(g, cs, opt);
EXPECT_FALSE(r.lines.empty());
}
// 诊断(真实参数复现):大网格 + 默认 opt(upsample=2,smooth=0.3,simplifyTol=0.5) + 17 级色阶。
TEST(ContourBands, ProducesLinesRealisticOptions) {
Grid g(60, 40);
g.x.resize(60); g.y.resize(40);
for (int i = 0; i < 60; ++i) g.x[i] = i * 3.0;
for (int j = 0; j < 40; ++j) g.y[j] = -33.0 + j * 1.2;
for (int j = 0; j < 40; ++j)
for (int i = 0; i < 60; ++i)
g.valueAt(i, j) = 2.0 + 340.0 * (0.5 + 0.5 * std::sin(i * 0.2) * std::cos(j * 0.25));
g.vmin = 2; g.vmax = 348;
ColorScale cs;
const double bars[17] = {2.08,4.59,7.81,11.02,14.26,17.25,20.56,23.55,27.05,
31.16,36.83,43.64,51.98,62.09,81.14,108.24,348.52};
for (int i = 0; i < 17; ++i) cs.addStop(bars[i], Rgba{(unsigned char)(i*15),0,200,255});
ContourOptions opt; // 默认 upsample=2, smooth=0.3, simplifyTol=0.5, makeLines=true
auto r = buildContourBands(g, cs, opt);
EXPECT_FALSE(r.lines.empty());
}