feat(demo): 工作台 QVTK 视图渲染真实 ERT 网格剖面(#18)

端到端打通 core(ColorScale 上色)+ render(VTK banded contour 管线)+ view(Qt/ADS 停靠)。
中央面板显示真实剖面网格数据1的等值面+等值线; 左右为 Phase 2 占位面板。
数据暂从 D:/dev/spike_data 读取(真实 Repository/中文路径/API 属 Phase 2)。
This commit is contained in:
gaozheng 2026-06-07 20:19:21 +08:00
parent d2006cb0c8
commit 59f4f0a41a
2 changed files with 126 additions and 28 deletions

View File

@ -1,6 +1,14 @@
# M1 spike QApplication + QMainWindow + QVTKOpenGLStereoWidget(锥体) # M1 demo ADS QVTK ERT #18
# vcpkgQt + VTK[qt] Qtspike#1 # spike S3 banded contour 线 + Phase 1 core ColorScale
# ADS spike#2
find_package(VTK REQUIRED COMPONENTS
GUISupportQt
RenderingOpenGL2
InteractionStyle
FiltersGeometry
FiltersModeling
)
find_package(nlohmann_json CONFIG REQUIRED)
add_executable(geopro_desktop WIN32 main.cpp) add_executable(geopro_desktop WIN32 main.cpp)
@ -8,12 +16,12 @@ target_link_libraries(geopro_desktop PRIVATE
Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Core Qt6::Gui Qt6::Widgets
${VTK_LIBRARIES} ${VTK_LIBRARIES}
ads::qt6advanceddocking ads::qt6advanceddocking
nlohmann_json::nlohmann_json
geopro_core # Phase 1ColorScale
) )
# VTK 9 autoinit/
vtk_module_autoinit(TARGETS geopro_desktop MODULES ${VTK_LIBRARIES}) vtk_module_autoinit(TARGETS geopro_desktop MODULES ${VTK_LIBRARIES})
# DLL vcpkg Qt §11
if(WIN32) if(WIN32)
add_custom_command(TARGET geopro_desktop POST_BUILD add_custom_command(TARGET geopro_desktop POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different

View File

@ -1,8 +1,11 @@
// M1 spike 冒烟程序(设计 §15 spike#1/#2 // M1 demo 工作台ADS 停靠 + QVTK 视图渲染真实 ERT 网格剖面(设计图 #18
// // 端到端打通core(ColorScale) + render(VTK banded contour) + view(Qt/ADS)。
// 验证目标: // 数据D:/dev/spike_data/grid.json + colorbar.json样本拷贝ASCII 路径)。
// 1) 全 vcpkg 下 Qt6 + VTK[qt] 共用同一份 Qt可编译/链接/运行(无双 Qt 冲突)。[S1 ✅] // 注真实数据加载Repository + 中文路径 + API属 Phase 2本处为可视化里程碑 demo。
// 2) QVTKOpenGLStereoWidget 在 ADS 停靠面板里渲染,浮动/重停靠不黑屏。[S2]
#include <fstream>
#include <string>
#include <vector>
#include <QApplication> #include <QApplication>
#include <QLabel> #include <QLabel>
@ -12,54 +15,141 @@
#include <DockManager.h> #include <DockManager.h>
#include <DockWidget.h> #include <DockWidget.h>
#include <nlohmann/json.hpp>
#include "model/ColorScale.hpp" // Phase 1 core
#include <QVTKOpenGLStereoWidget.h> #include <QVTKOpenGLStereoWidget.h>
#include <vtkActor.h> #include <vtkActor.h>
#include <vtkConeSource.h> #include <vtkBandedPolyDataContourFilter.h>
#include <vtkCamera.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkDoubleArray.h>
#include <vtkGenericOpenGLRenderWindow.h> #include <vtkGenericOpenGLRenderWindow.h>
#include <vtkImageData.h>
#include <vtkLookupTable.h>
#include <vtkNew.h> #include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkPolyDataMapper.h> #include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderer.h> #include <vtkRenderer.h>
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<std::vector<double>>();
auto y = g["y"].get<std::vector<double>>();
auto v = g["v"].get<std::vector<std::vector<double>>>(); // [j=y][i=x]
const int nx = static_cast<int>(x.size()), ny = static_cast<int>(y.size());
vtkNew<vtkImageData> 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<vtkDoubleArray> sc;
sc->SetName("v");
sc->SetNumberOfTuples(static_cast<vtkIdType>(nx) * ny);
for (int j = 0; j < ny; ++j)
for (int i = 0; i < nx; ++i)
sc->SetValue(static_cast<vtkIdType>(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<double> levels;
for (auto& pr : cb) {
double val = std::stod(pr[0].get<std::string>());
cs.addStop(val, parseColor(pr[1].get<std::string>(), AlphaScale::Bit255));
levels.push_back(val);
}
const double vmin = levels.front(), vmax = levels.back();
// 用 ColorScale 填一张精细 LUT256 级,按真实 colorBar 阶梯取色)
const int N = 256;
vtkNew<vtkLookupTable> 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<vtkDataSetSurfaceFilter> surf;
surf->SetInputData(img);
vtkNew<vtkBandedPolyDataContourFilter> banded;
banded->SetInputConnection(surf->GetOutputPort());
banded->SetNumberOfContours(static_cast<int>(levels.size()));
for (int k = 0; k < static_cast<int>(levels.size()); ++k) banded->SetValue(k, levels[k]);
banded->GenerateContourEdgesOn();
banded->SetScalarModeToValue();
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(banded->GetOutputPort());
mapper->SetScalarModeToUseCellData();
mapper->SetLookupTable(lut);
mapper->SetScalarRange(vmin, vmax);
vtkNew<vtkActor> bands;
bands->SetMapper(mapper);
vtkNew<vtkPolyDataMapper> edgeMapper;
edgeMapper->SetInputConnection(banded->GetOutputPort(1)); // contour edges
edgeMapper->ScalarVisibilityOff();
vtkNew<vtkActor> 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[]) int main(int argc, char* argv[])
{ {
QSurfaceFormat::setDefaultFormat(QVTKOpenGLStereoWidget::defaultFormat()); QSurfaceFormat::setDefaultFormat(QVTKOpenGLStereoWidget::defaultFormat());
QApplication app(argc, argv); QApplication app(argc, argv);
QMainWindow window; 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); window.resize(1280, 800);
// ---- VTK 渲染(锥体)----
auto* vtkWidget = new QVTKOpenGLStereoWidget(); auto* vtkWidget = new QVTKOpenGLStereoWidget();
vtkNew<vtkGenericOpenGLRenderWindow> renderWindow; vtkNew<vtkGenericOpenGLRenderWindow> renderWindow;
vtkWidget->setRenderWindow(renderWindow); vtkWidget->setRenderWindow(renderWindow);
vtkNew<vtkConeSource> cone;
cone->SetResolution(32);
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(cone->GetOutputPort());
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
vtkNew<vtkRenderer> renderer; vtkNew<vtkRenderer> renderer;
renderer->AddActor(actor);
renderer->SetBackground(0.12, 0.13, 0.16);
renderer->ResetCamera();
renderWindow->AddRenderer(renderer); renderWindow->AddRenderer(renderer);
// ---- ADS 停靠VTK 面板 + 占位面板(用于测试浮动/重停靠)---- buildGridSection(renderer, "D:/dev/spike_data/");
auto* dockManager = new ads::CDockManager(&window); auto* dockManager = new ads::CDockManager(&window);
window.setCentralWidget(dockManager); window.setCentralWidget(dockManager);
auto* vtkDock = new ads::CDockWidget(QStringLiteral("三维视图")); auto* vtkDock = new ads::CDockWidget(QStringLiteral("二维剖面视图"));
vtkDock->setWidget(vtkWidget); vtkDock->setWidget(vtkWidget);
dockManager->addDockWidget(ads::CenterDockWidgetArea, vtkDock); dockManager->addDockWidget(ads::CenterDockWidgetArea, vtkDock);
auto* leftDock = new ads::CDockWidget(QStringLiteral("对象列表")); auto* leftDock = new ads::CDockWidget(QStringLiteral("对象列表"));
leftDock->setWidget(new QLabel(QStringLiteral("(占位面板)"))); leftDock->setWidget(new QLabel(QStringLiteral("Phase 2 接入")));
dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock); dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock);
auto* rightDock = new ads::CDockWidget(QStringLiteral("属性")); auto* rightDock = new ads::CDockWidget(QStringLiteral("数据集 / 属性"));
rightDock->setWidget(new QLabel(QStringLiteral("(占位面板)"))); rightDock->setWidget(new QLabel(QStringLiteral("Phase 2 接入")));
dockManager->addDockWidget(ads::RightDockWidgetArea, rightDock); dockManager->addDockWidget(ads::RightDockWidgetArea, rightDock);
window.show(); window.show();