From 85e4dbea5603ef03cadbb0cdd292a1d2fe9c2fec Mon Sep 17 00:00:00 2001 From: gaozheng Date: Sun, 7 Jun 2026 19:26:58 +0800 Subject: [PATCH] =?UTF-8?q?spike(S3):=20VTK=20banded=20contour=20=E7=AE=A1?= =?UTF-8?q?=E7=BA=BF=E8=B7=91=E9=80=9A=E7=9C=9F=E5=AE=9E=E7=BD=91=E6=A0=BC?= =?UTF-8?q?=E6=A0=B7=E6=9C=AC(=E5=9B=BE#18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vtkImageData(规则栅格)->vtkDataSetSurfaceFilter->vtkBandedPolyDataContourFilter(GenerateContourEdges) 离屏渲染成功, 验证设计§4.3管线选型(B-1/B-2修正)。 颜色精确映射(colorBar非均匀值)留 render 层用 vtkColorTransferFunction 做。 --- tests/CMakeLists.txt | 2 + tests/spike/CMakeLists.txt | 15 +++ tests/spike/grid_contour_spike.cpp | 141 +++++++++++++++++++++++++++++ vcpkg.json | 3 +- 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tests/spike/CMakeLists.txt create mode 100644 tests/spike/grid_contour_spike.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef605af..6ed3229 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,3 +8,5 @@ target_link_libraries(geopro_tests PRIVATE GTest::gtest GTest::gtest_main) include(GoogleTest) gtest_discover_tests(geopro_tests) + +add_subdirectory(spike) # spike S3: banded contour 渲染验证 diff --git a/tests/spike/CMakeLists.txt b/tests/spike/CMakeLists.txt new file mode 100644 index 0000000..1ccd9e8 --- /dev/null +++ b/tests/spike/CMakeLists.txt @@ -0,0 +1,15 @@ +# Spike S3: 真实样本 banded contour 离屏渲染(验证设计 §4.3 管线选型) +find_package(nlohmann_json CONFIG REQUIRED) +find_package(VTK REQUIRED COMPONENTS + CommonCore + CommonDataModel + CommonColor + FiltersGeometry + FiltersModeling + RenderingOpenGL2 + IOImage +) + +add_executable(grid_contour_spike grid_contour_spike.cpp) +target_link_libraries(grid_contour_spike PRIVATE ${VTK_LIBRARIES} nlohmann_json::nlohmann_json) +vtk_module_autoinit(TARGETS grid_contour_spike MODULES ${VTK_LIBRARIES}) diff --git a/tests/spike/grid_contour_spike.cpp b/tests/spike/grid_contour_spike.cpp new file mode 100644 index 0000000..6a04295 --- /dev/null +++ b/tests/spike/grid_contour_spike.cpp @@ -0,0 +1,141 @@ +// Spike S3: 用真实网格样本验证 VTK banded contour 管线(设计 §4.3 B-1/B-2 修正)。 +// vtkImageData(规则栅格) -> vtkDataSetSurfaceFilter -> vtkBandedPolyDataContourFilter +// (GenerateContourEdgesOn 同出 banded 面 + 等值线) -> 离屏渲染 PNG。 +// 目视对照 docs/_validate/ref_18_grid.png。 +// +// 数据由 build 脚本拷成 ASCII 路径(Windows 下 ifstream 读中文路径会失败): +// D:/dev/spike_data/grid.json, colorbar.json -> spike_grid_contour.png +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using json = nlohmann::json; + +static const std::string kDir = "D:/dev/spike_data/"; + +struct Rgb { unsigned char r, g, b; }; + +static Rgb parseHexOrRgb(const std::string& s) { + if (!s.empty() && s[0] == '#') { + auto h = [&](int i) { return (unsigned char)std::stoi(s.substr(i, 2), nullptr, 16); }; + return Rgb{h(1), h(3), h(5)}; + } + int r = 0, g = 0, b = 0; + auto p = s.find('('); + if (p != std::string::npos) std::sscanf(s.c_str() + p, "(%d,%d,%d", &r, &g, &b); + return Rgb{(unsigned char)r, (unsigned char)g, (unsigned char)b}; +} + +int main() { + // ---- 读网格 ---- + json g = json::parse(std::ifstream(kDir + "grid.json"))["data"]; + auto x = g["x"].get>(); // 100, 规则 + auto y = g["y"].get>(); // 22, 规则 + auto v = g["v"].get>>(); // [22][100] = [j=y][i=x] + const int nx = (int)x.size(), ny = (int)y.size(); + const double dx = x[1] - x[0], dy = y[1] - y[0]; + + vtkNew img; + img->SetDimensions(nx, ny, 1); + img->SetOrigin(x[0], y[0], 0.0); + img->SetSpacing(dx, dy, 1.0); + vtkNew sc; + sc->SetName("v"); + sc->SetNumberOfTuples((vtkIdType)nx * ny); + for (int j = 0; j < ny; ++j) + for (int i = 0; i < nx; ++i) sc->SetValue((vtkIdType)j * nx + i, v[j][i]); // i 最快 + img->GetPointData()->SetScalars(sc); + + // ---- 色阶 stops ---- + json cb = json::parse(std::ifstream(kDir + "colorbar.json"))["data"]["properties"]["colorBar"]; + std::vector> stops; + for (auto& pr : cb) + stops.emplace_back(std::stod(pr[0].get()), parseHexOrRgb(pr[1].get())); + std::sort(stops.begin(), stops.end(), [](auto& a, auto& b) { return a.first < b.first; }); + const double vmin = stops.front().first, vmax = stops.back().first; + + // 离散 LUT(阶梯,取下界) + vtkNew lut; + lut->SetNumberOfTableValues((vtkIdType)stops.size()); + lut->SetTableRange(vmin, vmax); + for (size_t k = 0; k < stops.size(); ++k) { + auto c = stops[k].second; + lut->SetTableValue((vtkIdType)k, c.r / 255.0, c.g / 255.0, c.b / 255.0, 1.0); + } + lut->Build(); + + // ---- 管线:imageData -> surface(polydata) -> banded contour(+edges) ---- + vtkNew surf; + surf->SetInputData(img); + + vtkNew banded; + banded->SetInputConnection(surf->GetOutputPort()); + std::vector levels; + for (auto& s : stops) levels.push_back(s.first); + banded->SetNumberOfContours((int)levels.size()); + for (int k = 0; k < (int)levels.size(); ++k) banded->SetValue(k, levels[k]); + banded->GenerateContourEdgesOn(); + banded->SetScalarModeToValue(); + + vtkNew mapper; + mapper->SetInputConnection(banded->GetOutputPort()); + mapper->SetScalarModeToUseCellData(); + mapper->SetLookupTable(lut); + mapper->SetScalarRange(vmin, vmax); + + vtkNew bands; + bands->SetMapper(mapper); + + // 等值线边(黑) + vtkNew edgeMapper; + edgeMapper->SetInputConnection(banded->GetOutputPort(1)); // contour edges + edgeMapper->ScalarVisibilityOff(); + vtkNew edges; + edges->SetMapper(edgeMapper); + edges->GetProperty()->SetColor(0, 0, 0); + edges->GetProperty()->SetLineWidth(0.5); + + // ---- 离屏渲染 ---- + vtkNew ren; + ren->AddActor(bands); + ren->AddActor(edges); + ren->SetBackground(1, 1, 1); + ren->GetActiveCamera()->ParallelProjectionOn(); + ren->ResetCamera(); + + vtkNew rw; + rw->SetOffScreenRendering(1); + rw->AddRenderer(ren); + rw->SetSize(1100, 320); + rw->Render(); + + vtkNew w2i; + w2i->SetInput(rw); + vtkNew png; + png->SetFileName((kDir + "spike_grid_contour.png").c_str()); + png->SetInputConnection(w2i->GetOutputPort()); + png->Write(); + + std::printf("SPIKE_S3_DONE grid=%dx%d stops=%zu vmin=%.1f vmax=%.1f\n", nx, ny, stops.size(), + vmin, vmax); + return 0; +} diff --git a/vcpkg.json b/vcpkg.json index f250e56..3767cca 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -3,6 +3,7 @@ "version": "0.1.0", "description": "Geopro 3.0 desktop client (Qt6 + VTK9) - M1. 方案②-修订: Qt/VTK/ADS/QtKeychain 对接官方 MSVC Qt(不走 vcpkg); 仅非 Qt 依赖走 vcpkg, 按层递增。", "dependencies": [ - "gtest" + "gtest", + "nlohmann-json" ] }