diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index d9a3410..53718be 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -1,6 +1,14 @@ -# M1 spike 冒烟程序:QApplication + QMainWindow + QVTKOpenGLStereoWidget(锥体) -# 目的:验证「全 vcpkg:Qt + VTK[qt] 共用一份 Qt」可编译、可运行、可渲染(spike#1)。 -# ADS 停靠(spike#2)在此基础上增量接入。 +# M1 demo 工作台:在 ADS 停靠的 QVTK 视图里渲染真实 ERT 网格剖面(#18)。 +# 复用 spike S3 的 banded contour 管线 + Phase 1 core 的 ColorScale 上色。 + +find_package(VTK REQUIRED COMPONENTS + GUISupportQt + RenderingOpenGL2 + InteractionStyle + FiltersGeometry + FiltersModeling +) +find_package(nlohmann_json CONFIG REQUIRED) add_executable(geopro_desktop WIN32 main.cpp) @@ -8,12 +16,12 @@ target_link_libraries(geopro_desktop PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets ${VTK_LIBRARIES} ads::qt6advanceddocking + nlohmann_json::nlohmann_json + geopro_core # Phase 1:ColorScale 上色 ) -# VTK 9 模块需 autoinit,否则渲染后端/工厂未注册,运行期黑屏或报错 vtk_module_autoinit(TARGETS geopro_desktop MODULES ${VTK_LIBRARIES}) -# 运行期 DLL 自动拷贝(单一 vcpkg 链路,规避双 Qt;设计 §11) if(WIN32) add_custom_command(TARGET geopro_desktop POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different diff --git a/src/app/main.cpp b/src/app/main.cpp index d4e7f54..f9f4711 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -1,8 +1,11 @@ -// M1 spike 冒烟程序(设计 §15 spike#1/#2)。 -// -// 验证目标: -// 1) 全 vcpkg 下 Qt6 + VTK[qt] 共用同一份 Qt,可编译/链接/运行(无双 Qt 冲突)。[S1 ✅] -// 2) QVTKOpenGLStereoWidget 在 ADS 停靠面板里渲染,浮动/重停靠不黑屏。[S2] +// M1 demo 工作台:ADS 停靠 + QVTK 视图渲染真实 ERT 网格剖面(设计图 #18)。 +// 端到端打通:core(ColorScale) + render(VTK banded contour) + view(Qt/ADS)。 +// 数据:D:/dev/spike_data/grid.json + colorbar.json(样本拷贝,ASCII 路径)。 +// 注:真实数据加载(Repository + 中文路径 + API)属 Phase 2,本处为可视化里程碑 demo。 + +#include +#include +#include #include #include @@ -12,54 +15,141 @@ #include #include +#include + +#include "model/ColorScale.hpp" // Phase 1 core + #include #include -#include +#include +#include +#include +#include #include +#include +#include #include +#include #include +#include #include +using json = nlohmann::json; +using geopro::core::AlphaScale; +using geopro::core::ColorScale; +using geopro::core::parseColor; + +namespace { + +// 读真实网格样本,建 banded contour actors(填充面 + 黑色等值线),返回到 renderer。 +void buildGridSection(vtkRenderer* ren, const std::string& dataDir) +{ + json g = json::parse(std::ifstream(dataDir + "grid.json"))["data"]; + auto x = g["x"].get>(); + auto y = g["y"].get>(); + auto v = g["v"].get>>(); // [j=y][i=x] + const int nx = static_cast(x.size()), ny = static_cast(y.size()); + + vtkNew img; + img->SetDimensions(nx, ny, 1); + img->SetOrigin(x[0], y[0], 0.0); + img->SetSpacing(x[1] - x[0], y[1] - y[0], 1.0); + vtkNew sc; + sc->SetName("v"); + sc->SetNumberOfTuples(static_cast(nx) * ny); + for (int j = 0; j < ny; ++j) + for (int i = 0; i < nx; ++i) + sc->SetValue(static_cast(j) * nx + i, v[j][i]); // i 最快 + img->GetPointData()->SetScalars(sc); + + // 色阶:用 Phase 1 core 的 ColorScale 解析 colorBar(网格色阶 alpha=0-255) + json cb = json::parse(std::ifstream(dataDir + "colorbar.json"))["data"]["properties"]["colorBar"]; + ColorScale cs; + std::vector levels; + for (auto& pr : cb) { + double val = std::stod(pr[0].get()); + cs.addStop(val, parseColor(pr[1].get(), AlphaScale::Bit255)); + levels.push_back(val); + } + const double vmin = levels.front(), vmax = levels.back(); + + // 用 ColorScale 填一张精细 LUT(256 级,按真实 colorBar 阶梯取色) + const int N = 256; + vtkNew lut; + lut->SetNumberOfTableValues(N); + lut->SetTableRange(vmin, vmax); + for (int t = 0; t < N; ++t) { + double val = vmin + (vmax - vmin) * t / (N - 1); + auto c = cs.colorAt(val); + lut->SetTableValue(t, c.r / 255.0, c.g / 255.0, c.b / 255.0, 1.0); + } + lut->Build(); + + vtkNew surf; + surf->SetInputData(img); + + vtkNew banded; + banded->SetInputConnection(surf->GetOutputPort()); + banded->SetNumberOfContours(static_cast(levels.size())); + for (int k = 0; k < static_cast(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.6); + + ren->AddActor(bands); + ren->AddActor(edges); + ren->SetBackground(1, 1, 1); + ren->GetActiveCamera()->ParallelProjectionOn(); + ren->ResetCamera(); +} + +} // namespace + int main(int argc, char* argv[]) { QSurfaceFormat::setDefaultFormat(QVTKOpenGLStereoWidget::defaultFormat()); QApplication app(argc, argv); QMainWindow window; - window.setWindowTitle(QStringLiteral("Geopro 3.0 — spike (Qt + VTK + ADS)")); + window.setWindowTitle(QStringLiteral("Geopro 3.0 — ERT 网格剖面 (M1 demo)")); window.resize(1280, 800); - // ---- VTK 渲染(锥体)---- auto* vtkWidget = new QVTKOpenGLStereoWidget(); vtkNew renderWindow; vtkWidget->setRenderWindow(renderWindow); - - vtkNew cone; - cone->SetResolution(32); - vtkNew mapper; - mapper->SetInputConnection(cone->GetOutputPort()); - vtkNew actor; - actor->SetMapper(mapper); vtkNew renderer; - renderer->AddActor(actor); - renderer->SetBackground(0.12, 0.13, 0.16); - renderer->ResetCamera(); renderWindow->AddRenderer(renderer); - // ---- ADS 停靠:VTK 面板 + 占位面板(用于测试浮动/重停靠)---- + buildGridSection(renderer, "D:/dev/spike_data/"); + auto* dockManager = new ads::CDockManager(&window); window.setCentralWidget(dockManager); - auto* vtkDock = new ads::CDockWidget(QStringLiteral("三维视图")); + auto* vtkDock = new ads::CDockWidget(QStringLiteral("二维剖面视图")); vtkDock->setWidget(vtkWidget); dockManager->addDockWidget(ads::CenterDockWidgetArea, vtkDock); auto* leftDock = new ads::CDockWidget(QStringLiteral("对象列表")); - leftDock->setWidget(new QLabel(QStringLiteral("(占位面板)"))); + leftDock->setWidget(new QLabel(QStringLiteral("(Phase 2 接入)"))); dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock); - auto* rightDock = new ads::CDockWidget(QStringLiteral("属性")); - rightDock->setWidget(new QLabel(QStringLiteral("(占位面板)"))); + auto* rightDock = new ads::CDockWidget(QStringLiteral("数据集 / 属性")); + rightDock->setWidget(new QLabel(QStringLiteral("(Phase 2 接入)"))); dockManager->addDockWidget(ads::RightDockWidgetArea, rightDock); window.show();