From 39b97ffb70dd28edfd330906fb69df5adf1c39d8 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Sun, 7 Jun 2026 22:15:55 +0800 Subject: [PATCH] =?UTF-8?q?fix(app):=20=E8=A7=86=E5=9B=BE=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E4=B8=89=E6=8C=89=E9=92=AE(=E4=BA=8C=E7=BB=B4/?= =?UTF-8?q?=E4=B8=89=E7=BB=B4/=E4=B8=89=E7=BB=B4=E4=BD=93=E7=B4=A0)?= =?UTF-8?q?=E4=BA=92=E6=96=A5=E8=BF=9E=E8=B4=AF=20=E2=80=94=20=E5=88=872D/?= =?UTF-8?q?3D=E5=9B=9E=E5=89=96=E9=9D=A2,=E4=BD=93=E7=B4=A0=E8=87=AA?= =?UTF-8?q?=E8=BA=AB=E9=AB=98=E4=BA=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/main.cpp | 87 +++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index 8016560..8359dd2 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -220,6 +220,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re act2D->setChecked(true); // 默认二维 viewToolBar->addSeparator(); auto* actVoxel = viewToolBar->addAction(QStringLiteral("三维体素")); + // 三按钮做成统一互斥的"3 路视图模式":任意时刻恰一个勾选。 + actVoxel->setCheckable(true); + cameraGroup->addAction(actVoxel); centerLayout->addWidget(viewToolBar); centerLayout->addWidget(vtkWidget, 1); @@ -231,21 +234,6 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re if (sliceWidget->Get()) (*sliceWidget)->Off(); }; - QObject::connect(act2D, &QAction::triggered, vtkWidget, - [cameraMode, rendererPtr, renderWindowPtr, hideSlice]() { - *cameraMode = CameraMode::Top2D; - hideSlice(); // 切回剖面视图:关闭体素切片 - geopro::render::applyTop2D(rendererPtr); - renderWindowPtr->Render(); - }); - QObject::connect(act3D, &QAction::triggered, vtkWidget, - [cameraMode, rendererPtr, renderWindowPtr, hideSlice]() { - *cameraMode = CameraMode::Free3D; - hideSlice(); - geopro::render::applyFree3D(rendererPtr); - renderWindowPtr->Render(); - }); - auto* vtkDock = new ads::CDockWidget(QStringLiteral("剖面视图")); vtkDock->setWidget(centerWidget); dockManager->addDockWidget(ads::CenterDockWidgetArea, vtkDock); @@ -267,39 +255,68 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re rightDock->setWidget(propLabel); dockManager->addDockWidget(ads::RightDockWidgetArea, rightDock); - // 联动:点击 DS 项 → 加载 grid/colorScale → 渲染 + 更新属性。 + // 视图模式状态:当前数据集 id / 名称(供「二维/三维」按钮重渲染剖面用)。 + auto currentDsId = std::make_shared(); + auto currentDsName = std::make_shared(); + + // 渲染当前数据集的【剖面】:按 *cameraMode 选相机;体素态切回剖面也走这里。 // Scene/renderWindow 按【裸指针值】捕获:Scene 挂 window 父链、renderer 被 renderWindow // 引用计数持有,生命周期覆盖事件循环。repo 由调用方保活。 - auto renderDataset = [&repo, scene, renderWindowPtr, applyCurrentCamera, propLabel]( + auto renderSectionCurrent = + [&repo, scene, renderWindowPtr, applyCurrentCamera, hideSlice, propLabel, currentDsId, + currentDsName]() { + if (currentDsId->isEmpty()) return; // 还没有选中任何数据集 + const std::string dsId = currentDsId->toStdString(); + const auto g = repo.loadGrid(dsId); + const auto cs = repo.loadColorScale(dsId); + hideSlice(); // 回到剖面视图:关闭可能存在的体素切片 + scene->clear(); + const auto actors = geopro::render::buildGridContour(g, cs); + scene->addActor(actors.bands); + scene->addActor(actors.edges); + applyCurrentCamera(); // 按当前 2D/3D 模式重设相机 + renderWindowPtr->Render(); + propLabel->setText(QStringLiteral("数据集: %1\n网格: %2 x %3\nvmin / vmax: %4 / %5") + .arg(*currentDsName) + .arg(g.nx()) + .arg(g.ny()) + .arg(g.vmin) + .arg(g.vmax)); + }; + + // 联动:点击 DS 项 → 记为当前数据集 → 默认回到二维剖面(勾「二维」+ 俯视)。 + auto renderDataset = [currentDsId, currentDsName, cameraMode, act2D, renderSectionCurrent]( QTreeWidgetItem* item) { const QString id = item->data(0, Qt::UserRole).toString(); if (id.isEmpty()) return; // GS/TM 节点无 dsId,忽略 - const std::string dsId = id.toStdString(); - const auto g = repo.loadGrid(dsId); - const auto cs = repo.loadColorScale(dsId); - scene->clear(); - const auto actors = geopro::render::buildGridContour(g, cs); - scene->addActor(actors.bands); - scene->addActor(actors.edges); - applyCurrentCamera(); // 按当前 2D/3D 模式重设相机 - renderWindowPtr->Render(); - propLabel->setText(QStringLiteral("数据集: %1\n网格: %2 x %3\nvmin / vmax: %4 / %5") - .arg(item->text(0)) - .arg(g.nx()) - .arg(g.ny()) - .arg(g.vmin) - .arg(g.vmax)); + *currentDsId = id; + *currentDsName = item->text(0); + *cameraMode = CameraMode::Top2D; + act2D->setChecked(true); // 点数据集默认回到二维剖面 + renderSectionCurrent(); }; QObject::connect(tree, &QTreeWidget::itemClicked, tree, [renderDataset](QTreeWidgetItem* it, int) { renderDataset(it); }); + // 视图模式:二维 = 剖面 + 俯视;三维 = 剖面 + 斜视。两者都重渲染当前剖面。 + QObject::connect(act2D, &QAction::triggered, vtkWidget, + [cameraMode, renderSectionCurrent]() { + *cameraMode = CameraMode::Top2D; + renderSectionCurrent(); + }); + QObject::connect(act3D, &QAction::triggered, vtkWidget, + [cameraMode, renderSectionCurrent]() { + *cameraMode = CameraMode::Free3D; + renderSectionCurrent(); + }); + // 当前体素 vtkImageData(dd_slice 切面 widget 需复用,保活到下次重建)。 auto voxelImage = std::make_shared>(); // dd_voxel:读两条交叉剖面 → IDW 体素 → GPU 体绘制 + 默认 3D 视角 + 可拖切片。 QObject::connect(actVoxel, &QAction::triggered, vtkWidget, - [&repo, scene, rendererPtr, renderWindowPtr, cameraMode, act3D, propLabel, + [&repo, scene, rendererPtr, renderWindowPtr, cameraMode, actVoxel, propLabel, sliceWidget, voxelImage]() { QApplication::setOverrideCursor(Qt::WaitCursor); const auto scatters = repo.loadVoxelScatters(); @@ -318,9 +335,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re rendererPtr->AddViewProp(result.volume); *voxelImage = result.image; - // 体素默认 3D 视角(同步工具条勾选态)。 + // 体素 = 体块 + 3D 视角;高亮「三维体素」自身(互斥组会清掉 2D/3D)。 *cameraMode = CameraMode::Free3D; - act3D->setChecked(true); + actVoxel->setChecked(true); geopro::render::applyFree3D(rendererPtr); rendererPtr->ResetCamera(); renderWindowPtr->Render(); // 先渲一帧确保 interactor 就绪