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:
parent
d2006cb0c8
commit
59f4f0a41a
|
|
@ -1,6 +1,14 @@
|
||||||
# M1 spike 冒烟程序:QApplication + QMainWindow + QVTKOpenGLStereoWidget(锥体)
|
# M1 demo 工作台:在 ADS 停靠的 QVTK 视图里渲染真实 ERT 网格剖面(#18)。
|
||||||
# 目的:验证「全 vcpkg:Qt + VTK[qt] 共用一份 Qt」可编译、可运行、可渲染(spike#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 1:ColorScale 上色
|
||||||
)
|
)
|
||||||
|
|
||||||
# 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
|
||||||
|
|
|
||||||
136
src/app/main.cpp
136
src/app/main.cpp
|
|
@ -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 填一张精细 LUT(256 级,按真实 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();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue