feat/vtk-3d-view #7
|
|
@ -79,8 +79,6 @@ add_executable(geopro_desktop WIN32
|
|||
panels/chart/ScatterMarqueePicker.cpp
|
||||
panels/chart/ContourDrawTool.cpp
|
||||
panels/columns/Column2DDataset.cpp
|
||||
panels/columns/Column3DDataset.cpp
|
||||
panels/columns/Column3DAnalysis.cpp
|
||||
panels/columns/CategorySection.cpp
|
||||
panels/columns/CategoryAnalysisTab.cpp
|
||||
panels/columns/DateRangeEdit.cpp
|
||||
|
|
|
|||
156
src/app/main.cpp
156
src/app/main.cpp
|
|
@ -143,9 +143,7 @@
|
|||
#include "AxesSettingsDialog.hpp"
|
||||
#include "AxesSettingsPanel.hpp"
|
||||
#include "repo/DatasetFieldDictionary.hpp"
|
||||
#include "panels/columns/Column3DDataset.hpp"
|
||||
#include "panels/columns/Column2DDataset.hpp"
|
||||
#include "panels/columns/Column3DAnalysis.hpp"
|
||||
|
||||
#include "CameraPreset.hpp"
|
||||
#include "ColorLutBuilder.hpp"
|
||||
|
|
@ -424,30 +422,14 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
}
|
||||
};
|
||||
|
||||
// 异常刷新渲染 + 填充三维分析栏异常列表(#4b/4c):按显示过滤档位决定异常集合。
|
||||
// 0 全部显示=所有异常;1 随GS/2 随数据集=当前活动体的异常;3 全部隐藏=不渲染、列表空。
|
||||
// (随GS 暂同随数据集,无 GS 分组数据。loadAnomalyTree 空 key→全部,非空→该体。mock 同步回调。)
|
||||
auto refreshAnomalies = [sceneView, scene3dRepo, drawer, renderWindowPtr]() {
|
||||
// 异常刷新渲染(#4b/4c):恒「全部显示」——旧三维分析栏的过滤档位 UI 已退役,新分段 tab 暂无档位
|
||||
// 控件(功能缺失,待补)。异常列表由 refreshAnalysis 经 voxelTree 全量注入三维体段,此处只管渲染。
|
||||
// (loadAnomalyTree 空 key=全部。mock 同步回调。)
|
||||
auto refreshAnomalies = [sceneView, scene3dRepo, renderWindowPtr]() {
|
||||
sceneView->clearAnomalies();
|
||||
auto* ca = drawer->colAnalysis();
|
||||
const int mode = ca->anomalyFilterMode();
|
||||
if (mode == 3) { // 全部隐藏
|
||||
ca->setAnomalies({});
|
||||
renderWindowPtr->Render();
|
||||
return;
|
||||
}
|
||||
std::string key; // 空 = 全部
|
||||
if (mode != 0) { // 随GS/随数据集 → 当前活动体
|
||||
key = sceneView->currentVolumeDsId();
|
||||
if (key.empty()) { // 无活动体 → 空
|
||||
ca->setAnomalies({});
|
||||
renderWindowPtr->Render();
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::vector<geopro::core::Anomaly> set;
|
||||
scene3dRepo->loadAnomalyTree(
|
||||
key,
|
||||
std::string{}, // 空 key = 全部
|
||||
[&set](geopro::data::I3dSceneRepository::AnomalyTree tree) {
|
||||
for (auto& b : tree.bodies)
|
||||
for (auto& a : b.members) set.push_back(a);
|
||||
|
|
@ -455,8 +437,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
},
|
||||
[](const std::string&) {});
|
||||
for (const auto& a : set) sceneView->addAnomaly(a);
|
||||
ca->setAnomalies(set); // 填充列表(每条显隐勾选默认显示)
|
||||
renderWindowPtr->Render(); // 必须重绘:clear+addAnomaly 改了 prop,否则 VTK 不刷新(与列表脱节)
|
||||
renderWindowPtr->Render(); // 必须重绘:clear+addAnomaly 改了 prop,否则 VTK 不刷新
|
||||
};
|
||||
|
||||
// 体素变化(重建/清场)后把体素 image 推给 InteractionManager(切片基底),并调和已保存切片 + 异常。
|
||||
|
|
@ -471,9 +452,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
refreshAnomalies(); // 同步重载异常 actor + 刷新异常列表
|
||||
};
|
||||
|
||||
// ── 三栏抽屉信号 → 控制器/交互(Task 7 接线)──────────────────────────────
|
||||
auto* c3 = drawer->col3D();
|
||||
|
||||
// ── 抽屉信号 → 控制器/交互(Task 7/12 接线)──────────────────────────────
|
||||
// 三维分析栏 = 后端 Analysis 行(dd_slice) + 客户端创建的三维体(mock)。生成的三维体是"分析产物"
|
||||
// (设计 §2.1:三维分析栏按 对象/三维体模型/切片 三级树),归三维分析栏(非数据集栏)。
|
||||
// 后端列表每次勾选测线全量覆盖,故客户端体单独维护、刷新时合并注入(不被冲掉)。
|
||||
|
|
@ -629,11 +608,10 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
if (!ok) return;
|
||||
scene3dRepo->createSlice(
|
||||
spec, name.isEmpty() ? std::string("切片") : name.toStdString(),
|
||||
[interactionMgr, refreshAnalysis, drawer](std::string newId) {
|
||||
[interactionMgr, refreshAnalysis](std::string newId) {
|
||||
interactionMgr->tagSelectedSlice(newId); // 链接当前切片 → 新数据集(不重绘)
|
||||
refreshAnalysis(); // 新行进列表(勾选集不变→不发多余信号)
|
||||
drawer->colAnalysis()->setItemChecked(QString::fromStdString(newId),
|
||||
true); // 自动展开+勾选(syncSlices 去重)
|
||||
// TODO:新分段 tab 暂无 setItemChecked,新切片列表默认未勾(已渲染但列表不打勾,待补)。
|
||||
},
|
||||
[&window](const std::string& m) {
|
||||
QMessageBox::warning(&window, QStringLiteral("保存切片"),
|
||||
|
|
@ -669,25 +647,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
}
|
||||
};
|
||||
|
||||
// 关闭已保存切片(VTK 视图「关闭」) → 取消三维分析栏对应勾选(场景↔列表双向同步)。
|
||||
interactionMgr->onSliceClosed = [drawer](const std::string& dsId) {
|
||||
drawer->colAnalysis()->setItemChecked(QString::fromStdString(dsId), false);
|
||||
};
|
||||
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::axesModeChanged, sceneCtrl,
|
||||
&geopro::controller::VtkSceneController::setAxesMode);
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::axesUnitChanged, sceneCtrl,
|
||||
&geopro::controller::VtkSceneController::setAxesUnit);
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::verticalExaggerationChanged, sceneCtrl,
|
||||
&geopro::controller::VtkSceneController::setVerticalExaggeration);
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::viewRequested, sceneCtrl,
|
||||
&geopro::controller::VtkSceneController::applyView);
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::zoomInRequested, sceneCtrl,
|
||||
&geopro::controller::VtkSceneController::zoomIn);
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::zoomOutRequested, sceneCtrl,
|
||||
&geopro::controller::VtkSceneController::zoomOut);
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::fitRequested, sceneCtrl,
|
||||
&geopro::controller::VtkSceneController::fit);
|
||||
// TODO:关闭已保存切片(VTK「关闭」)时同步取消列表勾选——旧三维分析栏退役后,新分段 tab 暂无
|
||||
// setItemChecked,场景→列表的取消勾选同步暂缺(actor 已移除,仅列表打勾态不同步,待补)。
|
||||
|
||||
// ── VTK 画布工具条(Task 12 §9):全局视图控制 → sceneCtrl ──────────────────
|
||||
QObject::connect(viewToolbar, &geopro::app::VtkViewToolbar::viewRequested, sceneCtrl,
|
||||
|
|
@ -712,13 +673,6 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
});
|
||||
QObject::connect(axesPanel, &geopro::app::AxesSettingsPanel::closed, &window,
|
||||
[axesPanel]() { axesPanel->hide(); });
|
||||
// 三维数据集栏勾选(反演剖面)→ 并入渲染勾选集(剖面走帘面路径)。
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::checkedDatasetsChanged, sceneCtrl,
|
||||
[checkedProfiles, pushChecked](const QStringList& ids) {
|
||||
*checkedProfiles = ids;
|
||||
pushChecked();
|
||||
});
|
||||
|
||||
// ── 三维分析 tab(5 段)信号接线(Task 12)──────────────────────────────────
|
||||
auto* analysisTab = drawer->analysisTab();
|
||||
// 5 段勾选并集 → 按类型分流渲染:反演剖面→帘面(checkedProfiles);三维体→体素(checkedAnalysis);
|
||||
|
|
@ -817,62 +771,12 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
else if (ddCode == QStringLiteral("dd_anomaly"))
|
||||
scene3dRepo->deleteAnomaly(id, ok, err);
|
||||
});
|
||||
// O点位置/字体本期 stub(TODO P4:弹框)。
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::oPointClicked, vtkWidget,
|
||||
[]() { /* TODO P4: O点位置弹框 */ });
|
||||
QObject::connect(c3, &geopro::app::Column3DDataset::fontClicked, vtkWidget,
|
||||
[]() { /* TODO P4: 字体弹框 */ });
|
||||
// (旧三维数据集栏「生成三维体」接线已退役——改由 analysisTab::generateVolumeRequested 走新对话框。)
|
||||
|
||||
auto* ca = drawer->colAnalysis();
|
||||
// 三维分析栏勾选(三维体/切片):体走控制器体素路径;切片(dd_slice)不进控制器(否则 loadSection
|
||||
// 会对 slice id 失败),单独经 syncSlices 在父体上还原渲染。
|
||||
QObject::connect(ca, &geopro::app::Column3DAnalysis::checkedItemsChanged, sceneCtrl,
|
||||
[checkedAnalysis, pushChecked, checkedSliceIds, syncSlices,
|
||||
scene3dRepo](const QStringList& ids) {
|
||||
QStringList nonSlice;
|
||||
checkedSliceIds->clear();
|
||||
for (const QString& id : ids) {
|
||||
const std::string s = id.toStdString();
|
||||
if (scene3dRepo->isSliceDataset(s))
|
||||
checkedSliceIds->insert(s);
|
||||
else
|
||||
nonSlice << id;
|
||||
}
|
||||
*checkedAnalysis = nonSlice;
|
||||
pushChecked(); // 体/其它 → 控制器(增删图元,可能触发 onVolumeChanged→syncSlices)
|
||||
syncSlices(); // 切片勾选变化即时调和(父体已在场时立即显隐)
|
||||
});
|
||||
// (O点位置/字体、旧栏「生成三维体」「勾选→渲染」接线均已退役——分别由 analysisTab 的
|
||||
// generateVolumeRequested / checkedDatasetsChanged 接管。)
|
||||
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::sliceRequested, vtkWidget,
|
||||
[interactionMgr](geopro::render::interact::SliceAxis axis) {
|
||||
interactionMgr->addSlice(axis);
|
||||
});
|
||||
// 三维分析栏「数据详情」:项非体即切片(dd_slice / dd_voxel),按 ddCode 分派到只读属性
|
||||
// 对话框(仿异常详情)。数据直接从具体 scene3dRepo 取(体/切片在 3D 仓储,非 detailCtrl 的 2D 管线)。
|
||||
QObject::connect(ca, &geopro::app::Column3DAnalysis::detailRequested, &window,
|
||||
[&window, scene3dRepo](const QString& dsId, const QString& ddCode,
|
||||
const QString& name) {
|
||||
if (ddCode == QStringLiteral("dd_slice")) {
|
||||
geopro::data::I3dSceneRepository::SliceSpec sp;
|
||||
if (scene3dRepo->sliceSpec(dsId.toStdString(), sp)) {
|
||||
geopro::app::SlicePropertiesDialog dlg(name, sp, &window);
|
||||
dlg.exec();
|
||||
}
|
||||
} else { // dd_voxel:三维体
|
||||
geopro::data::Api3dRepository::VolumeInfo info;
|
||||
if (scene3dRepo->volumeInfo(dsId.toStdString(), info)) {
|
||||
geopro::app::VolumePropertiesDialog dlg(name, info, &window);
|
||||
dlg.exec();
|
||||
}
|
||||
}
|
||||
});
|
||||
// 三维分析栏切片右键「删除」→ 删除 mock 切片 + 刷新列表(若在渲染,删后行消失→取消勾选→自动移除图元)。
|
||||
QObject::connect(ca, &geopro::app::Column3DAnalysis::sliceDeleteRequested, &window,
|
||||
[scene3dRepo, refreshAnalysis](const QString& dsId) {
|
||||
scene3dRepo->deleteSlice(
|
||||
dsId.toStdString(), [refreshAnalysis]() { refreshAnalysis(); },
|
||||
[](const std::string&) {});
|
||||
});
|
||||
// 列表切片「保存」=把当前(可能被拖动过的)位姿覆盖更新到该 dd_slice;须该切片正在渲染才有位姿可取。
|
||||
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::sliceSaveRequested, &window,
|
||||
[&window, interactionMgr, scene3dRepo, sceneView](const QString& dsId) {
|
||||
|
|
@ -983,34 +887,15 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
sceneCtrl->setVolumeColorScale(dsId, dlg.colorScale());
|
||||
});
|
||||
|
||||
// ── 3D 异常控制(#4c):显示过滤 / 单条显隐 / 删除 → 驱动 VTK 异常渲染 ──────────
|
||||
// 过滤档位变化 → 重算异常集合并重渲染 + 刷新列表(独立于体勾选)。
|
||||
QObject::connect(ca, &geopro::app::Column3DAnalysis::anomalyDisplayFilterChanged, vtkWidget,
|
||||
[refreshAnomalies](int) { refreshAnomalies(); });
|
||||
// ── 3D 异常控制(#4c):单条显隐 → 驱动 VTK 异常渲染 ──────────
|
||||
// 单条显隐 → 切该异常 actor 可见性。
|
||||
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::anomalyVisibilityChanged, vtkWidget,
|
||||
[sceneView, renderWindowPtr](const QString& id, bool vis) {
|
||||
sceneView->setAnomalyVisible(id.toStdString(), vis);
|
||||
renderWindowPtr->Render();
|
||||
});
|
||||
// 列表选中异常 → VTK 高亮联动(R84,list→VTK)。
|
||||
QObject::connect(ca, &geopro::app::Column3DAnalysis::anomalySelected, vtkWidget,
|
||||
[sceneView](const QString& id) {
|
||||
sceneView->setSelectedAnomaly(id.toStdString());
|
||||
});
|
||||
// 双击异常 → 只读属性对话框(R83,名称/类型/标记/归属/坐标/备注)。
|
||||
QObject::connect(ca, &geopro::app::Column3DAnalysis::anomalyPropertiesRequested, &window,
|
||||
[&window](const geopro::core::Anomaly& a) {
|
||||
geopro::app::AnomalyPropertiesDialog dlg(a, &window);
|
||||
dlg.exec();
|
||||
});
|
||||
// 删除异常 → 删 mock + 刷新渲染/列表。
|
||||
QObject::connect(ca, &geopro::app::Column3DAnalysis::anomalyDeleteRequested, &window,
|
||||
[scene3dRepo, refreshAnomalies](const QString& id) {
|
||||
scene3dRepo->deleteAnomaly(
|
||||
id.toStdString(), [refreshAnomalies]() { refreshAnomalies(); },
|
||||
[](const std::string&) {});
|
||||
});
|
||||
// 异常双击属性(R83)/右键删除已并入 analysisTab 的 detailRequested(dd_anomaly) /
|
||||
// deleteDatasetRequested(dd_anomaly);列表选中→VTK高亮(R84)随旧栏退役暂缺,待新段补 anomalySelected。
|
||||
|
||||
// ── 二维数据集栏:天地图底图开关(③,复用轨迹图 token,经同一共享 GeoLocalFrame 配准)──
|
||||
auto* basemap = new geopro::app::TileBasemap(*scene, renderWindowPtr, frame, &window);
|
||||
|
|
@ -1055,12 +940,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
sceneView->onCameraChanged = [basemap]() { basemap->refresh(); };
|
||||
// 底图最大范围按当前勾选剖面合并范围动态定(随增删自动伸缩);刷新时实时查询。
|
||||
basemap->setDataRadiusProvider([sceneView]() { return sceneView->dataHorizontalRadius(); });
|
||||
// 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。
|
||||
QObject::connect(drawer->col3D(), &geopro::app::Column3DDataset::verticalExaggerationChanged,
|
||||
basemap, [basemap](double ve) { basemap->setVerticalExaggeration(ve); });
|
||||
// 单一来源:kVerticalExaggeration 一处定义,组合根下发到 控制器(上方259) / 底图 / UI 显示。
|
||||
// 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。单一来源 kVerticalExaggeration 下发
|
||||
// 控制器(上方)/底图;运行时 VE 改由坐标轴设置抽屉「应用」下发(旧三维数据集栏滑块已退役)。
|
||||
basemap->setVerticalExaggeration(kVerticalExaggeration);
|
||||
drawer->col3D()->setVerticalExaggeration(kVerticalExaggeration);
|
||||
// 坐标轴设置抽屉「应用」:轴显示开关 + 放大系数(=垂直夸张,下发控制器+底图);范围/单位待控制器 API。
|
||||
QObject::connect(axesPanel, &geopro::app::AxesSettingsPanel::applied, &window,
|
||||
[axesPanel, sceneCtrl, basemap](geopro::app::AxisRange x, geopro::app::AxisRange y,
|
||||
|
|
@ -1293,7 +1175,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
});
|
||||
|
||||
// ── 左上对象树勾选 → 拉取各 TM 的 ds 子树,按维度分发到三栏列表(spec §6.1/§8)──
|
||||
// 渲染由三栏勾选框驱动(Task 7:Column3DDataset::checkedDatasetsChanged → setCheckedDatasets)。
|
||||
// 渲染由分段勾选框驱动(Task 12:CategoryAnalysisTab::checkedDatasetsChanged → setCheckedDatasets)。
|
||||
auto generation = std::make_shared<unsigned long long>(0);
|
||||
QObject::connect(
|
||||
objectTree, &geopro::app::ObjectTreePanel::checkedSourcesChanged, &window,
|
||||
|
|
|
|||
|
|
@ -1,211 +0,0 @@
|
|||
#include "panels/columns/Column3DAnalysis.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
#include "EmptyAwareComboBox.hpp"
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QSet>
|
||||
#include <QSignalBlocker>
|
||||
#include <QSplitter>
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QTreeWidgetItemIterator>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Theme.hpp"
|
||||
#include "panels/DatasetListPanel.hpp"
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
Column3DAnalysis::Column3DAnalysis(QWidget* parent) : QWidget(parent) {
|
||||
auto* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(space::kMd, space::kMd, space::kMd, space::kMd);
|
||||
root->setSpacing(space::kMd);
|
||||
|
||||
tree_ = new QTreeWidget();
|
||||
tree_->setHeaderHidden(true);
|
||||
tree_->setRootIsDecorated(true);
|
||||
applyDatasetCardDelegate(tree_);
|
||||
tree_->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(tree_, &QTreeWidget::customContextMenuRequested, this, &Column3DAnalysis::onContextMenu);
|
||||
|
||||
connect(tree_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem*, int) {
|
||||
QStringList ids;
|
||||
for (QTreeWidgetItemIterator it(tree_); *it; ++it) {
|
||||
if ((*it)->checkState(0) == Qt::Checked)
|
||||
ids << (*it)->data(0, kDsIdRole).toString();
|
||||
}
|
||||
emit checkedItemsChanged(ids);
|
||||
});
|
||||
|
||||
// ── 数据集树(上) + 「异常」分组(下) 放进竖向 Splitter:可拖拽、清晰分隔,数据集树占多数 ──
|
||||
// ── 3D 异常控制(#4c):分组框内含 显示过滤下拉 + 异常列表(每条显隐勾选;选中联动 VTK)──
|
||||
anomalyTree_ = new QTreeWidget();
|
||||
anomalyTree_->setHeaderHidden(true);
|
||||
anomalyTree_->setRootIsDecorated(false);
|
||||
anomalyTree_->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(anomalyTree_, &QTreeWidget::customContextMenuRequested, this,
|
||||
&Column3DAnalysis::onAnomalyContextMenu);
|
||||
connect(anomalyTree_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem* it, int) {
|
||||
if (it == nullptr) return;
|
||||
emit anomalyVisibilityChanged(it->data(0, kDsIdRole).toString(),
|
||||
it->checkState(0) == Qt::Checked);
|
||||
});
|
||||
connect(anomalyTree_, &QTreeWidget::currentItemChanged, this,
|
||||
[this](QTreeWidgetItem* cur, QTreeWidgetItem*) {
|
||||
if (cur != nullptr) emit anomalySelected(cur->data(0, kDsIdRole).toString());
|
||||
});
|
||||
// 双击异常项 → 属性对话框(R83):按 id 回查当前集合发出整条异常。
|
||||
connect(anomalyTree_, &QTreeWidget::itemDoubleClicked, this,
|
||||
[this](QTreeWidgetItem* it, int) {
|
||||
if (it == nullptr) return;
|
||||
const QString id = it->data(0, kDsIdRole).toString();
|
||||
for (const auto& a : anomalies_)
|
||||
if (QString::fromStdString(a.id) == id) {
|
||||
emit anomalyPropertiesRequested(a);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
auto* anomGroup = new QGroupBox(QStringLiteral("异常"));
|
||||
auto* gv = new QVBoxLayout(anomGroup);
|
||||
gv->setContentsMargins(space::kSm, space::kSm, space::kSm, space::kSm);
|
||||
gv->setSpacing(space::kSm);
|
||||
{
|
||||
auto* fr = new QHBoxLayout();
|
||||
fr->addWidget(new QLabel(QStringLiteral("显示")));
|
||||
anomalyFilter_ = new EmptyAwareComboBox();
|
||||
anomalyFilter_->addItem(QStringLiteral("全部显示")); // 0
|
||||
anomalyFilter_->addItem(QStringLiteral("随GS")); // 1
|
||||
anomalyFilter_->addItem(QStringLiteral("随数据集")); // 2
|
||||
anomalyFilter_->addItem(QStringLiteral("全部隐藏")); // 3
|
||||
anomalyFilter_->setCurrentIndex(2); // 默认随数据集(= 跟当前三维体显隐)
|
||||
connect(anomalyFilter_, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
[this](int idx) { emit anomalyDisplayFilterChanged(idx); });
|
||||
fr->addWidget(anomalyFilter_, 1);
|
||||
gv->addLayout(fr);
|
||||
}
|
||||
gv->addWidget(anomalyTree_, 1);
|
||||
|
||||
auto* splitter = new QSplitter(Qt::Vertical);
|
||||
splitter->setChildrenCollapsible(false);
|
||||
splitter->addWidget(tree_);
|
||||
splitter->addWidget(anomGroup);
|
||||
splitter->setStretchFactor(0, 3); // 数据集树占多
|
||||
splitter->setStretchFactor(1, 2);
|
||||
root->addWidget(splitter, 1);
|
||||
}
|
||||
|
||||
int Column3DAnalysis::anomalyFilterMode() const {
|
||||
return anomalyFilter_ ? anomalyFilter_->currentIndex() : 2;
|
||||
}
|
||||
|
||||
void Column3DAnalysis::setAnomalies(const std::vector<geopro::core::Anomaly>& anoms) {
|
||||
anomalies_ = anoms; // 留存供双击查属性(R83)
|
||||
QSignalBlocker block(anomalyTree_); // 填充不触发 visibilityChanged
|
||||
anomalyTree_->clear();
|
||||
for (const auto& a : anoms) {
|
||||
auto* item = new QTreeWidgetItem(anomalyTree_);
|
||||
const QString name = a.name.empty() ? QStringLiteral("异常") : QString::fromStdString(a.name);
|
||||
const QString type = a.typeName.empty() ? QString() : QString::fromStdString(a.typeName);
|
||||
item->setText(0, type.isEmpty() ? name : QStringLiteral("%1(%2)").arg(name, type));
|
||||
item->setData(0, kDsIdRole, QString::fromStdString(a.id));
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(0, Qt::Checked); // 默认显示
|
||||
}
|
||||
}
|
||||
|
||||
void Column3DAnalysis::onAnomalyContextMenu(const QPoint& pos) {
|
||||
QTreeWidgetItem* it = anomalyTree_->itemAt(pos);
|
||||
if (it == nullptr) return;
|
||||
const QString id = it->data(0, kDsIdRole).toString();
|
||||
QMenu menu(this);
|
||||
menu.addAction(QStringLiteral("删除异常"), this, [this, id] { emit anomalyDeleteRequested(id); });
|
||||
menu.exec(anomalyTree_->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void Column3DAnalysis::setDatasets(const std::vector<geopro::data::DsRow>& rows) {
|
||||
// 按 dsId 保留刷新前的勾选态:列表重建(保存切片/生成体追加一行也会整树重建)不应丢已勾选项
|
||||
// 的渲染态——否则保存切片会连带取消三维体勾选、把它从场景移除(实测 bug)。
|
||||
// 切换测线(新数据)时旧 id 不匹配 → 自然全空,行为与原先一致。
|
||||
QSet<QString> wasChecked;
|
||||
for (QTreeWidgetItemIterator it(tree_); *it; ++it)
|
||||
if ((*it)->checkState(0) == Qt::Checked)
|
||||
wasChecked.insert((*it)->data(0, kDsIdRole).toString());
|
||||
|
||||
{
|
||||
QSignalBlocker blocker(tree_);
|
||||
populateDatasetList(tree_, rows, /*append=*/false);
|
||||
for (QTreeWidgetItemIterator it(tree_); *it; ++it) {
|
||||
(*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable);
|
||||
const QString id = (*it)->data(0, kDsIdRole).toString();
|
||||
(*it)->setCheckState(0, wasChecked.contains(id) ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
} // blocker released here
|
||||
// 仅当勾选集真正变化才发信号:重建但勾选集不变(如保存切片仅追加一行)→ 不发,
|
||||
// 避免下游 syncSlices 用"尚未勾选新切片"的中间态误隐藏刚链接的切片(闪烁/重复)。
|
||||
QStringList ids;
|
||||
QSet<QString> nowChecked;
|
||||
for (QTreeWidgetItemIterator it(tree_); *it; ++it)
|
||||
if ((*it)->checkState(0) == Qt::Checked) {
|
||||
const QString id = (*it)->data(0, kDsIdRole).toString();
|
||||
ids << id;
|
||||
nowChecked.insert(id);
|
||||
}
|
||||
if (nowChecked != wasChecked) emit checkedItemsChanged(ids);
|
||||
}
|
||||
|
||||
void Column3DAnalysis::setItemChecked(const QString& dsId, bool checked) {
|
||||
for (QTreeWidgetItemIterator it(tree_); *it; ++it) {
|
||||
if ((*it)->data(0, kDsIdRole).toString() != dsId) continue;
|
||||
for (QTreeWidgetItem* p = (*it)->parent(); p != nullptr; p = p->parent())
|
||||
p->setExpanded(true); // 展开父链 → 新勾选行可见
|
||||
// setCheckState 仅在状态变化时发 itemChanged → checkedItemsChanged(驱动渲染同步)。
|
||||
(*it)->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Column3DAnalysis::onContextMenu(const QPoint& pos) {
|
||||
QTreeWidgetItem* it = tree_->itemAt(pos);
|
||||
if (!it) return;
|
||||
|
||||
const QString dsId = it->data(0, kDsIdRole).toString();
|
||||
const QString ddCode = it->data(0, kDsDdCodeRole).toString();
|
||||
const QString name = it->data(0, kDsNameRole).toString();
|
||||
const bool isSlice = (ddCode == QStringLiteral("dd_slice"));
|
||||
|
||||
QMenu menu(this);
|
||||
if (!isSlice) {
|
||||
// 三维体数据集:切片▸(上下/前后/左右/任意) / 色阶 / 数据详情。
|
||||
// 显示/隐藏 = 勾选框,故菜单不再重复提供(去冗余)。
|
||||
QMenu* sub = menu.addMenu(QStringLiteral("切片"));
|
||||
using SA = geopro::render::interact::SliceAxis;
|
||||
sub->addAction(QStringLiteral("上下"), this, [this]{ emit sliceRequested(SA::UpDown); });
|
||||
sub->addAction(QStringLiteral("前后"), this, [this]{ emit sliceRequested(SA::FrontBack); });
|
||||
sub->addAction(QStringLiteral("左右"), this, [this]{ emit sliceRequested(SA::LeftRight); });
|
||||
sub->addAction(QStringLiteral("任意"), this, [this]{ emit sliceRequested(SA::Oblique); });
|
||||
menu.addAction(QStringLiteral("色阶"), this, [this, dsId]{ emit colorScaleRequested(dsId); });
|
||||
menu.addAction(QStringLiteral("数据详情"), this, [this, dsId, ddCode, name]{ emit detailRequested(dsId, ddCode, name); });
|
||||
} else {
|
||||
// 切片数据集:保存(覆盖位姿) / 保存为(另存新切片) / 导出▸(图片·dat) / 删除 / 色阶 / 数据详情。
|
||||
// 显示/隐藏 = 勾选框,去冗余。导出与 VTK 视图切片右键统一为二级菜单。
|
||||
menu.addAction(QStringLiteral("保存"), this, [this, dsId]{ emit sliceSaveRequested(dsId); });
|
||||
menu.addAction(QStringLiteral("保存为"), this, [this, dsId]{ emit sliceSaveAsRequested(dsId); });
|
||||
QMenu* exp = menu.addMenu(QStringLiteral("导出"));
|
||||
exp->addAction(QStringLiteral("图片"), this, [this, dsId]{ emit sliceExportImageRequested(dsId); });
|
||||
exp->addAction(QStringLiteral("dat"), this, [this, dsId]{ emit sliceExportDatRequested(dsId); });
|
||||
menu.addAction(QStringLiteral("删除"), this, [this, dsId]{ emit sliceDeleteRequested(dsId); });
|
||||
menu.addSeparator();
|
||||
menu.addAction(QStringLiteral("色阶"), this, [this, dsId]{ emit colorScaleRequested(dsId); });
|
||||
menu.addAction(QStringLiteral("数据详情"), this, [this, dsId, ddCode, name]{ emit detailRequested(dsId, ddCode, name); });
|
||||
}
|
||||
|
||||
menu.exec(tree_->viewport()->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
} // namespace geopro::app
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <QStringList>
|
||||
#include <vector>
|
||||
#include "repo/RepoTypes.hpp"
|
||||
#include "model/Anomaly.hpp"
|
||||
#include "interact/SlicePlaneMath.hpp" // SliceAxis
|
||||
|
||||
class QTreeWidget;
|
||||
class QComboBox;
|
||||
class QPoint;
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
// 三维分析栏:对象→三维体模型→切片 树 + 三维体/切片两套右键菜单 + 3D 异常控制(列表/过滤/显隐)。
|
||||
class Column3DAnalysis : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Column3DAnalysis(QWidget* parent = nullptr);
|
||||
// 本期:按 ds parentId 建树(切片挂源数据下);完整 对象→三维体→切片 三级树待后端数据(P4)。
|
||||
void setDatasets(const std::vector<geopro::data::DsRow>& rows); // Analysis 维度(三维体/切片)
|
||||
// 程序化勾选某 dsId 的行(保存切片后自动勾选新行)+ 展开其父节点使可见。
|
||||
void setItemChecked(const QString& dsId, bool checked);
|
||||
// 3D 异常列表(#4c):每条带显隐勾选;选中联动 VTK。anoms 为当前应展示的异常集合。
|
||||
void setAnomalies(const std::vector<geopro::core::Anomaly>& anoms);
|
||||
// 当前显示过滤档位(0全部显示/1随GS/2随数据集/3全部隐藏)。
|
||||
int anomalyFilterMode() const;
|
||||
|
||||
signals:
|
||||
void sliceRequested(geopro::render::interact::SliceAxis axis); // 三维体右键 切片▸(上下/前后/左右/任意)
|
||||
void colorScaleRequested(const QString& dsId);
|
||||
void detailRequested(const QString& dsId, const QString& ddCode, const QString& name);
|
||||
void sliceSaveRequested(const QString& dsId);
|
||||
void sliceSaveAsRequested(const QString& dsId);
|
||||
void sliceExportImageRequested(const QString& dsId); // 导出▸图片
|
||||
void sliceExportDatRequested(const QString& dsId); // 导出▸dat
|
||||
void sliceDeleteRequested(const QString& dsId);
|
||||
void checkedItemsChanged(const QStringList& dsIds);
|
||||
// ── 异常(#4c)──
|
||||
void anomalyVisibilityChanged(const QString& anomalyId, bool visible); // 单条显隐勾选
|
||||
void anomalyDisplayFilterChanged(int mode); // 过滤档位 0..3
|
||||
void anomalySelected(const QString& anomalyId); // 列表选中→VTK 高亮
|
||||
void anomalyDeleteRequested(const QString& anomalyId); // 右键删除
|
||||
void anomalyPropertiesRequested(const geopro::core::Anomaly& a); // 双击→属性对话框(R83)
|
||||
|
||||
private:
|
||||
void onContextMenu(const QPoint& pos);
|
||||
void onAnomalyContextMenu(const QPoint& pos);
|
||||
QTreeWidget* tree_ = nullptr;
|
||||
QTreeWidget* anomalyTree_ = nullptr;
|
||||
QComboBox* anomalyFilter_ = nullptr;
|
||||
std::vector<geopro::core::Anomaly> anomalies_; // 当前展示集合(双击查属性按 id 回查)
|
||||
};
|
||||
|
||||
} // namespace geopro::app
|
||||
|
|
@ -1,187 +0,0 @@
|
|||
#include "panels/columns/Column3DDataset.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QAbstractItemView>
|
||||
#include <QAction>
|
||||
#include <QComboBox>
|
||||
|
||||
#include "EmptyAwareComboBox.hpp"
|
||||
#include <QDebug>
|
||||
#include <QFormLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QPoint>
|
||||
#include <QPushButton>
|
||||
#include <QSet>
|
||||
#include <QSignalBlocker>
|
||||
#include <QSlider>
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItemIterator>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "Theme.hpp"
|
||||
#include "panels/DatasetListPanel.hpp"
|
||||
|
||||
using geopro::controller::AxesMode;
|
||||
using geopro::controller::AxesUnit;
|
||||
using geopro::controller::ViewDir;
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
Column3DDataset::Column3DDataset(QWidget* parent) : QWidget(parent) {
|
||||
auto* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(space::kMd, space::kMd, space::kMd, space::kMd);
|
||||
root->setSpacing(space::kMd);
|
||||
|
||||
// 坐标轴设置
|
||||
{
|
||||
auto* form = new QFormLayout();
|
||||
auto* mode = new EmptyAwareComboBox();
|
||||
mode->addItem(QStringLiteral("标准"), static_cast<int>(AxesMode::Standard));
|
||||
mode->addItem(QStringLiteral("三维立体"), static_cast<int>(AxesMode::Stereo));
|
||||
mode->addItem(QStringLiteral("不显示"), static_cast<int>(AxesMode::None));
|
||||
connect(mode, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
[this, mode](int) { emit axesModeChanged(static_cast<AxesMode>(mode->currentData().toInt())); });
|
||||
auto* oPoint = new QPushButton(QStringLiteral("设置…"));
|
||||
connect(oPoint, &QPushButton::clicked, this, &Column3DDataset::oPointClicked);
|
||||
auto* unit = new EmptyAwareComboBox();
|
||||
unit->addItem(QStringLiteral("无刻度"), static_cast<int>(AxesUnit::None));
|
||||
unit->addItem(QStringLiteral("米"), static_cast<int>(AxesUnit::Meter));
|
||||
unit->addItem(QStringLiteral("英尺"), static_cast<int>(AxesUnit::Feet));
|
||||
unit->addItem(QStringLiteral("经纬度"), static_cast<int>(AxesUnit::LatLon));
|
||||
unit->setCurrentIndex(1);
|
||||
connect(unit, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
[this, unit](int) { emit axesUnitChanged(static_cast<AxesUnit>(unit->currentData().toInt())); });
|
||||
auto* font = new QPushButton(QStringLiteral("设置…"));
|
||||
connect(font, &QPushButton::clicked, this, &Column3DDataset::fontClicked);
|
||||
form->addRow(QStringLiteral("显示方式"), mode);
|
||||
form->addRow(QStringLiteral("O点位置"), oPoint);
|
||||
form->addRow(QStringLiteral("刻度"), unit);
|
||||
form->addRow(QStringLiteral("字体"), font);
|
||||
root->addWidget(new QLabel(QStringLiteral("坐标轴设置")));
|
||||
root->addLayout(form);
|
||||
}
|
||||
|
||||
// 水平/垂直比例(单滑块 + 数值)。初值为中性 1×(无夸张);实际配置默认由组合根 setVerticalExaggeration 下发。
|
||||
{
|
||||
auto* row = new QHBoxLayout();
|
||||
veSlider_ = new QSlider(Qt::Horizontal);
|
||||
veSlider_->setMinimum(1);
|
||||
veSlider_->setMaximum(10);
|
||||
veSlider_->setValue(1);
|
||||
veLabel_ = new QLabel(QStringLiteral("1.0×"));
|
||||
connect(veSlider_, &QSlider::valueChanged, this, [this](int v) {
|
||||
veLabel_->setText(QStringLiteral("%1.0×").arg(v));
|
||||
emit verticalExaggerationChanged(static_cast<double>(v));
|
||||
});
|
||||
row->addWidget(veSlider_, 1);
|
||||
row->addWidget(veLabel_);
|
||||
root->addWidget(new QLabel(QStringLiteral("水平/垂直比例")));
|
||||
root->addLayout(row);
|
||||
}
|
||||
|
||||
// 快捷视图
|
||||
{
|
||||
auto* row = new QHBoxLayout();
|
||||
struct V {
|
||||
const char* t;
|
||||
ViewDir d;
|
||||
};
|
||||
const V views[] = {
|
||||
{"前", ViewDir::Front}, {"后", ViewDir::Back}, {"左", ViewDir::Left},
|
||||
{"右", ViewDir::Right}, {"上", ViewDir::Top}, {"下", ViewDir::Bottom},
|
||||
};
|
||||
for (const V& v : views) {
|
||||
auto* b = new QPushButton(QString::fromUtf8(v.t));
|
||||
ViewDir d = v.d;
|
||||
connect(b, &QPushButton::clicked, this, [this, d] { emit viewRequested(d); });
|
||||
row->addWidget(b);
|
||||
}
|
||||
root->addWidget(new QLabel(QStringLiteral("快捷视图")));
|
||||
root->addLayout(row);
|
||||
}
|
||||
|
||||
// 缩放
|
||||
{
|
||||
auto* row = new QHBoxLayout();
|
||||
auto* in = new QPushButton(QStringLiteral("放大"));
|
||||
auto* out = new QPushButton(QStringLiteral("缩小"));
|
||||
auto* fit = new QPushButton(QStringLiteral("适配"));
|
||||
connect(in, &QPushButton::clicked, this, &Column3DDataset::zoomInRequested);
|
||||
connect(out, &QPushButton::clicked, this, &Column3DDataset::zoomOutRequested);
|
||||
connect(fit, &QPushButton::clicked, this, &Column3DDataset::fitRequested);
|
||||
row->addWidget(in);
|
||||
row->addWidget(out);
|
||||
row->addWidget(fit);
|
||||
root->addWidget(new QLabel(QStringLiteral("缩放")));
|
||||
root->addLayout(row);
|
||||
}
|
||||
|
||||
// 数据集列表(可勾选)。勾选 = 渲染为帘面,同时是「生成三维体」的源集合(右键菜单据勾选集生成)。
|
||||
list_ = new QTreeWidget();
|
||||
list_->setHeaderHidden(true);
|
||||
list_->setRootIsDecorated(true);
|
||||
list_->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
applyDatasetCardDelegate(list_);
|
||||
connect(list_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem*, int) {
|
||||
QStringList ids;
|
||||
for (QTreeWidgetItemIterator it(list_); *it; ++it) {
|
||||
if ((*it)->checkState(0) == Qt::Checked)
|
||||
ids << (*it)->data(0, kDsIdRole).toString();
|
||||
}
|
||||
emit checkedDatasetsChanged(ids);
|
||||
});
|
||||
connect(list_, &QTreeWidget::customContextMenuRequested, this,
|
||||
&Column3DDataset::showListContextMenu);
|
||||
root->addWidget(list_, 1);
|
||||
}
|
||||
|
||||
void Column3DDataset::showListContextMenu(const QPoint& pos) {
|
||||
// 按**勾选集合**收集"可作三维体源"的数据集(反演剖面类)——与右键点在哪一项无关。
|
||||
static const QSet<QString> kSourceDdCodes = {QStringLiteral("dd_section"),
|
||||
QStringLiteral("dd_inversion_data")};
|
||||
QStringList sourceIds;
|
||||
for (QTreeWidgetItemIterator it(list_); *it; ++it) {
|
||||
if ((*it)->checkState(0) != Qt::Checked) continue; // 仅勾选项
|
||||
const QString ddCode = (*it)->data(0, kDsDdCodeRole).toString();
|
||||
if (kSourceDdCodes.contains(ddCode))
|
||||
sourceIds << (*it)->data(0, kDsIdRole).toString();
|
||||
}
|
||||
qInfo().noquote() << "[volsrc] 按勾选收集源 ds 数 =" << sourceIds.size() << ":"
|
||||
<< sourceIds.join(',');
|
||||
|
||||
QMenu menu(this);
|
||||
QAction* gen = menu.addAction(QStringLiteral("生成三维体"));
|
||||
gen->setEnabled(!sourceIds.isEmpty()); // 无可作源选中 → 灰显(提示需选反演剖面)
|
||||
QAction* chosen = menu.exec(list_->viewport()->mapToGlobal(pos));
|
||||
if (chosen == gen && !sourceIds.isEmpty())
|
||||
emit generateVolumeRequested(sourceIds);
|
||||
}
|
||||
|
||||
void Column3DDataset::setVerticalExaggeration(double ve) {
|
||||
const int v = std::max(1, static_cast<int>(ve + 0.5));
|
||||
QSignalBlocker block(veSlider_); // 仅同步 UI 显示;传播由组合根分发,避免重复发信号
|
||||
veSlider_->setValue(v);
|
||||
veLabel_->setText(QStringLiteral("%1.0×").arg(v));
|
||||
}
|
||||
|
||||
void Column3DDataset::setDatasets(const std::vector<geopro::data::DsRow>& rows) {
|
||||
{
|
||||
QSignalBlocker blocker(list_);
|
||||
populateDatasetList(list_, rows, /*append=*/false);
|
||||
for (QTreeWidgetItemIterator it(list_); *it; ++it) {
|
||||
(*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable);
|
||||
(*it)->setCheckState(0, Qt::Unchecked);
|
||||
}
|
||||
} // blocker released here
|
||||
// 填充后统一发一次(新载入必为空选):清掉上一次的渲染勾选
|
||||
QStringList ids;
|
||||
for (QTreeWidgetItemIterator it(list_); *it; ++it)
|
||||
if ((*it)->checkState(0) == Qt::Checked)
|
||||
ids << (*it)->data(0, kDsIdRole).toString();
|
||||
emit checkedDatasetsChanged(ids);
|
||||
}
|
||||
|
||||
} // namespace geopro::app
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <QStringList>
|
||||
#include <vector>
|
||||
#include "I3dSceneView.hpp" // AxesMode/AxesUnit/ViewDir
|
||||
#include "repo/RepoTypes.hpp"
|
||||
|
||||
class QTreeWidget;
|
||||
class QSlider;
|
||||
class QLabel;
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
// 三维数据集栏:坐标轴设置 + 水平/垂直比例 + 快捷视图 + 缩放 + 3D 数据集列表。
|
||||
class Column3DDataset : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Column3DDataset(QWidget* parent = nullptr);
|
||||
void setDatasets(const std::vector<geopro::data::DsRow>& rows);
|
||||
void setVerticalExaggeration(double ve); // 组合根下发配置默认值(仅同步UI显示,不重复发信号)
|
||||
|
||||
signals:
|
||||
void axesModeChanged(geopro::controller::AxesMode mode);
|
||||
void axesUnitChanged(geopro::controller::AxesUnit unit);
|
||||
void verticalExaggerationChanged(double ve);
|
||||
void viewRequested(geopro::controller::ViewDir dir);
|
||||
void zoomInRequested();
|
||||
void zoomOutRequested();
|
||||
void fitRequested();
|
||||
void oPointClicked();
|
||||
void fontClicked();
|
||||
void checkedDatasetsChanged(const QStringList& dsIds);
|
||||
// 右键「生成三维体」:选中的源数据集 id(≥1,均为可作源类型)→ 组合根弹参数对话框 + 客户端插值。
|
||||
void generateVolumeRequested(const QStringList& sourceDsIds);
|
||||
|
||||
private:
|
||||
// 右键菜单:选中可作源数据集(dd_section / dd_inversion_data)时提供「生成三维体」。
|
||||
void showListContextMenu(const QPoint& pos);
|
||||
|
||||
QTreeWidget* list_ = nullptr;
|
||||
QSlider* veSlider_ = nullptr; // 水平/垂直比例滑块
|
||||
QLabel* veLabel_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace geopro::app
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
#include "panels/columns/ColumnDrawer.hpp"
|
||||
#include "panels/columns/Column3DDataset.hpp"
|
||||
#include "panels/columns/Column2DDataset.hpp"
|
||||
#include "panels/columns/Column3DAnalysis.hpp"
|
||||
#include "panels/columns/CategoryAnalysisTab.hpp"
|
||||
#include "Glyphs.hpp"
|
||||
#include "Theme.hpp"
|
||||
|
|
@ -16,11 +14,6 @@ ColumnDrawer::ColumnDrawer(QWidget* parent, geopro::data::DatasetFieldDictionary
|
|||
{
|
||||
col2D_ = new Column2DDataset(this);
|
||||
analysisTab_ = new CategoryAnalysisTab(dict, this);
|
||||
// 过渡:旧三维数据集/三维分析栏仍实例化以兼容 main 现有接线,但隐藏、不入 tab(Task 12 退役)。
|
||||
col3D_ = new Column3DDataset(this);
|
||||
colAnalysis_ = new Column3DAnalysis(this);
|
||||
col3D_->hide();
|
||||
colAnalysis_->hide();
|
||||
|
||||
// Tab 容器(body_):两 tab(三维分析[分段] / 二维分析)。
|
||||
auto* tabs = new QTabWidget(this);
|
||||
|
|
|
|||
|
|
@ -9,22 +9,17 @@ class DatasetFieldDictionary;
|
|||
|
||||
namespace geopro::app {
|
||||
|
||||
class Column3DDataset;
|
||||
class Column2DDataset;
|
||||
class Column3DAnalysis;
|
||||
class CategoryAnalysisTab;
|
||||
|
||||
// VTK视图左侧内嵌抽屉:两 tab(三维分析[按数据类型分段]/二维分析) + 折叠开关。
|
||||
// 旧 col3D_/colAnalysis_ 仍实例化但隐藏(不入 tab),保留访问器供 main 现有接线过渡,Task 12 退役。
|
||||
class ColumnDrawer : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ColumnDrawer(QWidget* parent = nullptr,
|
||||
geopro::data::DatasetFieldDictionary* dict = nullptr);
|
||||
|
||||
Column3DDataset* col3D() const { return col3D_; } // 【过渡,Task 12 删】
|
||||
Column2DDataset* col2D() const { return col2D_; }
|
||||
Column3DAnalysis* colAnalysis() const { return colAnalysis_; } // 【过渡,Task 12 删】
|
||||
CategoryAnalysisTab* analysisTab() const { return analysisTab_; }
|
||||
|
||||
public slots:
|
||||
|
|
@ -32,9 +27,7 @@ public slots:
|
|||
void expand(); // 强制展开(进入全屏时确保三栏可见)
|
||||
|
||||
private:
|
||||
Column3DDataset* col3D_ = nullptr; // 【过渡,隐藏不入 tab,Task 12 删】
|
||||
Column2DDataset* col2D_ = nullptr;
|
||||
Column3DAnalysis* colAnalysis_ = nullptr; // 【过渡,隐藏不入 tab,Task 12 删】
|
||||
CategoryAnalysisTab* analysisTab_ = nullptr;
|
||||
QWidget* body_ = nullptr; // QTabWidget,折叠时隐藏
|
||||
QPushButton* toggleBtn_ = nullptr;
|
||||
|
|
|
|||
Loading…
Reference in New Issue