feat(vtk): Plane2D 策略持每类型平面矢量底图(多实例+生命周期+底图popup)
This commit is contained in:
parent
55085208bb
commit
e8df41b9f2
|
|
@ -109,7 +109,6 @@ add_executable(geopro_desktop WIN32
|
||||||
VolumeParamsDialog.cpp
|
VolumeParamsDialog.cpp
|
||||||
VolumePropertiesDialog.cpp
|
VolumePropertiesDialog.cpp
|
||||||
Logging.cpp
|
Logging.cpp
|
||||||
DatasetDimension.cpp
|
|
||||||
DatasetCategory.cpp
|
DatasetCategory.cpp
|
||||||
VtkViewToolbar.cpp
|
VtkViewToolbar.cpp
|
||||||
AxesSettingsDialog.cpp
|
AxesSettingsDialog.cpp
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "repo/CategoryConfig.hpp"
|
|
||||||
#include "repo/RepoTypes.hpp"
|
#include "repo/RepoTypes.hpp"
|
||||||
|
|
||||||
namespace geopro::app {
|
namespace geopro::app {
|
||||||
|
|
||||||
struct CategoryBuckets {
|
struct CategoryBuckets {
|
||||||
std::vector<std::vector<geopro::data::DsRow>> segments; // 与 categoryConfigs() 同序同长
|
std::vector<std::vector<geopro::data::DsRow>> segments; // 与 categoryCatalog() 同序同长
|
||||||
};
|
};
|
||||||
|
|
||||||
// 按 CategoryConfig 把 ds 分入大类段:先判 ddCode 白名单(三维体/切片),否则按 dsTypeCode 匹配;
|
// 按 categoryCatalog() 把 ds 分入大类段:遍历目录,命中首个 classify(row)==true 的描述符即归入该段;
|
||||||
// 不在表内的丢弃(接地电阻/原始数据/白化/坐标等)。保留原顺序。
|
// 不在表内的丢弃(接地电阻/原始数据/白化/坐标等)。保留原顺序。
|
||||||
CategoryBuckets splitByCategory(const std::vector<geopro::data::DsRow>& rows);
|
CategoryBuckets splitByCategory(const std::vector<geopro::data::DsRow>& rows);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
#include "DatasetDimension.hpp"
|
|
||||||
|
|
||||||
namespace geopro::app {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// 与 LocalSample3dRepository::dimensionOf 同一映射(spec §6.1)。
|
|
||||||
enum class Dim { D3, D2, Analysis, Other };
|
|
||||||
Dim dimOf(const std::string& c) {
|
|
||||||
if (c == "dd_voxel" || c == "dd_Structual3D" || c == "dd_Property3D" ||
|
|
||||||
c == "dd_section" || c == "dd_inversion_data" || c == "dd_radar_3d")
|
|
||||||
return Dim::D3;
|
|
||||||
if (c == "dd_slice") return Dim::Analysis;
|
|
||||||
if (c == "dd_trajectory_data") return Dim::D2;
|
|
||||||
return Dim::Other;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
DimBuckets splitByDimension(const std::vector<geopro::data::DsRow>& rows) {
|
|
||||||
DimBuckets b;
|
|
||||||
for (const auto& r : rows) {
|
|
||||||
switch (dimOf(r.ddCode)) {
|
|
||||||
case Dim::D3: b.dim3D.push_back(r); break;
|
|
||||||
case Dim::D2: b.dim2D.push_back(r); break;
|
|
||||||
case Dim::Analysis: b.analysis.push_back(r); break;
|
|
||||||
case Dim::Other: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace geopro::app
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
#include "repo/RepoTypes.hpp"
|
|
||||||
|
|
||||||
namespace geopro::app {
|
|
||||||
|
|
||||||
struct DimBuckets {
|
|
||||||
std::vector<geopro::data::DsRow> dim3D;
|
|
||||||
std::vector<geopro::data::DsRow> dim2D;
|
|
||||||
std::vector<geopro::data::DsRow> analysis;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 按 ddCode 把 ds 分流到 三维数据集 / 二维数据集 / 三维分析 三栏。
|
|
||||||
// Other 维度不入任何栏(保留原顺序)。
|
|
||||||
DimBuckets splitByDimension(const std::vector<geopro::data::DsRow>& rows);
|
|
||||||
|
|
||||||
} // namespace geopro::app
|
|
||||||
|
|
@ -139,6 +139,10 @@ void TileBasemap::requestRender() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TileBasemap::~TileBasemap() {
|
TileBasemap::~TileBasemap() {
|
||||||
|
// 移除本实例所有已贴瓦片:多实例(每 2D 平面一份)动态建销时,析构须撤回瓦片,否则渲染器仍持引用、
|
||||||
|
// 底图不随平面消失。共享 3D 底图存活至退出故旧码无此清理也无碍,但 per-plane 实例必须清。
|
||||||
|
if (auto* ren = scene_.renderer())
|
||||||
|
for (auto& kv : placed_) ren->RemoveViewProp(kv.second);
|
||||||
if (styleObs_ && observer_) styleObs_->RemoveObserver(observer_);
|
if (styleObs_ && observer_) styleObs_->RemoveObserver(observer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "TileBasemap.hpp"
|
||||||
|
#include "controller/DatasetRenderStrategy.hpp" // geopro::controller::IPlaneBasemap
|
||||||
|
|
||||||
|
namespace geopro::render { class Scene; }
|
||||||
|
namespace geopro::core { class GeoLocalFrame; }
|
||||||
|
class vtkRenderWindow;
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
// 2D 平面底图适配器:把 app 层 TileBasemap 适配到控制器层抽象 IPlaneBasemap,
|
||||||
|
// 使 geopro_controller(仅链 geopro_data+Qt::Core) 不反依赖 app 层与 VTK(仿 I3dSceneView/VtkSceneView)。
|
||||||
|
// main.cpp 经底图工厂按平面 z 造之;持 TileBasemap 值成员,随适配器析构而析构(移除瓦片→底图随平面消失)。
|
||||||
|
class TileBasemapPlaneAdapter : public geopro::controller::IPlaneBasemap {
|
||||||
|
public:
|
||||||
|
TileBasemapPlaneAdapter(geopro::render::Scene& scene, vtkRenderWindow* rw,
|
||||||
|
std::shared_ptr<geopro::core::GeoLocalFrame> frame, double groundZ,
|
||||||
|
std::function<double()> radiusProvider)
|
||||||
|
: bm_(scene, rw, std::move(frame), nullptr, groundZ) {
|
||||||
|
bm_.setDataRadiusProvider(std::move(radiusProvider));
|
||||||
|
}
|
||||||
|
void show(int kind) override {
|
||||||
|
bm_.show(kind == 0 ? TileBasemap::Street : TileBasemap::Hidden);
|
||||||
|
}
|
||||||
|
void hide() override { bm_.hide(); }
|
||||||
|
void setOpacity(double o) override { bm_.setOpacity(o); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
TileBasemap bm_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
|
|
@ -93,7 +93,6 @@
|
||||||
|
|
||||||
#include "ApiClient.hpp"
|
#include "ApiClient.hpp"
|
||||||
#include "AuthService.hpp"
|
#include "AuthService.hpp"
|
||||||
#include "DatasetDimension.hpp"
|
|
||||||
#include "DatasetCategory.hpp"
|
#include "DatasetCategory.hpp"
|
||||||
#include "repo/CategoryDescriptor.hpp"
|
#include "repo/CategoryDescriptor.hpp"
|
||||||
#include "Credential.hpp"
|
#include "Credential.hpp"
|
||||||
|
|
@ -143,6 +142,7 @@
|
||||||
#include "panels/DatasetAttrPanel.hpp"
|
#include "panels/DatasetAttrPanel.hpp"
|
||||||
#include "panels/ObjectExceptionPanel.hpp"
|
#include "panels/ObjectExceptionPanel.hpp"
|
||||||
#include "TileBasemap.hpp"
|
#include "TileBasemap.hpp"
|
||||||
|
#include "TileBasemapPlaneAdapter.hpp"
|
||||||
#include "panels/columns/ColumnDrawer.hpp"
|
#include "panels/columns/ColumnDrawer.hpp"
|
||||||
#include "panels/columns/CategoryAnalysisTab.hpp"
|
#include "panels/columns/CategoryAnalysisTab.hpp"
|
||||||
#include "panels/columns/CategorySection.hpp"
|
#include "panels/columns/CategorySection.hpp"
|
||||||
|
|
@ -1276,6 +1276,11 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
// 2D 段「z 值」滑块 → 整体升降该 2D 类型平面(Plane2DRenderStrategy 重摆其全部足迹)。
|
// 2D 段「z 值」滑块 → 整体升降该 2D 类型平面(Plane2DRenderStrategy 重摆其全部足迹)。
|
||||||
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::planeZChanged, sceneCtrl,
|
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::planeZChanged, sceneCtrl,
|
||||||
&geopro::controller::VtkSceneController::setPlaneZ);
|
&geopro::controller::VtkSceneController::setPlaneZ);
|
||||||
|
// 2D 段「底图」弹窗 → 切该类型平面底图 矢量平面/无 + 透明度(Plane2DRenderStrategy 多实例底图)。
|
||||||
|
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::basemapKindChanged, sceneCtrl,
|
||||||
|
&geopro::controller::VtkSceneController::setBasemapKind);
|
||||||
|
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::basemapOpacityChanged, sceneCtrl,
|
||||||
|
&geopro::controller::VtkSceneController::setBasemapOpacity);
|
||||||
// 反向 VTK→list:在 VTK 里点中/选中一张切片 → 在三维体段树里同步选中该切片行(②反向)。
|
// 反向 VTK→list:在 VTK 里点中/选中一张切片 → 在三维体段树里同步选中该切片行(②反向)。
|
||||||
// 点空白/清选(dsId 空) → 一并清 VTK 异常高亮(否则取消选中后异常图形仍高亮,用户反馈)。
|
// 点空白/清选(dsId 空) → 一并清 VTK 异常高亮(否则取消选中后异常图形仍高亮,用户反馈)。
|
||||||
interactionMgr->onSliceSelectionChanged = [drawer, sceneView, renderWindowPtr](
|
interactionMgr->onSliceSelectionChanged = [drawer, sceneView, renderWindowPtr](
|
||||||
|
|
@ -1322,6 +1327,16 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
[basemap](double o) { basemap->setOpacity(o); });
|
[basemap](double o) { basemap->setOpacity(o); });
|
||||||
// 底图最大范围按当前勾选剖面合并范围动态定(随增删自动伸缩);刷新时实时查询。
|
// 底图最大范围按当前勾选剖面合并范围动态定(随增删自动伸缩);刷新时实时查询。
|
||||||
basemap->setDataRadiusProvider([sceneView]() { return sceneView->dataHorizontalRadius(); });
|
basemap->setDataRadiusProvider([sceneView]() { return sceneView->dataHorizontalRadius(); });
|
||||||
|
// F2:2D 平面底图工厂下发 → Plane2DRenderStrategy 据此为每个 2D 类型平面按需建/销平面矢量底图
|
||||||
|
// (与共享 3D 底图同源 scene/渲染窗/frame/数据半径规则;随平面 z 升降重建、全消随平面消失)。
|
||||||
|
// 工厂造 TileBasemapPlaneAdapter(app 层适配 IPlaneBasemap),使 geopro_controller 不反依赖 app/VTK。
|
||||||
|
sceneCtrl->setPlaneBasemapFactory(
|
||||||
|
[scene, renderWindowPtr, frame, sceneView](double groundZ)
|
||||||
|
-> std::unique_ptr<geopro::controller::IPlaneBasemap> {
|
||||||
|
return std::make_unique<geopro::app::TileBasemapPlaneAdapter>(
|
||||||
|
*scene, renderWindowPtr, frame, groundZ,
|
||||||
|
[sceneView]() { return sceneView->dataHorizontalRadius(); });
|
||||||
|
});
|
||||||
// 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。单一来源 kVerticalExaggeration 下发
|
// 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。单一来源 kVerticalExaggeration 下发
|
||||||
// 控制器(上方)/底图;运行时 VE 改由坐标轴设置抽屉「应用」下发(旧三维数据集栏滑块已退役)。
|
// 控制器(上方)/底图;运行时 VE 改由坐标轴设置抽屉「应用」下发(旧三维数据集栏滑块已退役)。
|
||||||
basemap->setVerticalExaggeration(kVerticalExaggeration);
|
basemap->setVerticalExaggeration(kVerticalExaggeration);
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,10 @@ CategoryAnalysisTab::CategoryAnalysisTab(geopro::data::DatasetFieldDictionary* d
|
||||||
&CategoryAnalysisTab::anomalyVisibilityChanged);
|
&CategoryAnalysisTab::anomalyVisibilityChanged);
|
||||||
connect(sec, &CategorySection::datasetSelected, this, &CategoryAnalysisTab::datasetSelected);
|
connect(sec, &CategorySection::datasetSelected, this, &CategoryAnalysisTab::datasetSelected);
|
||||||
connect(sec, &CategorySection::planeZChanged, this, &CategoryAnalysisTab::planeZChanged);
|
connect(sec, &CategorySection::planeZChanged, this, &CategoryAnalysisTab::planeZChanged);
|
||||||
|
connect(sec, &CategorySection::basemapKindChanged, this,
|
||||||
|
&CategoryAnalysisTab::basemapKindChanged);
|
||||||
|
connect(sec, &CategorySection::basemapOpacityChanged, this,
|
||||||
|
&CategoryAnalysisTab::basemapOpacityChanged);
|
||||||
// #7:各段等分 stretch → 内容都少时四段平分高度填满面板(初始与 VTK 区等高、不出滚动条);
|
// #7:各段等分 stretch → 内容都少时四段平分高度填满面板(初始与 VTK 区等高、不出滚动条);
|
||||||
// 某段内容增多时其最小高度(=内容总高)撑大,超出视口则由外层 QScrollArea 统一出纵向滚动条。
|
// 某段内容增多时其最小高度(=内容总高)撑大,超出视口则由外层 QScrollArea 统一出纵向滚动条。
|
||||||
col->addWidget(sec, 1);
|
col->addWidget(sec, 1);
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ signals:
|
||||||
void anomalyVisibilityChanged(const QString& dsId, bool vis);
|
void anomalyVisibilityChanged(const QString& dsId, bool vis);
|
||||||
void datasetSelected(const QString& dsId, const QString& ddCode); // 树选中→VTK 高亮联动
|
void datasetSelected(const QString& dsId, const QString& ddCode); // 树选中→VTK 高亮联动
|
||||||
void planeZChanged(const QString& typeId, double z); // 2D 段 z 值滑块:整体升降该类型平面
|
void planeZChanged(const QString& typeId, double z); // 2D 段 z 值滑块:整体升降该类型平面
|
||||||
|
void basemapKindChanged(const QString& typeId, int kind); // 2D 段底图弹窗:矢量平面(0)/无(1)
|
||||||
|
void basemapOpacityChanged(const QString& typeId, double o); // 2D 段底图弹窗:透明度[0,1]
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void recomputeCheckedUnion();
|
void recomputeCheckedUnion();
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,7 @@ CategorySection::CategorySection(const geopro::data::CategoryDescriptor& desc,
|
||||||
break;
|
break;
|
||||||
case geopro::data::OpKind::Basemap:
|
case geopro::data::OpKind::Basemap:
|
||||||
acts.push_back({QStringLiteral("map"), QStringLiteral("底图"), {},
|
acts.push_back({QStringLiteral("map"), QStringLiteral("底图"), {},
|
||||||
[this](QToolButton*) { // Task F2 建底图 popup;当前先发请求信号
|
[this](QToolButton* host) { showBasemapPopup(host); }});
|
||||||
emit basemapPopupRequested(QString::fromStdString(desc_.id));
|
|
||||||
}});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -500,4 +498,54 @@ void CategorySection::showPlaneZPopup(QToolButton* host) {
|
||||||
menu.exec(host->mapToGlobal(QPoint(0, host->height())));
|
menu.exec(host->mapToGlobal(QPoint(0, host->height())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CategorySection::showBasemapPopup(QToolButton* host) {
|
||||||
|
// 底图 popup(仿工具条底图控件):本类型平面底图 矢量平面(默认)/无 + 透明度滑块(0–100,默认 50)。
|
||||||
|
// 类型切换为离散单次事件直发;透明度拖动逐步触发→单发 QTimer(150ms)防抖,停手后一次发射,免抖动重铺瓦片。
|
||||||
|
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* kindCombo = new QComboBox(box);
|
||||||
|
kindCombo->addItem(QStringLiteral("矢量平面")); // index 0
|
||||||
|
kindCombo->addItem(QStringLiteral("无")); // index 1
|
||||||
|
kindCombo->setCurrentIndex(lastBasemapKind_);
|
||||||
|
connect(kindCombo, &QComboBox::currentIndexChanged, this, [this](int idx) {
|
||||||
|
lastBasemapKind_ = idx;
|
||||||
|
emit basemapKindChanged(QString::fromStdString(desc_.id), idx);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* lab = new QLabel(box);
|
||||||
|
auto* sld = new QSlider(Qt::Horizontal, box);
|
||||||
|
sld->setRange(0, 100);
|
||||||
|
sld->setValue(lastBasemapOpacity_);
|
||||||
|
sld->setMinimumWidth(160);
|
||||||
|
sld->setToolTip(QStringLiteral("底图透明度"));
|
||||||
|
auto syncLabel = [lab](int v) { lab->setText(QStringLiteral("透明度:%1%").arg(v)); };
|
||||||
|
syncLabel(sld->value());
|
||||||
|
if (!basemapOpacityTimer_) { // 定时器 parent=this,存活于 modal popup 之外,停手后安全发射终值
|
||||||
|
basemapOpacityTimer_ = new QTimer(this);
|
||||||
|
basemapOpacityTimer_->setSingleShot(true);
|
||||||
|
basemapOpacityTimer_->setInterval(150);
|
||||||
|
connect(basemapOpacityTimer_, &QTimer::timeout, this, [this]() {
|
||||||
|
emit basemapOpacityChanged(QString::fromStdString(desc_.id), pendingBasemapOpacity_);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
connect(sld, &QSlider::valueChanged, this, [this, syncLabel](int v) {
|
||||||
|
lastBasemapOpacity_ = v;
|
||||||
|
syncLabel(v);
|
||||||
|
pendingBasemapOpacity_ = v / 100.0;
|
||||||
|
basemapOpacityTimer_->start(); // 重启防抖窗口:覆盖拖动、键盘、点轨——停手后一次性发射
|
||||||
|
});
|
||||||
|
|
||||||
|
lay->addWidget(kindCombo);
|
||||||
|
lay->addWidget(lab);
|
||||||
|
lay->addWidget(sld);
|
||||||
|
wa->setDefaultWidget(box);
|
||||||
|
menu.addAction(wa);
|
||||||
|
menu.exec(host->mapToGlobal(QPoint(0, host->height())));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace geopro::app
|
} // namespace geopro::app
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,8 @@ signals:
|
||||||
void collapsedChanged(); // 折叠/展开切换 → 外层 CategoryAnalysisTab 重排各段 stretch
|
void collapsedChanged(); // 折叠/展开切换 → 外层 CategoryAnalysisTab 重排各段 stretch
|
||||||
void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); // 段头「+新增三维体」(接收方按 sourceIds 解析类型)
|
void generateVolumeRequested(const QString& dsTypeCode, const QStringList& sourceDsIds); // 段头「+新增三维体」(接收方按 sourceIds 解析类型)
|
||||||
void planeZChanged(const QString& typeId, double z); // PlaneZ 滑块:整体升降该 2D 类型平面(z=绝对高程,米)
|
void planeZChanged(const QString& typeId, double z); // PlaneZ 滑块:整体升降该 2D 类型平面(z=绝对高程,米)
|
||||||
void basemapPopupRequested(const QString& typeId); // Basemap 图标:弹底图选择 popup(Task F2 实现)
|
void basemapKindChanged(const QString& typeId, int kind); // 底图弹窗:矢量平面(0)/无(1)
|
||||||
|
void basemapOpacityChanged(const QString& typeId, double o); // 底图弹窗透明度滑块[0,1](防抖发射)
|
||||||
void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); // 双击/右键=详情
|
void detailRequested(const QString& dsId, const QString& ddCode, const QString& name); // 双击/右键=详情
|
||||||
void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除(切片/异常)
|
void deleteDatasetRequested(const QString& dsId, const QString& ddCode); // 右键删除(切片/异常)
|
||||||
// ── 三维体段右键操作(迁自旧 Column3DAnalysis,全接)──
|
// ── 三维体段右键操作(迁自旧 Column3DAnalysis,全接)──
|
||||||
|
|
@ -71,6 +72,7 @@ signals:
|
||||||
private:
|
private:
|
||||||
void showContextMenu(const QPoint& pos); // 段体树右键菜单(详情 + 删除)
|
void showContextMenu(const QPoint& pos); // 段体树右键菜单(详情 + 删除)
|
||||||
void showPlaneZPopup(QToolButton* host); // PlaneZ 图标:弹 z 值滑块 popup → planeZChanged
|
void showPlaneZPopup(QToolButton* host); // PlaneZ 图标:弹 z 值滑块 popup → planeZChanged
|
||||||
|
void showBasemapPopup(QToolButton* host); // Basemap 图标:弹 矢量平面/无 + 透明度滑块 popup
|
||||||
void rebuildList(); // 据 rows_(经装置/日期筛选)重建段体树并复原勾选
|
void rebuildList(); // 据 rows_(经装置/日期筛选)重建段体树并复原勾选
|
||||||
void refreshArrayCombo(); // 据当前 rows_ 重填装置类型下拉项(经字典 value→中文)
|
void refreshArrayCombo(); // 据当前 rows_ 重填装置类型下拉项(经字典 value→中文)
|
||||||
void emitChecked(); // 收集勾选 → checkedDatasetsChanged
|
void emitChecked(); // 收集勾选 → checkedDatasetsChanged
|
||||||
|
|
@ -94,6 +96,10 @@ private:
|
||||||
double lastPlaneZ_ = 0.0; // 上次 z 值滑块设定的平面高程(重开 popup 时回显,无则 0)
|
double lastPlaneZ_ = 0.0; // 上次 z 值滑块设定的平面高程(重开 popup 时回显,无则 0)
|
||||||
QTimer* planeZTimer_ = nullptr; // z 值滑块发射防抖:拖动/键盘/点轨期合并为停手后一次重摆(owned by this,存活于 popup 之外)
|
QTimer* planeZTimer_ = nullptr; // z 值滑块发射防抖:拖动/键盘/点轨期合并为停手后一次重摆(owned by this,存活于 popup 之外)
|
||||||
double pendingPlaneZ_ = 0.0; // 防抖待发的平面 z(定时器到点时取此值发射 planeZChanged)
|
double pendingPlaneZ_ = 0.0; // 防抖待发的平面 z(定时器到点时取此值发射 planeZChanged)
|
||||||
|
int lastBasemapKind_ = 0; // 上次底图选择(0=矢量平面/1=无),重开 popup 时回显
|
||||||
|
int lastBasemapOpacity_ = 50; // 上次底图透明度(0–100,重开 popup 回显;默认 50)
|
||||||
|
QTimer* basemapOpacityTimer_ = nullptr; // 底图透明度滑块发射防抖(同 planeZ:停手后一次发射,免抖动重铺瓦片)
|
||||||
|
double pendingBasemapOpacity_ = 0.5; // 防抖待发的底图透明度[0,1](定时器到点发射 basemapOpacityChanged)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace geopro::app
|
} // namespace geopro::app
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
namespace geopro::controller {
|
namespace geopro::controller {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr double kDefaultBasemapOpacity = 0.5; // 平面底图默认半透明(地下足迹可透过看)
|
||||||
|
}
|
||||||
|
|
||||||
// 各策略委托回控制器既有渲染路径(友元访问其私有 addDatasetAsync/add2DDatasetAsync/view_)。
|
// 各策略委托回控制器既有渲染路径(友元访问其私有 addDatasetAsync/add2DDatasetAsync/view_)。
|
||||||
// 增量 gen 沿用控制器当前 rebuildGeneration_(不自增,与并发增量互不作废)。
|
// 增量 gen 沿用控制器当前 rebuildGeneration_(不自增,与并发增量互不作废)。
|
||||||
void VolumeRenderStrategy::add(const std::string& /*typeId*/, const std::string& dsId) {
|
void VolumeRenderStrategy::add(const std::string& /*typeId*/, const std::string& dsId) {
|
||||||
|
|
@ -30,8 +34,21 @@ void Plane2DRenderStrategy::remove(const std::string& dsId) {
|
||||||
planeReg_.onUnchecked(it->second, dsId); // 该类型成员集空时平面自动消失
|
planeReg_.onUnchecked(it->second, dsId); // 该类型成员集空时平面自动消失
|
||||||
dsToType_.erase(it);
|
dsToType_.erase(it);
|
||||||
}
|
}
|
||||||
// 该类型全消(控制器活跃计数归零):此时 planeReg_.hasPlane==false。Phase F2 在此销毁平面底图。
|
// 该类型首勾(控制器活跃计数 0→1,先于 add 触发):建该类型平面矢量底图。
|
||||||
void Plane2DRenderStrategy::onTypeDeactivated(const std::string& /*typeId*/) {}
|
// 注意 onTypeActivated 在 add 之前触发 → 此刻 planeReg_ 尚无该平面,createBasemap 以 zRefElev() 兜底
|
||||||
|
// (即首勾 add 即将写入的平面 z,二者一致)。kind/opacity 复位为默认(矢量平面/0.5)。
|
||||||
|
void Plane2DRenderStrategy::onTypeActivated(const std::string& typeId) {
|
||||||
|
bmKind_[typeId] = 0;
|
||||||
|
bmOpacity_[typeId] = kDefaultBasemapOpacity;
|
||||||
|
createBasemap(typeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 该类型全消(控制器活跃计数 1→0):销毁该类型底图(析构移除瓦片→底图随平面一并消失),遗忘其 kind/opacity。
|
||||||
|
void Plane2DRenderStrategy::onTypeDeactivated(const std::string& typeId) {
|
||||||
|
bms_.erase(typeId);
|
||||||
|
bmKind_.erase(typeId);
|
||||||
|
bmOpacity_.erase(typeId);
|
||||||
|
}
|
||||||
|
|
||||||
void Plane2DRenderStrategy::setPlaneZ(const std::string& typeId, double z) {
|
void Plane2DRenderStrategy::setPlaneZ(const std::string& typeId, double z) {
|
||||||
planeReg_.setPlaneZ(typeId, z); // 平面 z 真源更新(类型不存在则无操作)
|
planeReg_.setPlaneZ(typeId, z); // 平面 z 真源更新(类型不存在则无操作)
|
||||||
|
|
@ -42,7 +59,38 @@ void Plane2DRenderStrategy::setPlaneZ(const std::string& typeId, double z) {
|
||||||
ctrl_.view_.removeDataset(dsId);
|
ctrl_.view_.removeDataset(dsId);
|
||||||
ctrl_.add2DDatasetAsync(dsId, ctrl_.rebuildGeneration_, z);
|
ctrl_.add2DDatasetAsync(dsId, ctrl_.rebuildGeneration_, z);
|
||||||
}
|
}
|
||||||
|
// 底图同步升降:销毁旧实例、按新平面 z 重建(复用当前 kind/opacity),简单可靠(无 setGroundZ 增量重铺)。
|
||||||
|
if (bms_.count(typeId)) createBasemap(typeId);
|
||||||
ctrl_.view_.renderIncremental();
|
ctrl_.view_.renderIncremental();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plane2DRenderStrategy::setBasemapKind(const std::string& typeId, int kind) {
|
||||||
|
bmKind_[typeId] = kind;
|
||||||
|
auto it = bms_.find(typeId);
|
||||||
|
if (it == bms_.end()) return;
|
||||||
|
if (kind == 0) it->second->show(0); // 矢量平面
|
||||||
|
else it->second->hide(); // 无(保留实例,仅隐瓦片)
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane2DRenderStrategy::setBasemapOpacity(const std::string& typeId, double o) {
|
||||||
|
bmOpacity_[typeId] = o;
|
||||||
|
auto it = bms_.find(typeId);
|
||||||
|
if (it != bms_.end()) it->second->setOpacity(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plane2DRenderStrategy::createBasemap(const std::string& typeId) {
|
||||||
|
if (!basemapFactory_) return; // 工厂未注入(如纯逻辑单测,无 VTK) → 不建底图
|
||||||
|
// 平面 z:已建平面取 planeReg_(setPlaneZ 重建走此);onTypeActivated 时平面尚未建 → 以 zRefElev() 兜底
|
||||||
|
// (= add 即将写入的首勾平面 z,二者一致)。
|
||||||
|
const double gz =
|
||||||
|
planeReg_.hasPlane(typeId) ? planeReg_.planeZ(typeId) : ctrl_.view_.zRefElev();
|
||||||
|
auto bm = basemapFactory_(gz);
|
||||||
|
if (!bm) return;
|
||||||
|
const int kind = bmKind_.count(typeId) ? bmKind_[typeId] : 0;
|
||||||
|
const double op = bmOpacity_.count(typeId) ? bmOpacity_[typeId] : kDefaultBasemapOpacity;
|
||||||
|
bm->setOpacity(op); // 先定透明度,再 show 套用到初次铺瓦
|
||||||
|
if (kind == 0) bm->show(0); // 默认矢量平面;kind=1(无)则仅留实例
|
||||||
|
bms_[typeId] = std::move(bm); // 替换旧实例 → 旧底图适配器析构移除其瓦片
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace geopro::controller
|
} // namespace geopro::controller
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -9,6 +10,20 @@ namespace geopro::controller {
|
||||||
|
|
||||||
class VtkSceneController; // 策略委托回控制器既有渲染路径(add→addDatasetAsync/add2DDatasetAsync;remove→view.removeDataset)
|
class VtkSceneController; // 策略委托回控制器既有渲染路径(add→addDatasetAsync/add2DDatasetAsync;remove→view.removeDataset)
|
||||||
|
|
||||||
|
// 平面底图抽象:控制器层不依赖 VTK/app(geopro_controller 仅链 geopro_data+Qt::Core)。
|
||||||
|
// app 层(main.cpp)经工厂注入具体 TileBasemap 适配器,仿既有 I3dSceneView/VtkSceneView 边界,
|
||||||
|
// 避免 geopro_controller 反向依赖 app 层与 VTK。
|
||||||
|
class IPlaneBasemap {
|
||||||
|
public:
|
||||||
|
virtual ~IPlaneBasemap() = default;
|
||||||
|
virtual void show(int kind) = 0; // 0=矢量平面(Street)/其它=无(hide)
|
||||||
|
virtual void hide() = 0;
|
||||||
|
virtual void setOpacity(double o) = 0; // 半透明度[0,1]
|
||||||
|
};
|
||||||
|
// 工厂:按平面 z 造一份平面底图(底图所需 scene/渲染窗/frame/数据半径规则由 app 闭包捕获)。
|
||||||
|
// 未注入(空)则不建底图——便于无 VTK 的纯逻辑单测。
|
||||||
|
using PlaneBasemapFactory = std::function<std::unique_ptr<IPlaneBasemap>(double groundZ)>;
|
||||||
|
|
||||||
class IDatasetRenderStrategy {
|
class IDatasetRenderStrategy {
|
||||||
public:
|
public:
|
||||||
virtual ~IDatasetRenderStrategy() = default;
|
virtual ~IDatasetRenderStrategy() = default;
|
||||||
|
|
@ -59,13 +74,26 @@ public:
|
||||||
explicit Plane2DRenderStrategy(VtkSceneController& ctrl) : ctrl_(ctrl) {}
|
explicit Plane2DRenderStrategy(VtkSceneController& ctrl) : ctrl_(ctrl) {}
|
||||||
void add(const std::string& typeId, const std::string& dsId) override;
|
void add(const std::string& typeId, const std::string& dsId) override;
|
||||||
void remove(const std::string& dsId) override;
|
void remove(const std::string& dsId) override;
|
||||||
void onTypeDeactivated(const std::string& typeId) override;
|
void onTypeActivated(const std::string& typeId) override; // 首勾:建该类型平面矢量底图
|
||||||
// 滑块整体升降该类型平面 z:更新 planeReg_ 后,对该类型已勾选足迹移除并按新 z 重摆。
|
void onTypeDeactivated(const std::string& typeId) override; // 全消:销毁该类型底图(瓦片随之消失)
|
||||||
|
// 滑块整体升降该类型平面 z:更新 planeReg_ 后,对该类型已勾选足迹移除并按新 z 重摆 + 底图重建于新 z。
|
||||||
void setPlaneZ(const std::string& typeId, double z);
|
void setPlaneZ(const std::string& typeId, double z);
|
||||||
|
// 底图工厂注入(main.cpp 构造后一次性下发;未注入则底图建造静默跳过,便于纯逻辑单测)。
|
||||||
|
void setBasemapFactory(PlaneBasemapFactory f) { basemapFactory_ = std::move(f); }
|
||||||
|
void setBasemapKind(const std::string& typeId, int kind); // 0=矢量平面(show)/1=无(hide)
|
||||||
|
void setBasemapOpacity(const std::string& typeId, double o); // 该类型底图半透明度[0,1]
|
||||||
private:
|
private:
|
||||||
|
void createBasemap(const std::string& typeId); // 按当前 z/kind/opacity 建(或重建)该类型底图
|
||||||
|
|
||||||
VtkSceneController& ctrl_;
|
VtkSceneController& ctrl_;
|
||||||
PlaneZRegistry planeReg_; // 按类型的平面 z 生命周期
|
PlaneZRegistry planeReg_; // 按类型的平面 z 生命周期
|
||||||
std::map<std::string, std::string> dsToType_; // dsId→typeId(remove 只得 dsId,需自存反查)
|
std::map<std::string, std::string> dsToType_; // dsId→typeId(remove 只得 dsId,需自存反查)
|
||||||
|
|
||||||
|
// 每 2D 类型一份平面矢量底图(贴该类型平面 z);随平面建/销/升降。键=typeId。
|
||||||
|
std::map<std::string, std::unique_ptr<IPlaneBasemap>> bms_;
|
||||||
|
std::map<std::string, int> bmKind_; // 该类型底图选择(0=矢量平面/1=无),重建时复用
|
||||||
|
std::map<std::string, double> bmOpacity_; // 该类型底图透明度,重建时复用
|
||||||
|
PlaneBasemapFactory basemapFactory_; // app 注入的底图工厂(空=不建底图)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace geopro::controller
|
} // namespace geopro::controller
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,18 @@ void VtkSceneController::setPlaneZ(const QString& typeId, double z) {
|
||||||
if (plane2d_) plane2d_->setPlaneZ(typeId.toStdString(), z);
|
if (plane2d_) plane2d_->setPlaneZ(typeId.toStdString(), z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VtkSceneController::setPlaneBasemapFactory(PlaneBasemapFactory factory) {
|
||||||
|
if (plane2d_) plane2d_->setBasemapFactory(std::move(factory));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VtkSceneController::setBasemapKind(const QString& typeId, int kind) {
|
||||||
|
if (plane2d_) plane2d_->setBasemapKind(typeId.toStdString(), kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VtkSceneController::setBasemapOpacity(const QString& typeId, double opacity) {
|
||||||
|
if (plane2d_) plane2d_->setBasemapOpacity(typeId.toStdString(), opacity);
|
||||||
|
}
|
||||||
|
|
||||||
IDatasetRenderStrategy* VtkSceneController::strategyForType(const std::string& typeId) const {
|
IDatasetRenderStrategy* VtkSceneController::strategyForType(const std::string& typeId) const {
|
||||||
for (const auto& d : geopro::data::categoryCatalog())
|
for (const auto& d : geopro::data::categoryCatalog())
|
||||||
if (d.id == typeId) return registry_.get(d.renderStrategyId);
|
if (d.id == typeId) return registry_.get(d.renderStrategyId);
|
||||||
|
|
@ -316,12 +328,6 @@ void VtkSceneController::zoomIn() { view_.zoom(1.2); }
|
||||||
void VtkSceneController::zoomOut() { view_.zoom(1.0 / 1.2); }
|
void VtkSceneController::zoomOut() { view_.zoom(1.0 / 1.2); }
|
||||||
void VtkSceneController::fit() { view_.fitView(); }
|
void VtkSceneController::fit() { view_.fitView(); }
|
||||||
|
|
||||||
const geopro::core::Grid& VtkSceneController::grid(const std::string& dsId) {
|
|
||||||
auto it = gridCache_.find(dsId);
|
|
||||||
if (it == gridCache_.end()) it = gridCache_.emplace(dsId, dsRepo_.loadGrid(dsId)).first;
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
const geopro::core::ColorScale& VtkSceneController::colorScale(const std::string& dsId) {
|
const geopro::core::ColorScale& VtkSceneController::colorScale(const std::string& dsId) {
|
||||||
auto it = colorScaleCache_.find(dsId);
|
auto it = colorScaleCache_.find(dsId);
|
||||||
if (it == colorScaleCache_.end())
|
if (it == colorScaleCache_.end())
|
||||||
|
|
@ -331,7 +337,6 @@ const geopro::core::ColorScale& VtkSceneController::colorScale(const std::string
|
||||||
|
|
||||||
void VtkSceneController::rebuildInternal() {
|
void VtkSceneController::rebuildInternal() {
|
||||||
const unsigned long long gen = ++rebuildGeneration_; // 自增:作废此前所有在途增量回调
|
const unsigned long long gen = ++rebuildGeneration_; // 自增:作废此前所有在途增量回调
|
||||||
const bool is2D = (mode_ == ViewMode::Map2D);
|
|
||||||
|
|
||||||
view_.clear(); // 移除全部数据图元(保留底图);frame 重锚标志复位
|
view_.clear(); // 移除全部数据图元(保留底图);frame 重锚标志复位
|
||||||
loadingDs_.clear(); // 旧在途加载随之作废(回调按 gen 丢弃)
|
loadingDs_.clear(); // 旧在途加载随之作废(回调按 gen 丢弃)
|
||||||
|
|
@ -343,9 +348,6 @@ void VtkSceneController::rebuildInternal() {
|
||||||
|
|
||||||
// 坏 dsId(loadGrid/loadColorScale 抛异常)= best-effort 跳过:emit loadFailed 但不中断。
|
// 坏 dsId(loadGrid/loadColorScale 抛异常)= best-effort 跳过:emit loadFailed 但不中断。
|
||||||
try {
|
try {
|
||||||
if (is2D) {
|
|
||||||
for (const auto& [dsId, typeId] : checked_) view_.addSurveyLine(grid(dsId));
|
|
||||||
} else {
|
|
||||||
// 回调用 QPointer<self> 守对象存活 + gen 守数据新鲜:迟到回调若已析构/作废则丢弃。
|
// 回调用 QPointer<self> 守对象存活 + gen 守数据新鲜:迟到回调若已析构/作废则丢弃。
|
||||||
QPointer<VtkSceneController> self(this);
|
QPointer<VtkSceneController> self(this);
|
||||||
if (showTerrain_) {
|
if (showTerrain_) {
|
||||||
|
|
@ -364,13 +366,12 @@ void VtkSceneController::rebuildInternal() {
|
||||||
// 已在 setCheckedDatasets 计入;策略 add 内部转调 addDatasetAsync/add2DDatasetAsync)。
|
// 已在 setCheckedDatasets 计入;策略 add 内部转调 addDatasetAsync/add2DDatasetAsync)。
|
||||||
for (const auto& [dsId, typeId] : checked_)
|
for (const auto& [dsId, typeId] : checked_)
|
||||||
if (auto* s = strategyForType(typeId)) s->add(typeId, dsId);
|
if (auto* s = strategyForType(typeId)) s->add(typeId, dsId);
|
||||||
}
|
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
emit loadFailed(QString::fromStdString(e.what()));
|
emit loadFailed(QString::fromStdString(e.what()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保留相机重建(改VE):不 ResetCamera,原地按新夸张重绘。
|
// 保留相机重建(改VE):不 ResetCamera,原地按新夸张重绘。视图恒三维(is2D=false)。
|
||||||
view_.render(is2D, /*resetCamera=*/!preserveCameraOnRebuild_);
|
view_.render(/*is2D=*/false, /*resetCamera=*/!preserveCameraOnRebuild_);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace geopro::controller
|
} // namespace geopro::controller
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ namespace geopro::controller {
|
||||||
|
|
||||||
class DatasetViewState; // 跨视图共享色阶真源(统一同步机制)
|
class DatasetViewState; // 跨视图共享色阶真源(统一同步机制)
|
||||||
|
|
||||||
// 中央视图模式:二维地图(俯视测线)/ 三维视图(帘面/体素/地形)。
|
// 中央视图模式:固定三维视图(帘面/体素/地形)。旧二维俯视测线(Map2D)路径已退役(main 恒 View3D)。
|
||||||
enum class ViewMode { Map2D, View3D };
|
enum class ViewMode { View3D };
|
||||||
|
|
||||||
// 三维图层("视图详情"浮层勾选)。
|
// 三维图层("视图详情"浮层勾选)。
|
||||||
enum class SceneLayer { Curtain, Voxel, Terrain };
|
enum class SceneLayer { Curtain, Voxel, Terrain };
|
||||||
|
|
@ -49,6 +49,10 @@ public:
|
||||||
// 构造后由 main.cpp 注入一次。
|
// 构造后由 main.cpp 注入一次。
|
||||||
void setViewState(DatasetViewState* state);
|
void setViewState(DatasetViewState* state);
|
||||||
|
|
||||||
|
// 注入 2D 平面底图工厂(app 层闭包捕获 scene/渲染窗/frame/数据半径规则,造 TileBasemap 适配器):
|
||||||
|
// 转交 Plane2DRenderStrategy,供各类型平面按需建底图。main.cpp 构造后一次性下发。
|
||||||
|
void setPlaneBasemapFactory(PlaneBasemapFactory factory);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// 勾选并集统一入口(取代旧 setCheckedDatasets(QStringList)/setChecked2DDatasets):
|
// 勾选并集统一入口(取代旧 setCheckedDatasets(QStringList)/setChecked2DDatasets):
|
||||||
// 每项 = (dsId, typeId=描述符 id)。diff vs 上次后按 catalog[typeId].renderStrategyId 派给策略
|
// 每项 = (dsId, typeId=描述符 id)。diff vs 上次后按 catalog[typeId].renderStrategyId 派给策略
|
||||||
|
|
@ -78,6 +82,9 @@ public slots:
|
||||||
const AxisRangeCfg& z);
|
const AxisRangeCfg& z);
|
||||||
// 2D 段「z 值」滑块:整体升降某 2D 类型平面(含其上全部已勾选足迹)。转交 Plane2DRenderStrategy。
|
// 2D 段「z 值」滑块:整体升降某 2D 类型平面(含其上全部已勾选足迹)。转交 Plane2DRenderStrategy。
|
||||||
void setPlaneZ(const QString& typeId, double z);
|
void setPlaneZ(const QString& typeId, double z);
|
||||||
|
// 2D 段「底图」弹窗:切该类型平面底图 矢量平面(0)/无(1) + 透明度[0,1]。转交 Plane2DRenderStrategy。
|
||||||
|
void setBasemapKind(const QString& typeId, int kind);
|
||||||
|
void setBasemapOpacity(const QString& typeId, double opacity);
|
||||||
|
|
||||||
void applyView(ViewDir dir); // 6 向快捷视图
|
void applyView(ViewDir dir); // 6 向快捷视图
|
||||||
void zoomIn(); // Zoom In (×1.2)
|
void zoomIn(); // Zoom In (×1.2)
|
||||||
|
|
@ -119,7 +126,7 @@ private:
|
||||||
// 渲染策略注册表(构造时注册 volume/curtain/plane2d 三策略,各持本控制器引用)。
|
// 渲染策略注册表(构造时注册 volume/curtain/plane2d 三策略,各持本控制器引用)。
|
||||||
RenderStrategyRegistry registry_;
|
RenderStrategyRegistry registry_;
|
||||||
Plane2DRenderStrategy* plane2d_ = nullptr; // registry_ 中 plane2d 策略的裸指针(setPlaneZ 免下转型)
|
Plane2DRenderStrategy* plane2d_ = nullptr; // registry_ 中 plane2d 策略的裸指针(setPlaneZ 免下转型)
|
||||||
ViewMode mode_ = ViewMode::Map2D;
|
ViewMode mode_ = ViewMode::View3D;
|
||||||
bool showCurtain_ = true;
|
bool showCurtain_ = true;
|
||||||
bool showVoxel_ = false;
|
bool showVoxel_ = false;
|
||||||
bool showTerrain_ = false;
|
bool showTerrain_ = false;
|
||||||
|
|
@ -135,7 +142,6 @@ private:
|
||||||
QPointer<DatasetViewState> state_; // 跨视图色阶真源(注入;编辑/加载/重着色都经它;QPointer 防悬挂)
|
QPointer<DatasetViewState> state_; // 跨视图色阶真源(注入;编辑/加载/重着色都经它;QPointer 防悬挂)
|
||||||
|
|
||||||
// 缓存(按 dsId):避免重复读盘/插值。
|
// 缓存(按 dsId):避免重复读盘/插值。
|
||||||
std::map<std::string, geopro::core::Grid> gridCache_;
|
|
||||||
std::map<std::string, geopro::core::ColorScale> colorScaleCache_;
|
std::map<std::string, geopro::core::ColorScale> colorScaleCache_;
|
||||||
// 帘面源网格缓存:帘面重着色需 grid 重建 addCurtain(loadSection 的 s.grid 不在 gridCache_)。
|
// 帘面源网格缓存:帘面重着色需 grid 重建 addCurtain(loadSection 的 s.grid 不在 gridCache_)。
|
||||||
std::map<std::string, geopro::core::Grid> sectionGridCache_;
|
std::map<std::string, geopro::core::Grid> sectionGridCache_;
|
||||||
|
|
@ -154,7 +160,6 @@ private:
|
||||||
// 正在加载的 ds:防重复勾选竞态重复请求;全量重建时清空。
|
// 正在加载的 ds:防重复勾选竞态重复请求;全量重建时清空。
|
||||||
std::set<std::string> loadingDs_;
|
std::set<std::string> loadingDs_;
|
||||||
|
|
||||||
const geopro::core::Grid& grid(const std::string& dsId);
|
|
||||||
const geopro::core::ColorScale& colorScale(const std::string& dsId);
|
const geopro::core::ColorScale& colorScale(const std::string& dsId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace geopro::app {
|
|
||||||
|
|
||||||
// 一个数据类型大类段的配置(spec §5)。识别键二选一:dsTypeCode 优先;ddCode 用于三维体/切片。
|
|
||||||
struct CategorySpec {
|
|
||||||
std::string id; // 段稳定 id
|
|
||||||
std::string title; // 段标题(UI 显示)
|
|
||||||
std::string dsTypeCode; // 主识别键(空=不按 dsTypeCode)
|
|
||||||
std::string ddCode; // 次识别键(dd_voxel/dd_slice;空=不按 ddCode)
|
|
||||||
bool canGenerateVolume; // 段内是否提供「生成三维体」入口(仅反演类)
|
|
||||||
bool hasArrayTypeFilter; // 段头是否显示装置类型筛选(仅 ERT 类)
|
|
||||||
};
|
|
||||||
|
|
||||||
// 5 段固定有序(spec §5 表)。
|
|
||||||
inline const std::vector<CategorySpec>& categoryConfigs() {
|
|
||||||
static const std::vector<CategorySpec> kCfg = {
|
|
||||||
{"resistivity", "电阻率数据", "ERT platform inversion data", "", true, true},
|
|
||||||
{"apparent", "视电阻率数据", "visual resistivity data", "", true, true},
|
|
||||||
{"transient", "瞬变电磁数据", "DD TRANSIENT ELECTROMAGNETIC INVERSION", "", true, false},
|
|
||||||
{"voxel", "三维体", "", "dd_voxel", false, false},
|
|
||||||
// 切片不单列段——挂在三维体段「体→切片/异常」三级树下(spec §8 修订)。
|
|
||||||
};
|
|
||||||
return kCfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace geopro::app
|
|
||||||
|
|
@ -172,11 +172,6 @@ target_sources(geopro_tests PRIVATE
|
||||||
app/test_color_scale_io.cpp
|
app/test_color_scale_io.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/app/ColorScaleIO.cpp
|
${CMAKE_SOURCE_DIR}/src/app/ColorScaleIO.cpp
|
||||||
)
|
)
|
||||||
# 维度过滤纯函数(splitByDimension: ddCode -> 三维/二维/分析三栏,无 Qt/VTK 依赖)。
|
|
||||||
target_sources(geopro_tests PRIVATE
|
|
||||||
app/test_dataset_dimension.cpp
|
|
||||||
${CMAKE_SOURCE_DIR}/src/app/DatasetDimension.cpp
|
|
||||||
)
|
|
||||||
# 大类分类纯函数(splitByCategory: dsTypeCode/ddCode -> 5 个数据类型大类段,无 Qt/VTK 依赖)。
|
# 大类分类纯函数(splitByCategory: dsTypeCode/ddCode -> 5 个数据类型大类段,无 Qt/VTK 依赖)。
|
||||||
target_sources(geopro_tests PRIVATE
|
target_sources(geopro_tests PRIVATE
|
||||||
app/test_dataset_category.cpp
|
app/test_dataset_category.cpp
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include "DatasetDimension.hpp"
|
|
||||||
#include "repo/RepoTypes.hpp"
|
|
||||||
|
|
||||||
using geopro::data::DsRow;
|
|
||||||
using geopro::app::splitByDimension;
|
|
||||||
using geopro::app::DimBuckets;
|
|
||||||
|
|
||||||
static DsRow row(const char* id, const char* ddCode) {
|
|
||||||
DsRow r; r.id = id; r.ddCode = ddCode; return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DatasetDimension, SplitsByDdCode) {
|
|
||||||
std::vector<DsRow> in{
|
|
||||||
row("a", "dd_section"), // 3D
|
|
||||||
row("b", "dd_voxel"), // 3D
|
|
||||||
row("f", "dd_radar_3d"), // 3D(三维雷达体,spec §6.1)
|
|
||||||
row("c", "dd_trajectory_data"), // 2D
|
|
||||||
row("d", "dd_slice"), // Analysis
|
|
||||||
row("e", "dd_unknownxyz"), // Other -> not in any bucket
|
|
||||||
};
|
|
||||||
DimBuckets b = splitByDimension(in);
|
|
||||||
ASSERT_EQ(b.dim3D.size(), 3u);
|
|
||||||
EXPECT_EQ(b.dim3D[0].id, "a");
|
|
||||||
EXPECT_EQ(b.dim3D[1].id, "b");
|
|
||||||
EXPECT_EQ(b.dim3D[2].id, "f");
|
|
||||||
ASSERT_EQ(b.dim2D.size(), 1u);
|
|
||||||
EXPECT_EQ(b.dim2D[0].id, "c");
|
|
||||||
ASSERT_EQ(b.analysis.size(), 1u);
|
|
||||||
EXPECT_EQ(b.analysis[0].id, "d");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DatasetDimension, EmptyInput) {
|
|
||||||
DimBuckets b = splitByDimension({});
|
|
||||||
EXPECT_TRUE(b.dim3D.empty());
|
|
||||||
EXPECT_TRUE(b.dim2D.empty());
|
|
||||||
EXPECT_TRUE(b.analysis.empty());
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue