From 5e57d462c8c680100cdd02e5cf0bfa170cb75ad5 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Tue, 16 Jun 2026 15:49:10 +0800 Subject: [PATCH] =?UTF-8?q?refactor(vtk):=20=E5=88=A0=E4=B8=89=E6=B5=AE?= =?UTF-8?q?=E5=B1=82+=E5=88=86=E6=AE=B5=E5=88=87=E6=8D=A2,=E6=94=B9?= =?UTF-8?q?=E6=8C=82=E4=B8=89=E6=A0=8F=E6=8A=BD=E5=B1=89,=E6=8E=A5?= =?UTF-8?q?=E4=BF=A1=E5=8F=B7,=E4=B8=AD=E5=A4=AE=E6=94=B9=E5=90=8DVTK?= =?UTF-8?q?=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/main.cpp | 422 +++++++---------------------------------------- 1 file changed, 62 insertions(+), 360 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index 4b872d2..61825a3 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -116,6 +116,10 @@ #include "panels/ObjectAttrPanel.hpp" #include "panels/DatasetAttrPanel.hpp" #include "panels/ObjectExceptionPanel.hpp" +#include "panels/columns/ColumnDrawer.hpp" +#include "panels/columns/Column3DDataset.hpp" +#include "panels/columns/Column2DDataset.hpp" +#include "panels/columns/Column3DAnalysis.hpp" #include "CameraPreset.hpp" #include "ColorLutBuilder.hpp" @@ -186,59 +190,6 @@ private: QWidget* host_; }; -// 把浮层锚定在 host 右上角(P2 三维数据集栏工具条):随 host 尺寸变化重定位, -// 紧贴右边距 14px,置于 header 下方 12px。仅在浮层可见时移动(隐藏时不打扰)。 -class RightTopAnchor : public QObject { -public: - RightTopAnchor(QWidget* overlay, QWidget* host, QWidget* header) - : QObject(host), overlay_(overlay), host_(host), header_(header) - { - host_->installEventFilter(this); - } - -protected: - bool eventFilter(QObject* obj, QEvent* e) override - { - if (obj == host_ && (e->type() == QEvent::Resize || e->type() == QEvent::Show) && - overlay_->isVisible()) { - overlay_->adjustSize(); - overlay_->move(host_->width() - overlay_->width() - 14, header_->height() + 12); - overlay_->raise(); - } - return QObject::eventFilter(obj, e); - } - -private: - QWidget* overlay_; - QWidget* host_; - QWidget* header_; -}; - -// 浮层左下角锚定:随 host 尺寸变化贴左下(切片工具条用,评审 M4)。 -class BottomLeftAnchor : public QObject { -public: - BottomLeftAnchor(QWidget* overlay, QWidget* host) : QObject(host), overlay_(overlay), host_(host) - { - host_->installEventFilter(this); - } - -protected: - bool eventFilter(QObject* obj, QEvent* e) override - { - if (obj == host_ && (e->type() == QEvent::Resize || e->type() == QEvent::Show) && - overlay_->isVisible()) { - overlay_->adjustSize(); - overlay_->move(14, host_->height() - overlay_->height() - 14); - overlay_->raise(); - } - return QObject::eventFilter(obj, e); - } - -private: - QWidget* overlay_; - QWidget* host_; -}; - // 读取 RSA 公钥 PEM 全文(登录时密码加密用)。读不到返回空串,登录将报错。 std::string readPem(const std::string& path) { @@ -308,7 +259,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re // 安装自定义拾取样式 + 持活动切片。仅三维 + 有体素可用;切到二维 closeAll。 auto* interactionMgr = new geopro::render::interact::InteractionManager( renderWindowPtr->GetInteractor(), renderWindowPtr, scene->renderer()); - // sceneView->onVolumeChanged 在切片 UI 接线处统一设置(需 updateSliceButtons 闭包,见下)。 + // sceneView->onVolumeChanged 在三栏接线处设置(把体素 image 推给 InteractionManager,见下)。 // 非 QObject 堆对象统一在此清理,按构造逆序: // interactionMgr(持 interactor/切片观察者) → sceneView(持 scene&) → scene3dRepo → scene。 // interactionMgr 先析构:closeAll() 解绑所有切片观察者,再拆 scene/interactor,防悬挂崩溃。 @@ -320,7 +271,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re delete scene; }); - // PROJ 可用性(体素/地形/切片层都需配准):失败则浮层相应勾选禁用并提示。 + // PROJ 可用性探测(体素/地形/切片层都需配准):三栏重构后浮层勾选已移除, + // 仅保留探测以便将来在三栏里据此禁用相关项;本期结果暂未消费。 bool crsAvailable = false; try { geopro::core::CrsTransform probe(kProjectCrs, kWgs84); @@ -328,6 +280,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re } catch (const std::exception&) { crsAvailable = false; } + (void)crsAvailable; // 停靠系统配置(必须在 CDockManager 构造前设置):对齐原型——面板固定、 // 标题栏不显示「关闭 / 浮动 / 标签菜单」等子窗口操作按钮,并关闭自动隐藏(钉住)。 @@ -371,234 +324,71 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re return box; }; - // 中央容器:顶部「二维地图/三维视图」工具条 + 下方 QVTK 视图。 + // 中央容器:顶部「VTK视图」表头 + 下方 [左三栏抽屉 | 右 QVTK 画布]。 auto* centerWidget = new QWidget(); auto* centerLayout = new QVBoxLayout(centerWidget); centerLayout->setContentsMargins(0, 0, 0, 0); centerLayout->setSpacing(0); - // 「二维地图/三维视图」分段切换表头:与「异常/属性」面板表头同款(42px 表头底 + 强调色下划线页签)。 - auto seg = geopro::app::buildSegmentedHeader( - {QStringLiteral("二维地图"), QStringLiteral("三维视图")}, - {{geopro::app::Glyph::Collapse, QStringLiteral("折叠")}, - {geopro::app::Glyph::Download, QStringLiteral("导出")}}); - auto* viewHeader = seg.header; - auto* act2D = seg.buttons[0]; - auto* act3D = seg.buttons[1]; + // VTK视图面板表头(Task 7):图标 + 标题「VTK视图」+ 全屏操作按钮(全屏 connect 见 Task 8)。 + auto* viewHeader = geopro::app::buildPanelHeader( + geopro::app::Glyph::Map, QStringLiteral("VTK视图"), + {{geopro::app::Glyph::Fullscreen, QStringLiteral("全屏")}}); + + // 左侧内嵌三栏抽屉(自带折叠按钮)+ 右侧 GL 画布,水平并列(非 GL 覆盖层,避免 z-order/圆角伪影)。 + auto* drawer = new geopro::app::ColumnDrawer(centerWidget); + auto* viewRow = new QHBoxLayout(); + viewRow->setContentsMargins(0, 0, 0, 0); + viewRow->setSpacing(0); + viewRow->addWidget(drawer); // 左侧抽屉(自带折叠按钮) + viewRow->addWidget(vtkWidget, 1); // 右侧 GL 画布 centerLayout->addWidget(viewHeader); - centerLayout->addWidget(vtkWidget, 1); + centerLayout->addLayout(viewRow, 1); - // ──「视图详情」图层浮层(对齐原型 3D 视图左上):浮在 QVTK 之上,控制三维图层显隐。 - // 仅三维视图显示;含 帘面 / 体素 勾选(体素=两交叉测线散点配准 IDW 的派生层,正确归宿)。 - auto* layerPanel = new QFrame(centerWidget); - layerPanel->setFrameShape(QFrame::StyledPanel); - geopro::app::applyTokenizedStyleSheet( - layerPanel, - // 不设 border-radius:浮层是 centerWidget 的子控件,悬于原生 GL 画布上,圆角四角处会 - // 露出父级浅底(浅色模式下即四个白直角)。改为直角矩形,不透明底铺满整块,无四角伪影。 - QStringLiteral("QFrame{background:{{canvas/bg-soft}};border:1px solid {{canvas/grid}};}" - "QCheckBox{padding:2px 1px;color:{{canvas/text}};}" - "QCheckBox:disabled{color:{{canvas/text-dim}};}")); - auto* layerLayout = new QVBoxLayout(layerPanel); - // 浮层内边距取间距令牌:左右 lg(12)、上下 ml(10),对称(原 13/10/15/11 是手调奇数)。 - layerLayout->setContentsMargins(geopro::app::space::kLg, geopro::app::space::kMl, - geopro::app::space::kLg, geopro::app::space::kMl); - layerLayout->setSpacing(geopro::app::space::kSm); - auto* layerTitle = new QLabel(QStringLiteral("视图详情")); - geopro::app::applyTokenizedStyleSheet( - layerTitle, QStringLiteral("font-weight:%1;color:{{canvas/text}};border:none;background:transparent;" - "padding-bottom:3px;font-size:%2px;") - .arg(geopro::app::type::kWeightSemibold) - .arg(geopro::app::scaledPx(geopro::app::type::kTitle))); - auto* chkCurtain = new QCheckBox(QStringLiteral("帘面(断面墙)")); - chkCurtain->setChecked(true); - auto* chkVoxel = new QCheckBox(QStringLiteral("体素(dd_voxel)")); - chkVoxel->setChecked(false); - auto* chkTerrain = new QCheckBox(QStringLiteral("地形(DEM+影像)")); - chkTerrain->setChecked(false); - // 切片交互已由 P3 左下「切片」工具条提供,此处不再放(原 P1 占位禁用项已移除)。 - if (!crsAvailable) { // PROJ 不可用 → 体素/地形层(都需配准)禁用并提示 - const QString tip = QStringLiteral("PROJ 数据(proj.db)缺失,配准不可用"); - chkVoxel->setEnabled(false); chkVoxel->setToolTip(tip); - chkTerrain->setEnabled(false); chkTerrain->setToolTip(tip); - } - layerLayout->addWidget(layerTitle); - layerLayout->addWidget(chkCurtain); - layerLayout->addWidget(chkVoxel); - layerLayout->addWidget(chkTerrain); - layerPanel->setVisible(false); // 默认二维,不显示图层浮层 - - // ──「三维数据集栏」工具条浮层(P2,spec §7.2):浮于 QVTK 右上,仅三维视图显示。 - // 坐标轴下拉(标准/立体/不显示) + 刻度下拉(无/米/英尺/经纬度) + 纵向比例滑块 + 快捷视图 6 钮 + Zoom(In/Out/Fit)。 - auto* axisBar = new QFrame(centerWidget); - axisBar->setFrameShape(QFrame::StyledPanel); - // 深色主题样式:控件须显式设深底(否则默认白底 + 浅字 → 看不清)。下拉弹窗(QAbstractItemView) - // 是独立顶层窗,须单独配色。与左上「视图详情」浮层同一套 canvas/* token。 - geopro::app::applyTokenizedStyleSheet( - axisBar, - QStringLiteral( - // 不设 border-radius:浮层悬于原生 GL 画布上,圆角四角会露父级浅底(四个白直角)。 - // 与左上「视图详情」浮层同法:直角矩形 + 不透明底铺满。 - "QFrame{background:{{canvas/bg-soft}};border:1px solid {{canvas/grid}};}" - "QLabel{color:{{canvas/text}};border:none;background:transparent;}" - "QComboBox{color:{{canvas/text}};background:{{canvas/bg}};border:1px solid {{canvas/grid}};" - "border-radius:4px;padding:2px 6px;}" - "QComboBox:hover{border-color:{{accent/primary}};}" - "QComboBox::drop-down{border:none;width:16px;}" - "QComboBox QAbstractItemView{color:{{canvas/text}};background:{{canvas/bg}};" - "border:1px solid {{canvas/grid}};selection-background-color:{{bg/selected}};" - "selection-color:{{canvas/text}};outline:none;}" - "QPushButton{color:{{canvas/text}};background:{{canvas/bg}};border:1px solid {{canvas/grid}};" - "border-radius:4px;padding:2px 8px;}" - "QPushButton:hover{background:{{bg/hover}};border-color:{{accent/primary}};}" - "QPushButton:pressed{background:{{bg/selected}};}" - "QSlider::groove:horizontal{height:4px;background:{{canvas/grid}};border-radius:2px;}" - "QSlider::handle:horizontal{width:12px;background:{{accent/primary}};" - "border-radius:6px;margin:-4px 0;}")); - auto* axisLayout = new QHBoxLayout(axisBar); - axisLayout->setContentsMargins(geopro::app::space::kMd, geopro::app::space::kSm, - geopro::app::space::kMd, geopro::app::space::kSm); - axisLayout->setSpacing(geopro::app::space::kSm); - - // 坐标轴显示方式下拉(枚举值绑到 itemData,槽用 currentData 取值,不依赖项顺序)。 - auto* axesModeCombo = new QComboBox(); - axesModeCombo->addItem(QStringLiteral("坐标轴:标准"), - static_cast(geopro::controller::AxesMode::Standard)); - axesModeCombo->addItem(QStringLiteral("坐标轴:三维立体"), - static_cast(geopro::controller::AxesMode::Stereo)); - axesModeCombo->addItem(QStringLiteral("坐标轴:不显示"), - static_cast(geopro::controller::AxesMode::None)); - // 刻度单位下拉。 - auto* axesUnitCombo = new QComboBox(); - axesUnitCombo->addItem(QStringLiteral("刻度:无"), - static_cast(geopro::controller::AxesUnit::None)); - axesUnitCombo->addItem(QStringLiteral("刻度:米"), - static_cast(geopro::controller::AxesUnit::Meter)); - axesUnitCombo->addItem(QStringLiteral("刻度:英尺"), - static_cast(geopro::controller::AxesUnit::Feet)); - axesUnitCombo->addItem(QStringLiteral("刻度:经纬度"), - static_cast(geopro::controller::AxesUnit::LatLon)); - axesUnitCombo->setCurrentIndex(1); // 默认米(与控制器默认一致) - // 纵向比例滑块(范围 1–10,默认 2;spec §4 C6)。 - auto* veLabel = new QLabel(QStringLiteral("比例")); - auto* veSlider = new QSlider(Qt::Horizontal); - veSlider->setMinimum(1); - veSlider->setMaximum(10); - veSlider->setValue(static_cast(kVerticalExaggeration)); - veSlider->setFixedWidth(80); - auto* veValue = new QLabel(QStringLiteral("%1x").arg(static_cast(kVerticalExaggeration))); - // 快捷视图 6 钮。 - auto* btnTop = new QPushButton(QStringLiteral("上")); - auto* btnBottom = new QPushButton(QStringLiteral("下")); - auto* btnFront = new QPushButton(QStringLiteral("前")); - auto* btnBack = new QPushButton(QStringLiteral("后")); - auto* btnLeft = new QPushButton(QStringLiteral("左")); - auto* btnRight = new QPushButton(QStringLiteral("右")); - // Zoom 3 钮。 - auto* btnZoomIn = new QPushButton(QStringLiteral("放大")); - auto* btnZoomOut = new QPushButton(QStringLiteral("缩小")); - auto* btnFit = new QPushButton(QStringLiteral("适配")); - - axisLayout->addWidget(axesModeCombo); - axisLayout->addWidget(axesUnitCombo); - axisLayout->addWidget(veLabel); - axisLayout->addWidget(veSlider); - axisLayout->addWidget(veValue); - axisLayout->addWidget(btnFront); - axisLayout->addWidget(btnBack); - axisLayout->addWidget(btnLeft); - axisLayout->addWidget(btnRight); - axisLayout->addWidget(btnTop); - axisLayout->addWidget(btnBottom); - axisLayout->addWidget(btnZoomIn); - axisLayout->addWidget(btnZoomOut); - axisLayout->addWidget(btnFit); - axisBar->setVisible(false); // 默认二维,不显示 - - // P2 工具条右上锚定:随 centerWidget 尺寸变化重定位(紧贴右边距 14px,工具条下方)。 - // 锚定器 parent=centerWidget,随其销毁;不需保留指针。 - new RightTopAnchor(axisBar, centerWidget, viewHeader); - - // ──「切片」工具条浮层(P3,spec §9):浮于 QVTK 左下,仅三维 + 有体素时可用。 - // 上下/前后/左右/任意 → 创建对应切片;关闭 → 关当前选中切片;翻转 → 水平 180°。 - // 深色主题复用 P2 工具条同款样式(canvas/* token,不设 border-radius,GL 上四角露浅底)。 - auto* sliceBar = new QFrame(centerWidget); - sliceBar->setFrameShape(QFrame::StyledPanel); - geopro::app::applyTokenizedStyleSheet( - sliceBar, - QStringLiteral( - "QFrame{background:{{canvas/bg-soft}};border:1px solid {{canvas/grid}};}" - "QLabel{color:{{canvas/text}};border:none;background:transparent;}" - "QPushButton{color:{{canvas/text}};background:{{canvas/bg}};border:1px solid {{canvas/grid}};" - "border-radius:4px;padding:2px 8px;}" - "QPushButton:hover{background:{{bg/hover}};border-color:{{accent/primary}};}" - "QPushButton:pressed{background:{{bg/selected}};}" - "QPushButton:disabled{color:{{canvas/text-dim}};border-color:{{canvas/grid}};}")); - auto* sliceLayout = new QHBoxLayout(sliceBar); - sliceLayout->setContentsMargins(geopro::app::space::kMd, geopro::app::space::kSm, - geopro::app::space::kMd, geopro::app::space::kSm); - sliceLayout->setSpacing(geopro::app::space::kSm); - auto* sliceLabel = new QLabel(QStringLiteral("切片")); - auto* btnSliceUpDown = new QPushButton(QStringLiteral("上下")); - auto* btnSliceFrontBack = new QPushButton(QStringLiteral("前后")); - auto* btnSliceLeftRight = new QPushButton(QStringLiteral("左右")); - auto* btnSliceOblique = new QPushButton(QStringLiteral("任意")); - auto* btnSliceFlip = new QPushButton(QStringLiteral("翻转")); - auto* btnSliceClose = new QPushButton(QStringLiteral("关闭")); - sliceLayout->addWidget(sliceLabel); - sliceLayout->addWidget(btnSliceUpDown); - sliceLayout->addWidget(btnSliceFrontBack); - sliceLayout->addWidget(btnSliceLeftRight); - sliceLayout->addWidget(btnSliceOblique); - sliceLayout->addWidget(btnSliceFlip); - sliceLayout->addWidget(btnSliceClose); - sliceBar->setVisible(false); // 默认二维,不显示 - new BottomLeftAnchor(sliceBar, centerWidget); // 随窗口 resize 贴左下(评审 M4) - - // 切片按钮可用性:仅三维 + 有体素时创建/翻转可用;关闭仅在有切片时可用。 - auto updateSliceButtons = [interactionMgr, btnSliceUpDown, btnSliceFrontBack, btnSliceLeftRight, - btnSliceOblique, btnSliceFlip, btnSliceClose, sceneView]() { - const bool canSlice = sceneView->hasVolume() && interactionMgr->hasVolume(); - btnSliceUpDown->setEnabled(canSlice); - btnSliceFrontBack->setEnabled(canSlice); - btnSliceLeftRight->setEnabled(canSlice); - btnSliceOblique->setEnabled(canSlice); - btnSliceFlip->setEnabled(canSlice); - btnSliceClose->setEnabled(interactionMgr->hasSlices()); - }; - updateSliceButtons(); - - using SliceAxis = geopro::render::interact::SliceAxis; - auto addSlice = [interactionMgr, updateSliceButtons](SliceAxis axis) { - interactionMgr->addSlice(axis); - updateSliceButtons(); - }; - QObject::connect(btnSliceUpDown, &QPushButton::clicked, vtkWidget, - [addSlice]() { addSlice(SliceAxis::UpDown); }); - QObject::connect(btnSliceFrontBack, &QPushButton::clicked, vtkWidget, - [addSlice]() { addSlice(SliceAxis::FrontBack); }); - QObject::connect(btnSliceLeftRight, &QPushButton::clicked, vtkWidget, - [addSlice]() { addSlice(SliceAxis::LeftRight); }); - QObject::connect(btnSliceOblique, &QPushButton::clicked, vtkWidget, - [addSlice]() { addSlice(SliceAxis::Oblique); }); - QObject::connect(btnSliceFlip, &QPushButton::clicked, vtkWidget, - [interactionMgr]() { interactionMgr->flipView(); }); - QObject::connect(btnSliceClose, &QPushButton::clicked, vtkWidget, - [interactionMgr, updateSliceButtons]() { - interactionMgr->closeSelected(); - updateSliceButtons(); - }); - // 体素变化(重建/清场)后刷新按钮可用性(切片可能已被 closeAll 清空)。 - sceneView->onVolumeChanged = [interactionMgr, sceneView, updateSliceButtons]() { + // 体素变化(重建/清场)后把体素 image 推给 InteractionManager(切片基底)。 + sceneView->onVolumeChanged = [interactionMgr, sceneView]() { if (sceneView->hasVolume()) interactionMgr->setVolumeImage(sceneView->currentVolumeImage(), sceneView->currentColorScale(), sceneView->currentVmin(), sceneView->currentVmax()); else interactionMgr->setVolumeImage(nullptr, sceneView->currentColorScale(), 0.0, 0.0); - updateSliceButtons(); }; + // ── 三栏抽屉信号 → 控制器/交互(Task 7 接线)────────────────────────────── + auto* c3 = drawer->col3D(); + 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); + QObject::connect(c3, &geopro::app::Column3DDataset::checkedDatasetsChanged, sceneCtrl, + &geopro::controller::VtkSceneController::setCheckedDatasets); + // 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: 字体弹框 */ }); + + auto* ca = drawer->colAnalysis(); + QObject::connect(ca, &geopro::app::Column3DAnalysis::sliceRequested, vtkWidget, + [interactionMgr](geopro::render::interact::SliceAxis axis) { + interactionMgr->addSlice(axis); + }); + QObject::connect(ca, &geopro::app::Column3DAnalysis::detailRequested, &detailCtrl, + [&detailCtrl](const QString& dsId, const QString& ddCode, const QString& name) { + detailCtrl.openDataset(dsId, ddCode, name); + }); + // ── 中央“空状态”引导浮层:未接入真实 sections 时,引导首次使用者从左侧入手。── // 透明背景 + 鼠标穿透(不挡 QVTK 交互);CenterOverlay 随视口尺寸保持居中; // 接入真实中央数据后改成依 sections 是否为空调 setVisible 即可。 @@ -645,7 +435,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re auto* emptyCentering = new CenterOverlay(emptyState, vtkWidget); emptyCentering->reposition(); - auto* vtkDock = new ads::CDockWidget(QStringLiteral("二维地图/三维视图")); + auto* vtkDock = new ads::CDockWidget(QStringLiteral("VTK视图")); vtkDock->setWidget(centerWidget); auto* centerDockArea = dockManager->addDockWidget(ads::CenterDockWidgetArea, vtkDock); @@ -799,95 +589,6 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re } }); - // 「视图详情」浮层 + 「三维数据集栏」工具条显隐:仅三维显示。 - // 视图详情浮层置左上;P2 工具条置右上(工具条下方),二者均随相机/数据变化保持位置。 - auto showLayerPanel = [layerPanel, axisBar, sliceBar, viewHeader, centerWidget, - updateSliceButtons](bool show3D) { - if (show3D) { - layerPanel->move(14, viewHeader->height() + 12); - layerPanel->adjustSize(); - layerPanel->setVisible(true); - layerPanel->raise(); - axisBar->adjustSize(); - // 右上对齐:紧贴右边距 14px。 - axisBar->move(centerWidget->width() - axisBar->width() - 14, viewHeader->height() + 12); - axisBar->setVisible(true); - axisBar->raise(); - // 切片工具条:左下角(视图详情浮层下方)。 - sliceBar->adjustSize(); - sliceBar->move(14, centerWidget->height() - sliceBar->height() - 14); - sliceBar->setVisible(true); - sliceBar->raise(); - updateSliceButtons(); - } else { - layerPanel->setVisible(false); - axisBar->setVisible(false); - sliceBar->setVisible(false); - } - }; - - // ── 工具条「二维地图/三维视图」:切换互斥视图 → 控制器重建 + 图层浮层显隐 ── - using geopro::controller::SceneLayer; - using CtrlViewMode = geopro::controller::ViewMode; - QObject::connect(act2D, &QAbstractButton::clicked, vtkWidget, - [sceneCtrl, showLayerPanel, interactionMgr, updateSliceButtons]() { - interactionMgr->closeAll(); // 切到二维:关闭所有切片(仅三维有切片) - updateSliceButtons(); - showLayerPanel(false); - sceneCtrl->setViewMode(CtrlViewMode::Map2D); - }); - QObject::connect(act3D, &QAbstractButton::clicked, vtkWidget, - [sceneCtrl, showLayerPanel]() { - showLayerPanel(true); - sceneCtrl->setViewMode(CtrlViewMode::View3D); - }); - - // ──「视图详情」图层勾选 → 控制器更新图层 → 重建中央 ── - QObject::connect(chkCurtain, &QCheckBox::toggled, vtkWidget, - [sceneCtrl](bool on) { sceneCtrl->setLayer(SceneLayer::Curtain, on); }); - QObject::connect(chkVoxel, &QCheckBox::toggled, vtkWidget, - [sceneCtrl](bool on) { sceneCtrl->setLayer(SceneLayer::Voxel, on); }); - QObject::connect(chkTerrain, &QCheckBox::toggled, vtkWidget, - [sceneCtrl](bool on) { sceneCtrl->setLayer(SceneLayer::Terrain, on); }); - - // ──「三维数据集栏」工具条 → 控制器槽(P2)── - using geopro::controller::AxesMode; - using geopro::controller::AxesUnit; - using geopro::controller::ViewDir; - QObject::connect(axesModeCombo, qOverload(&QComboBox::currentIndexChanged), sceneCtrl, - [sceneCtrl, axesModeCombo](int) { - sceneCtrl->setAxesMode( - static_cast(axesModeCombo->currentData().toInt())); - }); - QObject::connect(axesUnitCombo, qOverload(&QComboBox::currentIndexChanged), sceneCtrl, - [sceneCtrl, axesUnitCombo](int) { - sceneCtrl->setAxesUnit( - static_cast(axesUnitCombo->currentData().toInt())); - }); - QObject::connect(veSlider, &QSlider::valueChanged, sceneCtrl, - [sceneCtrl, veValue](int v) { - veValue->setText(QStringLiteral("%1x").arg(v)); - sceneCtrl->setVerticalExaggeration(static_cast(v)); - }); - QObject::connect(btnFront, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->applyView(ViewDir::Front); }); - QObject::connect(btnBack, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->applyView(ViewDir::Back); }); - QObject::connect(btnLeft, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->applyView(ViewDir::Left); }); - QObject::connect(btnRight, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->applyView(ViewDir::Right); }); - QObject::connect(btnTop, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->applyView(ViewDir::Top); }); - QObject::connect(btnBottom, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->applyView(ViewDir::Bottom); }); - QObject::connect(btnZoomIn, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->zoomIn(); }); - QObject::connect(btnZoomOut, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->zoomOut(); }); - QObject::connect(btnFit, &QPushButton::clicked, sceneCtrl, - [sceneCtrl]() { sceneCtrl->fit(); }); - // ── 左上对象树勾选 → 渲染勾选数据集(本期样本驱动:任意勾选 → 样本 ds "grid1",空 → 清场)── // 真实接 Api 时改为把勾选 TM 映射到其 ds 维度过滤后的真实 dsId 列表(spec §6.1/§8)。 QObject::connect(objectTree, &geopro::app::ObjectTreePanel::checkedTmsChanged, sceneCtrl, @@ -898,8 +599,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re hasData ? QStringList{QStringLiteral("grid1")} : QStringList{}); }); - // ── 启动:建立一次中央视图(默认 2D,无勾选 → 空场景 + 背景)。 - sceneCtrl->setViewMode(CtrlViewMode::Map2D); + // ── 启动:建立一次中央视图。三栏重构后删除了 2D/3D 切换,统一固定为三维视图 + // (帘面默认开启 showCurtain_=true,勾选 dd_section → 帘面)。无勾选 → 空场景 + 背景。 + sceneCtrl->setViewMode(geopro::controller::ViewMode::View3D); // VTK 背景随主题切换:控制器重渲染(走完整渲染路径、末尾必 Render)。 // context 用 sceneCtrl(非 window):ThemeManager 是进程级单例,连接须随 sceneCtrl 析构自动断开,