feat(ui): 三维体段右键全接旧栏操作-体(生成切片/色阶) 切片(保存/另存/导出图片dat/色阶/删除) 异常(显隐/删除)

This commit is contained in:
gaozheng 2026-06-25 12:33:22 +08:00
parent eb50a87694
commit 778ffe88c0
5 changed files with 57 additions and 11 deletions

View File

@ -853,7 +853,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
pushChecked(); // 体/其它 → 控制器(增删图元,可能触发 onVolumeChanged→syncSlices
syncSlices(); // 切片勾选变化即时调和(父体已在场时立即显隐)
});
QObject::connect(ca, &geopro::app::Column3DAnalysis::sliceRequested, vtkWidget,
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::sliceRequested, vtkWidget,
[interactionMgr](geopro::render::interact::SliceAxis axis) {
interactionMgr->addSlice(axis);
});
@ -884,7 +884,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
[](const std::string&) {});
});
// 列表切片「保存」=把当前(可能被拖动过的)位姿覆盖更新到该 dd_slice须该切片正在渲染才有位姿可取。
QObject::connect(ca, &geopro::app::Column3DAnalysis::sliceSaveRequested, &window,
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::sliceSaveRequested, &window,
[&window, interactionMgr, scene3dRepo, sceneView](const QString& dsId) {
if (!interactionMgr->selectSavedSlice(dsId.toStdString())) {
QMessageBox::information(&window, QStringLiteral("保存"),
@ -904,7 +904,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
[](const std::string&) {});
});
// 列表切片「保存为」=以该切片当前(存储)位姿另存为新 dd_slice不依赖渲染
QObject::connect(ca, &geopro::app::Column3DAnalysis::sliceSaveAsRequested, &window,
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::sliceSaveAsRequested, &window,
[&window, scene3dRepo, refreshAnalysis](const QString& dsId) {
geopro::data::I3dSceneRepository::SliceSpec spec;
if (!scene3dRepo->sliceSpec(dsId.toStdString(), spec)) return;
@ -919,7 +919,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
[](const std::string&) {});
});
// 列表切片「导出▸图片」:定位到渲染中的该切片 → 导出其上色 2D 图。
QObject::connect(ca, &geopro::app::Column3DAnalysis::sliceExportImageRequested, &window,
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::sliceExportImageRequested, &window,
[&window, interactionMgr](const QString& dsId) {
if (!interactionMgr->selectSavedSlice(dsId.toStdString())) {
QMessageBox::information(&window, QStringLiteral("导出"),
@ -937,7 +937,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
QStringLiteral("导出失败。"));
});
// 列表切片「导出▸dat」定位到渲染中的该切片 → 导出其重采样标量网格。
QObject::connect(ca, &geopro::app::Column3DAnalysis::sliceExportDatRequested, &window,
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::sliceExportDatRequested, &window,
[&window, interactionMgr](const QString& dsId) {
if (!interactionMgr->selectSavedSlice(dsId.toStdString())) {
QMessageBox::information(&window, QStringLiteral("导出"),
@ -956,7 +956,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
});
// 色阶(三维体/切片):复刻原版「色阶配置」对话框,确定后体素 + 其切片随新色阶重渲染。
// 仅对当前已渲染的三维体生效(切片色阶继承体色阶,经 InteractionManager 重建)。
QObject::connect(ca, &geopro::app::Column3DAnalysis::colorScaleRequested, &window,
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::colorScaleRequested, &window,
[&window, &colorTplRepo, &nav, sceneCtrl, sceneView](const QString& qid) {
const std::string dsId = qid.toStdString();
if (sceneView->currentVolumeDsId() != dsId || !sceneView->hasVolume()) {
@ -998,7 +998,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
QObject::connect(ca, &geopro::app::Column3DAnalysis::anomalyDisplayFilterChanged, vtkWidget,
[refreshAnomalies](int) { refreshAnomalies(); });
// 单条显隐 → 切该异常 actor 可见性。
QObject::connect(ca, &geopro::app::Column3DAnalysis::anomalyVisibilityChanged, vtkWidget,
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::anomalyVisibilityChanged, vtkWidget,
[sceneView, renderWindowPtr](const QString& id, bool vis) {
sceneView->setAnomalyVisible(id.toStdString(), vis);
renderWindowPtr->Render();

View File

@ -39,6 +39,16 @@ CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* d
connect(sec, &CategorySection::detailRequested, this, &CategoryAnalysisTab::detailRequested);
connect(sec, &CategorySection::deleteDatasetRequested, this,
&CategoryAnalysisTab::deleteDatasetRequested);
connect(sec, &CategorySection::sliceRequested, this, &CategoryAnalysisTab::sliceRequested);
connect(sec, &CategorySection::colorScaleRequested, this, &CategoryAnalysisTab::colorScaleRequested);
connect(sec, &CategorySection::sliceSaveRequested, this, &CategoryAnalysisTab::sliceSaveRequested);
connect(sec, &CategorySection::sliceSaveAsRequested, this, &CategoryAnalysisTab::sliceSaveAsRequested);
connect(sec, &CategorySection::sliceExportImageRequested, this,
&CategoryAnalysisTab::sliceExportImageRequested);
connect(sec, &CategorySection::sliceExportDatRequested, this,
&CategoryAnalysisTab::sliceExportDatRequested);
connect(sec, &CategorySection::anomalyVisibilityChanged, this,
&CategoryAnalysisTab::anomalyVisibilityChanged);
col->addWidget(sec);
}
col->addStretch(1);

View File

@ -5,6 +5,7 @@
#include <string>
#include <vector>
#include "DatasetCategory.hpp" // CategoryBuckets
#include "interact/SlicePlaneMath.hpp" // geopro::render::interact::SliceAxis
#include "repo/RepoTypes.hpp"
namespace geopro::data {
@ -31,6 +32,14 @@ signals:
void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds);
void detailRequested(const QString& dsId, const QString& ddCode, const QString& name);
void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除切片/异常
// ── 三维体段操作转发(迁自旧 Column3DAnalysis全接──
void sliceRequested(geopro::render::interact::SliceAxis axis);
void colorScaleRequested(const QString& dsId);
void sliceSaveRequested(const QString& dsId);
void sliceSaveAsRequested(const QString& dsId);
void sliceExportImageRequested(const QString& dsId);
void sliceExportDatRequested(const QString& dsId);
void anomalyVisibilityChanged(const QString& dsId, bool vis);
private:
void recomputeCheckedUnion();

View File

@ -195,6 +195,7 @@ QStringList CategorySection::checkedDsIds() const {
void CategorySection::emitChecked() { emit checkedDatasetsChanged(checkedDsIds()); }
void CategorySection::showContextMenu(const QPoint& pos) {
using geopro::render::interact::SliceAxis;
QTreeWidgetItem* it = list_->itemAt(pos);
if (!it) return;
const QString id = it->data(0, kDsIdRole).toString();
@ -204,10 +205,27 @@ void CategorySection::showContextMenu(const QPoint& pos) {
QMenu menu(this);
menu.addAction(QStringLiteral("详情"), this,
[this, id, ddCode, name] { emit detailRequested(id, ddCode, name); });
// 切片 / 异常可删除(三维体段无 deleteVolume 端点)。
if (ddCode == QStringLiteral("dd_slice") || ddCode == QStringLiteral("dd_anomaly")) {
menu.addAction(QStringLiteral("删除"), this,
[this, id, ddCode] { emit deleteDatasetRequested(id, ddCode); });
if (ddCode == QStringLiteral("dd_voxel")) { // 三维体
QMenu* sl = menu.addMenu(QStringLiteral("生成切片"));
sl->addAction(QStringLiteral("上下"), this, [this] { emit sliceRequested(SliceAxis::UpDown); });
sl->addAction(QStringLiteral("前后"), this, [this] { emit sliceRequested(SliceAxis::FrontBack); });
sl->addAction(QStringLiteral("左右"), this, [this] { emit sliceRequested(SliceAxis::LeftRight); });
sl->addAction(QStringLiteral("任意"), this, [this] { emit sliceRequested(SliceAxis::Oblique); });
menu.addAction(QStringLiteral("色阶…"), this, [this, id] { emit colorScaleRequested(id); });
} else if (ddCode == QStringLiteral("dd_slice")) { // 切片
menu.addAction(QStringLiteral("保存位姿"), this, [this, id] { emit sliceSaveRequested(id); });
menu.addAction(QStringLiteral("另存为…"), this, [this, id] { emit sliceSaveAsRequested(id); });
QMenu* ex = menu.addMenu(QStringLiteral("导出"));
ex->addAction(QStringLiteral("图片"), this, [this, id] { emit sliceExportImageRequested(id); });
ex->addAction(QStringLiteral("dat"), this, [this, id] { emit sliceExportDatRequested(id); });
menu.addAction(QStringLiteral("色阶…"), this, [this, id] { emit colorScaleRequested(id); });
menu.addSeparator();
menu.addAction(QStringLiteral("删除"), this, [this, id, ddCode] { emit deleteDatasetRequested(id, ddCode); });
} else if (ddCode == QStringLiteral("dd_anomaly")) { // 异常
menu.addAction(QStringLiteral("显示"), this, [this, id] { emit anomalyVisibilityChanged(id, true); });
menu.addAction(QStringLiteral("隐藏"), this, [this, id] { emit anomalyVisibilityChanged(id, false); });
menu.addSeparator();
menu.addAction(QStringLiteral("删除"), this, [this, id, ddCode] { emit deleteDatasetRequested(id, ddCode); });
}
menu.exec(list_->viewport()->mapToGlobal(pos));
}

View File

@ -2,6 +2,7 @@
#include <QStringList>
#include <QWidget>
#include <vector>
#include "interact/SlicePlaneMath.hpp" // geopro::render::interact::SliceAxis
#include "repo/CategoryConfig.hpp"
#include "repo/RepoTypes.hpp"
@ -38,6 +39,14 @@ signals:
void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); // 段头「+新增三维体」
void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); // 双击/右键=详情
void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除(切片/异常)
// ── 三维体段右键操作(迁自旧 Column3DAnalysis全接──
void sliceRequested(geopro::render::interact::SliceAxis axis); // 体→生成切片(轴)
void colorScaleRequested(const QString& dsId); // 体/切片→色阶
void sliceSaveRequested(const QString& dsId); // 切片→保存位姿
void sliceSaveAsRequested(const QString& dsId); // 切片→另存
void sliceExportImageRequested(const QString& dsId); // 切片→导出图片
void sliceExportDatRequested(const QString& dsId); // 切片→导出 dat
void anomalyVisibilityChanged(const QString& dsId, bool vis); // 异常→显示/隐藏
private:
void showContextMenu(const QPoint& pos); // 段体树右键菜单(详情 + 删除)