From 352e60d37b352472720f8a60dd906410d694ddba Mon Sep 17 00:00:00 2001 From: gaozheng Date: Tue, 30 Jun 2026 23:33:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(vtk):=202D=20=E6=AE=B5=20z=E5=80=BC?= =?UTF-8?q?=E6=BB=91=E5=9D=97=E6=95=B4=E4=BD=93=E5=8D=87=E9=99=8D=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=B9=B3=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/main.cpp | 3 ++ .../panels/columns/CategoryAnalysisTab.cpp | 1 + .../panels/columns/CategoryAnalysisTab.hpp | 1 + src/app/panels/columns/CategorySection.cpp | 36 +++++++++++++++++-- src/app/panels/columns/CategorySection.hpp | 4 ++- src/controller/DatasetRenderStrategy.cpp | 12 +++++++ src/controller/DatasetRenderStrategy.hpp | 2 ++ src/controller/VtkSceneController.cpp | 8 ++++- src/controller/VtkSceneController.hpp | 4 +++ 9 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index c0f3025..56c6dc2 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -1273,6 +1273,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re } renderWindowPtr->Render(); }); + // 2D 段「z 值」滑块 → 整体升降该 2D 类型平面(Plane2DRenderStrategy 重摆其全部足迹)。 + QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::planeZChanged, sceneCtrl, + &geopro::controller::VtkSceneController::setPlaneZ); // 反向 VTK→list:在 VTK 里点中/选中一张切片 → 在三维体段树里同步选中该切片行(②反向)。 // 点空白/清选(dsId 空) → 一并清 VTK 异常高亮(否则取消选中后异常图形仍高亮,用户反馈)。 interactionMgr->onSliceSelectionChanged = [drawer, sceneView, renderWindowPtr]( diff --git a/src/app/panels/columns/CategoryAnalysisTab.cpp b/src/app/panels/columns/CategoryAnalysisTab.cpp index 8c12088..7b8dbe1 100644 --- a/src/app/panels/columns/CategoryAnalysisTab.cpp +++ b/src/app/panels/columns/CategoryAnalysisTab.cpp @@ -68,6 +68,7 @@ CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* d connect(sec, &CategorySection::anomalyVisibilityChanged, this, &CategoryAnalysisTab::anomalyVisibilityChanged); connect(sec, &CategorySection::datasetSelected, this, &CategoryAnalysisTab::datasetSelected); + connect(sec, &CategorySection::planeZChanged, this, &CategoryAnalysisTab::planeZChanged); // #7:各段等分 stretch → 内容都少时四段平分高度填满面板(初始与 VTK 区等高、不出滚动条); // 某段内容增多时其最小高度(=内容总高)撑大,超出视口则由外层 QScrollArea 统一出纵向滚动条。 col->addWidget(sec, 1); diff --git a/src/app/panels/columns/CategoryAnalysisTab.hpp b/src/app/panels/columns/CategoryAnalysisTab.hpp index 61cabbe..faa476b 100644 --- a/src/app/panels/columns/CategoryAnalysisTab.hpp +++ b/src/app/panels/columns/CategoryAnalysisTab.hpp @@ -52,6 +52,7 @@ signals: void sliceExportDatRequested(const QString& dsId); void anomalyVisibilityChanged(const QString& dsId, bool vis); void datasetSelected(const QString& dsId, const QString& ddCode); // 树选中→VTK 高亮联动 + void planeZChanged(const QString& typeId, double z); // 2D 段 z 值滑块:整体升降该类型平面 private: void recomputeCheckedUnion(); diff --git a/src/app/panels/columns/CategorySection.cpp b/src/app/panels/columns/CategorySection.cpp index 3ef60a0..d26ad70 100644 --- a/src/app/panels/columns/CategorySection.cpp +++ b/src/app/panels/columns/CategorySection.cpp @@ -12,9 +12,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -82,9 +84,7 @@ CategorySection::CategorySection(const geopro::data::CategoryDescriptor& desc, break; case geopro::data::OpKind::PlaneZ: acts.push_back({QStringLiteral("collapse"), QStringLiteral("z 值"), {}, - [this](QToolButton*) { // Task E3 建滑块 popup;当前先发请求信号 - emit zSliderRequested(QString::fromStdString(desc_.id)); - }}); + [this](QToolButton* host) { showPlaneZPopup(host); }}); break; case geopro::data::OpKind::Basemap: acts.push_back({QStringLiteral("map"), QStringLiteral("底图"), {}, @@ -457,4 +457,34 @@ void CategorySection::showContextMenu(const QPoint& pos) { menu.exec(list_->viewport()->mapToGlobal(pos)); } +void CategorySection::showPlaneZPopup(QToolButton* host) { + // z 值滑块 popup(仿工具条底图滑块):拖动整体升降本类型平面(含其上全部足迹)。 + // 范围 ±500 米:覆盖常见场景高程量级;滑块值即平面绝对高程(米),首开回显 lastPlaneZ_(无则 0)。 + constexpr int kPlaneZRangeM = 500; + QMenu menu(this); + auto* wa = new QWidgetAction(&menu); + auto* box = new QWidget(&menu); + auto* lay = new QVBoxLayout(box); + lay->setContentsMargins(space::kMd, space::kSm, space::kMd, space::kSm); + lay->setSpacing(space::kXs); + auto* lab = new QLabel(box); + auto* sld = new QSlider(Qt::Horizontal, box); + sld->setRange(-kPlaneZRangeM, kPlaneZRangeM); + sld->setValue(static_cast(lastPlaneZ_)); + sld->setMinimumWidth(160); + sld->setToolTip(QStringLiteral("平面高程 z(米)")); + auto syncLabel = [lab](int v) { lab->setText(QStringLiteral("平面 z:%1 米").arg(v)); }; + syncLabel(sld->value()); + connect(sld, &QSlider::valueChanged, this, [this, syncLabel](int v) { + lastPlaneZ_ = v; + syncLabel(v); + emit planeZChanged(QString::fromStdString(desc_.id), static_cast(v)); + }); + lay->addWidget(lab); + lay->addWidget(sld); + wa->setDefaultWidget(box); + menu.addAction(wa); + menu.exec(host->mapToGlobal(QPoint(0, host->height()))); +} + } // namespace geopro::app diff --git a/src/app/panels/columns/CategorySection.hpp b/src/app/panels/columns/CategorySection.hpp index 69c9587..5cb9285 100644 --- a/src/app/panels/columns/CategorySection.hpp +++ b/src/app/panels/columns/CategorySection.hpp @@ -53,7 +53,7 @@ signals: void checkedDatasetsChanged(const QStringList& dsIds); // 数据行勾选=渲染 void collapsedChanged(); // 折叠/展开切换 → 外层 CategoryAnalysisTab 重排各段 stretch void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); // 段头「+新增三维体」(接收方按 sourceIds 解析类型) - void zSliderRequested(const QString& typeId); // PlaneZ 图标:弹 z 值滑块 popup(Task E3 实现) + void planeZChanged(const QString& typeId, double z); // PlaneZ 滑块:整体升降该 2D 类型平面(z=绝对高程,米) void basemapPopupRequested(const QString& typeId); // Basemap 图标:弹底图选择 popup(Task F2 实现) void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); // 双击/右键=详情 void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除(切片/异常) @@ -70,6 +70,7 @@ signals: private: void showContextMenu(const QPoint& pos); // 段体树右键菜单(详情 + 删除) + void showPlaneZPopup(QToolButton* host); // PlaneZ 图标:弹 z 值滑块 popup → planeZChanged void rebuildList(); // 据 rows_(经装置/日期筛选)重建段体树并复原勾选 void refreshArrayCombo(); // 据当前 rows_ 重填装置类型下拉项(经字典 value→中文) void emitChecked(); // 收集勾选 → checkedDatasetsChanged @@ -90,6 +91,7 @@ private: QTreeWidget* list_ = nullptr; QTimer* spinTimer_ = nullptr; // 驱动 busy 行 spinner 旋转(有 busy 行时运行) int spinAngle_ = 0; // 当前 spinner 角度(度) + double lastPlaneZ_ = 0.0; // 上次 z 值滑块设定的平面高程(重开 popup 时回显,无则 0) }; } // namespace geopro::app diff --git a/src/controller/DatasetRenderStrategy.cpp b/src/controller/DatasetRenderStrategy.cpp index 26190b7..f04cd37 100644 --- a/src/controller/DatasetRenderStrategy.cpp +++ b/src/controller/DatasetRenderStrategy.cpp @@ -33,4 +33,16 @@ void Plane2DRenderStrategy::remove(const std::string& dsId) { // 该类型全消(控制器活跃计数归零):此时 planeReg_.hasPlane==false。Phase F2 在此销毁平面底图。 void Plane2DRenderStrategy::onTypeDeactivated(const std::string& /*typeId*/) {} +void Plane2DRenderStrategy::setPlaneZ(const std::string& typeId, double z) { + planeReg_.setPlaneZ(typeId, z); // 平面 z 真源更新(类型不存在则无操作) + // 重摆该类型全部已勾选足迹:移除旧 actor,按既有 add 路径在新 z 重新加载摆放。 + // add2DDatasetAsync 复用 rebuildGeneration_ + loadingDs_/is2DChecked 防迟到/防重复(与 add 同护栏)。 + for (const auto& [dsId, t] : dsToType_) { + if (t != typeId) continue; + ctrl_.view_.removeDataset(dsId); + ctrl_.add2DDatasetAsync(dsId, ctrl_.rebuildGeneration_, z); + } + ctrl_.view_.renderIncremental(); +} + } // namespace geopro::controller diff --git a/src/controller/DatasetRenderStrategy.hpp b/src/controller/DatasetRenderStrategy.hpp index cb0236e..17db96f 100644 --- a/src/controller/DatasetRenderStrategy.hpp +++ b/src/controller/DatasetRenderStrategy.hpp @@ -60,6 +60,8 @@ public: void add(const std::string& typeId, const std::string& dsId) override; void remove(const std::string& dsId) override; void onTypeDeactivated(const std::string& typeId) override; + // 滑块整体升降该类型平面 z:更新 planeReg_ 后,对该类型已勾选足迹移除并按新 z 重摆。 + void setPlaneZ(const std::string& typeId, double z); private: VtkSceneController& ctrl_; PlaneZRegistry planeReg_; // 按类型的平面 z 生命周期 diff --git a/src/controller/VtkSceneController.cpp b/src/controller/VtkSceneController.cpp index 01019a6..12b1bd0 100644 --- a/src/controller/VtkSceneController.cpp +++ b/src/controller/VtkSceneController.cpp @@ -23,7 +23,13 @@ VtkSceneController::VtkSceneController(data::IDatasetRepository& dsRepo, // add/remove 委托回既有渲染路径(addDatasetAsync/add2DDatasetAsync/view_.removeDataset)。 registry_.registerStrategy("volume", std::make_unique(*this)); registry_.registerStrategy("curtain", std::make_unique(*this)); - registry_.registerStrategy("plane2d", std::make_unique(*this)); + auto plane2d = std::make_unique(*this); + plane2d_ = plane2d.get(); // 留裸指针供 setPlaneZ 直呼(registry_ 持所有权) + registry_.registerStrategy("plane2d", std::move(plane2d)); +} + +void VtkSceneController::setPlaneZ(const QString& typeId, double z) { + if (plane2d_) plane2d_->setPlaneZ(typeId.toStdString(), z); } IDatasetRenderStrategy* VtkSceneController::strategyForType(const std::string& typeId) const { diff --git a/src/controller/VtkSceneController.hpp b/src/controller/VtkSceneController.hpp index b00a72e..e5a2d37 100644 --- a/src/controller/VtkSceneController.hpp +++ b/src/controller/VtkSceneController.hpp @@ -76,6 +76,9 @@ public slots: // 坐标轴设置面板「应用」:一次性下发 显示方式 + 单位 + per-axis 可见性/范围(单次重建)。 void setAxesConfig(AxesMode mode, AxesUnit unit, const AxisRangeCfg& x, const AxisRangeCfg& y, const AxisRangeCfg& z); + // 2D 段「z 值」滑块:整体升降某 2D 类型平面(含其上全部已勾选足迹)。转交 Plane2DRenderStrategy。 + void setPlaneZ(const QString& typeId, double z); + void applyView(ViewDir dir); // 6 向快捷视图 void zoomIn(); // Zoom In (×1.2) void zoomOut(); // Zoom Out (×1/1.2) @@ -115,6 +118,7 @@ private: std::map typeActive_; // 渲染策略注册表(构造时注册 volume/curtain/plane2d 三策略,各持本控制器引用)。 RenderStrategyRegistry registry_; + Plane2DRenderStrategy* plane2d_ = nullptr; // registry_ 中 plane2d 策略的裸指针(setPlaneZ 免下转型) ViewMode mode_ = ViewMode::Map2D; bool showCurtain_ = true; bool showVoxel_ = false;