feat(view): 左下数据列表 + 对象树收到测线层(对齐原型, 增量2)
- 对象树 GS→TM(测线复选, UserRole+2=tmId); DS(采集批次)移出树, 入左下「数据真实显示栏」 (QTabWidget 数据/文件; panels/DatasetListPanel)。findTm 按 tmId 查 TM。 - 中央 rebuildCentral 改遍历勾选的测线 → 渲染其 dd_section(可多条共存)。 - 树单击测线→填数据列表; 数据列表单击采集批次→loadDataset(数据详情+异常列表+属性,抽共享 lambda)。 - 启动自动选首个含 dd_section 的测线 + 首数据集(对齐原型默认载入态)。 - structure 取一次共享; app 构建干净; 待人工登录复核。
This commit is contained in:
parent
127e9a0b21
commit
50c4de4019
|
|
@ -13,7 +13,8 @@
|
||||||
桌面 app `geopro_desktop`:
|
桌面 app `geopro_desktop`:
|
||||||
- **真实登录**:LoginWindow(用户名/密码/图形验证码/记住)→ `verifyCodeCheck` → RSA 加密密码 → `login2` → token → 进工作台。**真机登录成功**;输入框样式已修(三态白底深字)。
|
- **真实登录**:LoginWindow(用户名/密码/图形验证码/记住)→ `verifyCodeCheck` → RSA 加密密码 → `login2` → token → 进工作台。**真机登录成功**;输入框样式已修(三态白底深字)。
|
||||||
- **工作台 ADS 三区 + 数据详情**:
|
- **工作台 ADS 三区 + 数据详情**:
|
||||||
- **左 对象树**:GS→TM→DS,复选框勾选 → 控制中央显示哪些测线。
|
- **左上 对象显示栏**:GS→TM(测线),复选框勾选测线 → 控制中央显示哪些测线的 dd_section。
|
||||||
|
- **左下 数据真实显示栏**(对齐原型):单击测线 → 列其采集批次(数据集,tab 数据/文件);单击采集批次 → 数据详情+异常列表+属性。启动自动选首测线+首数据集。
|
||||||
- **中央 二维地图 / 三维视图**(两个**真内容**,非相机切换):
|
- **中央 二维地图 / 三维视图**(两个**真内容**,非相机切换):
|
||||||
- 二维地图 = `MapLineActor`:测线 `lat/lon` 轨迹**红线**俯视(浅底),像地图。
|
- 二维地图 = `MapLineActor`:测线 `lat/lon` 轨迹**红线**俯视(浅底),像地图。
|
||||||
- 三维视图 = `CurtainActor`:沿测线的**竖直断面墙**(分段色带,z 纵向夸张×3,沿弯曲测线弯)。中央工具条**仅**「二维地图/三维视图」(对齐原型,无体素按钮)。
|
- 三维视图 = `CurtainActor`:沿测线的**竖直断面墙**(分段色带,z 纵向夸张×3,沿弯曲测线弯)。中央工具条**仅**「二维地图/三维视图」(对齐原型,无体素按钮)。
|
||||||
|
|
@ -76,7 +77,7 @@
|
||||||
9. render 仍部分内联在 main.cpp;可逐步抽到 view/controller。
|
9. render 仍部分内联在 main.cpp;可逐步抽到 view/controller。
|
||||||
10. **布局对齐原型**(权威参考 `http://prototype.geomative.cn/`;截图存 `.playwright-mcp/`)。**计划见 `plans/2026-06-08-m1-prototype-layout.md`(六面板 + view/ 抽取,增量序列)**。进度:
|
10. **布局对齐原型**(权威参考 `http://prototype.geomative.cn/`;截图存 `.playwright-mcp/`)。**计划见 `plans/2026-06-08-m1-prototype-layout.md`(六面板 + view/ 抽取,增量序列)**。进度:
|
||||||
- ✅ **增量1 右上「异常列表」**(2026-06-08,`panels/AnomalyListPanel`,与数据详情显隐联动;待人工复核)。
|
- ✅ **增量1 右上「异常列表」**(2026-06-08,`panels/AnomalyListPanel`,与数据详情显隐联动;待人工复核)。
|
||||||
- ⬜ **增量2 左下「数据列表」**+ 对象树到 TM 层(DS 移出树入数据列表)。
|
- ✅ **增量2 左下「数据列表」+ 对象树到 TM 层**(2026-06-08,`panels/DatasetListPanel`;树 GS→TM 复选驱动中央, DS 移出树入数据列表 tab 数据/文件, DS 单击→详情+异常+属性, 启动自动选首测线/首数据集;待人工复核)。
|
||||||
- ⬜ **增量3 3D「视图详情」图层浮层**(体素的正确归宿;体素引擎已就绪,UI 待此接入)。
|
- ⬜ **增量3 3D「视图详情」图层浮层**(体素的正确归宿;体素引擎已就绪,UI 待此接入)。
|
||||||
- ⬜ **增量4 数据详情富工具条 + 电极标记 + 数值标签**;底图影像=DEM/底图任务。
|
- ⬜ **增量4 数据详情富工具条 + 电极标记 + 数值标签**;底图影像=DEM/底图任务。
|
||||||
- 架构:新面板抽到 `src/app/panels/`(暂随 app 编译,如 login/),控制 main.cpp 体量;后续可升 `src/view/` 库。
|
- 架构:新面板抽到 `src/app/panels/`(暂随 app 编译,如 login/),控制 main.cpp 体量;后续可升 `src/view/` 库。
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,11 @@
|
||||||
- 放右上 dock(与"属性"分上下或 tab)。**人工复核**:单击数据集→右上列出 3 异常;眼睛切换隐藏对应虚线。
|
- 放右上 dock(与"属性"分上下或 tab)。**人工复核**:单击数据集→右上列出 3 异常;眼睛切换隐藏对应虚线。
|
||||||
- 提交 `feat(view): 右上异常列表面板 + 与数据详情异常显隐联动`。
|
- 提交 `feat(view): 右上异常列表面板 + 与数据详情异常显隐联动`。
|
||||||
|
|
||||||
### 增量 2:左下「数据列表」+ 树结构调整(树到 TM,DS 入数据列表)
|
### 增量 2:左下「数据列表」+ 树结构调整 ✅ 已完成(2026-06-08)
|
||||||
|
> `panels/DatasetListPanel`(populateDatasetList)。树 `populateTree` 改 GS→TM(测线复选,UserRole+2=tmId);
|
||||||
|
> `findTm` 按 tmId 查 TM。中央 rebuildCentral 改遍历勾选 TM→渲染其 dd_section。左下 dock = QTabWidget
|
||||||
|
> (数据 QListWidget / 文件占位)。树单击 TM→填数据列表;数据列表单击 DS→`loadDataset`(详情+异常+属性,
|
||||||
|
> 抽成共享 lambda)。启动自动选首含 dd_section 的测线+首数据集。app 构建净;**待人工复核**。**原计划存档**:
|
||||||
- repo.loadStructure 改为树到 **TM** 层(GS→TM),DS 不再进树;新增 `listDatasets(tmId)` 或复用结构。
|
- repo.loadStructure 改为树到 **TM** 层(GS→TM),DS 不再进树;新增 `listDatasets(tmId)` 或复用结构。
|
||||||
(当前样本仅 1 DS grid1 挂 ERT1;多 TM/DS 为 mock 结构,先支持单条,预留多条。)
|
(当前样本仅 1 DS grid1 挂 ERT1;多 TM/DS 为 mock 结构,先支持单条,预留多条。)
|
||||||
- `src/view/panels/DatasetListPanel`:tab 数据/文件;列选中 TM 的采集批次;单击 → 数据详情 + 属性。
|
- `src/view/panels/DatasetListPanel`:tab 数据/文件;列选中 TM 的采集批次;单击 → 数据详情 + 属性。
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ find_package(nlohmann_json CONFIG REQUIRED)
|
||||||
add_executable(geopro_desktop WIN32
|
add_executable(geopro_desktop WIN32
|
||||||
main.cpp
|
main.cpp
|
||||||
login/LoginWindow.cpp
|
login/LoginWindow.cpp
|
||||||
panels/AnomalyListPanel.cpp)
|
panels/AnomalyListPanel.cpp
|
||||||
|
panels/DatasetListPanel.cpp)
|
||||||
|
|
||||||
target_include_directories(geopro_desktop PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(geopro_desktop PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
|
|
||||||
198
src/app/main.cpp
198
src/app/main.cpp
|
|
@ -1,5 +1,6 @@
|
||||||
// M1 工作台(视图重构 Task B):正确产品模型。
|
// M1 工作台(视图重构 Task B):正确产品模型。
|
||||||
// - 左 对象树:GS→TM→DS(复选框)。勾选 dd_section → 在中央当前视图显示该数据集,可多条共存。
|
// - 左上 对象显示栏:GS→TM(测线,复选框)。勾选测线 → 在中央显示其 dd_section,可多条共存。
|
||||||
|
// - 左下 数据真实显示栏:单击测线 → 列其采集批次(数据集,tab 数据/文件)。单击采集批次 → 数据详情+异常+属性。
|
||||||
// - 中央「二维地图 / 三维视图」:两个互斥视图(内容不同,不是同一物体换相机)。
|
// - 中央「二维地图 / 三维视图」:两个互斥视图(内容不同,不是同一物体换相机)。
|
||||||
// 二维地图 = 对每个勾选数据集 buildSurveyLine(lat/lon 红线俯视,z=0)+ applyTop2D(浅底背景)。
|
// 二维地图 = 对每个勾选数据集 buildSurveyLine(lat/lon 红线俯视,z=0)+ applyTop2D(浅底背景)。
|
||||||
// 三维视图 = 对每个勾选数据集 buildCurtain(竖直断面墙),actor SetScale(1,1,3) 纵向夸张 + applyFree3D(白底)。
|
// 三维视图 = 对每个勾选数据集 buildCurtain(竖直断面墙),actor SetScale(1,1,3) 纵向夸张 + applyFree3D(白底)。
|
||||||
|
|
@ -28,6 +29,7 @@
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QListWidgetItem>
|
#include <QListWidgetItem>
|
||||||
#include <QSignalBlocker>
|
#include <QSignalBlocker>
|
||||||
|
#include <QTabWidget>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QSurfaceFormat>
|
#include <QSurfaceFormat>
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
|
|
@ -47,6 +49,7 @@
|
||||||
#include "AuthService.hpp"
|
#include "AuthService.hpp"
|
||||||
#include "login/LoginWindow.hpp"
|
#include "login/LoginWindow.hpp"
|
||||||
#include "panels/AnomalyListPanel.hpp"
|
#include "panels/AnomalyListPanel.hpp"
|
||||||
|
#include "panels/DatasetListPanel.hpp"
|
||||||
|
|
||||||
#include "CameraPreset.hpp"
|
#include "CameraPreset.hpp"
|
||||||
#include "Scene.hpp"
|
#include "Scene.hpp"
|
||||||
|
|
@ -70,13 +73,12 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// 角色:DS 项的 dd 类型存在 UserRole+1(dsId 存在 UserRole)。
|
// 角色:树 TM 项存 tmId(UserRole+2);数据列表 DS 项的 dsId/ddType 由 panels/DatasetListPanel 定义。
|
||||||
constexpr int kRoleDsId = Qt::UserRole;
|
constexpr int kRoleTmId = Qt::UserRole + 2;
|
||||||
constexpr int kRoleDdType = Qt::UserRole + 1;
|
|
||||||
|
|
||||||
// 从对象结构树构建 QTreeWidget:GS → TM → DS 三层。
|
// 从对象结构树构建 QTreeWidget:GS → TM 两层(对齐原型;DS=采集批次在左下「数据列表」,不进树)。
|
||||||
// DS 项可勾选(复选框):勾选驱动该测线竖直帘面在中央场景显示;UserRole 存 dsId、UserRole+1 存 ddType。
|
// TM(测线) 项可勾选(复选框):勾选驱动该测线的 dd_section 在中央场景显示;UserRole+2 存 tmId。
|
||||||
// 网格剖面(dd_section)默认勾选,启动即显示帘面。
|
// 含 dd_section 的测线默认勾选,启动即显示。
|
||||||
void populateTree(QTreeWidget* tree, const std::vector<geopro::data::GsNode>& gss)
|
void populateTree(QTreeWidget* tree, const std::vector<geopro::data::GsNode>& gss)
|
||||||
{
|
{
|
||||||
for (const auto& gs : gss) {
|
for (const auto& gs : gss) {
|
||||||
|
|
@ -85,21 +87,27 @@ void populateTree(QTreeWidget* tree, const std::vector<geopro::data::GsNode>& gs
|
||||||
for (const auto& tm : gs.tms) {
|
for (const auto& tm : gs.tms) {
|
||||||
auto* tmItem = new QTreeWidgetItem(gsItem);
|
auto* tmItem = new QTreeWidgetItem(gsItem);
|
||||||
tmItem->setText(0, QString::fromStdString(tm.name));
|
tmItem->setText(0, QString::fromStdString(tm.name));
|
||||||
for (const auto& ds : tm.dss) {
|
tmItem->setData(0, kRoleTmId, QString::fromStdString(tm.id));
|
||||||
auto* dsItem = new QTreeWidgetItem(tmItem);
|
tmItem->setFlags(tmItem->flags() | Qt::ItemIsUserCheckable);
|
||||||
dsItem->setText(0, QString::fromStdString(ds.name));
|
const bool hasSection =
|
||||||
dsItem->setData(0, kRoleDsId, QString::fromStdString(ds.id));
|
std::any_of(tm.dss.begin(), tm.dss.end(),
|
||||||
dsItem->setData(0, kRoleDdType, QString::fromStdString(ds.ddType));
|
[](const geopro::data::DsNode& d) { return d.ddType == "dd_section"; });
|
||||||
dsItem->setFlags(dsItem->flags() | Qt::ItemIsUserCheckable);
|
tmItem->setCheckState(0, hasSection ? Qt::Checked : Qt::Unchecked);
|
||||||
// 网格剖面默认勾选 → 启动即显帘面;其余默认不勾。
|
|
||||||
dsItem->setCheckState(
|
|
||||||
0, ds.ddType == "dd_section" ? Qt::Checked : Qt::Unchecked);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tree->expandAll();
|
tree->expandAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在结构中按 tmId 查 TM;找不到返回 nullptr。
|
||||||
|
const geopro::data::TmNode* findTm(const std::vector<geopro::data::GsNode>& gss,
|
||||||
|
const std::string& tmId)
|
||||||
|
{
|
||||||
|
for (const auto& gs : gss)
|
||||||
|
for (const auto& tm : gs.tms)
|
||||||
|
if (tm.id == tmId) return &tm;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// 读取 RSA 公钥 PEM 全文(登录时密码加密用)。读不到返回空串,登录将报错。
|
// 读取 RSA 公钥 PEM 全文(登录时密码加密用)。读不到返回空串,登录将报错。
|
||||||
std::string readPem(const std::string& path)
|
std::string readPem(const std::string& path)
|
||||||
{
|
{
|
||||||
|
|
@ -225,13 +233,27 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
// 放在中央视图下方。
|
// 放在中央视图下方。
|
||||||
dockManager->addDockWidget(ads::BottomDockWidgetArea, detailDock, centerDockArea);
|
dockManager->addDockWidget(ads::BottomDockWidgetArea, detailDock, centerDockArea);
|
||||||
|
|
||||||
// 左 dock:对象树。
|
// 项目结构(GS→TM→DS):取一次共享,供树/中央/数据列表查 TM 的数据集。
|
||||||
|
auto structure = std::make_shared<std::vector<geopro::data::GsNode>>(repo.loadStructure());
|
||||||
|
|
||||||
|
// 左上 dock:对象树(GS→TM,测线复选)。
|
||||||
auto* tree = new QTreeWidget();
|
auto* tree = new QTreeWidget();
|
||||||
tree->setHeaderLabel(QStringLiteral("对象"));
|
tree->setHeaderLabel(QStringLiteral("对象显示栏"));
|
||||||
populateTree(tree, repo.loadStructure());
|
populateTree(tree, *structure);
|
||||||
auto* leftDock = new ads::CDockWidget(QStringLiteral("对象列表"));
|
auto* leftDock = new ads::CDockWidget(QStringLiteral("对象显示栏"));
|
||||||
leftDock->setWidget(tree);
|
leftDock->setWidget(tree);
|
||||||
dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock);
|
auto* leftArea = dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock);
|
||||||
|
|
||||||
|
// 左下 dock:数据真实显示栏(选中测线后列其采集批次=数据集;tab 数据/文件)。
|
||||||
|
auto* datasetTabs = new QTabWidget();
|
||||||
|
auto* datasetList = new QListWidget();
|
||||||
|
datasetList->setAlternatingRowColors(true);
|
||||||
|
datasetTabs->addTab(datasetList, QStringLiteral("数据"));
|
||||||
|
auto* fileList = new QListWidget(); // M1 文件 tab 占位
|
||||||
|
datasetTabs->addTab(fileList, QStringLiteral("文件"));
|
||||||
|
auto* datasetDock = new ads::CDockWidget(QStringLiteral("数据真实显示栏"));
|
||||||
|
datasetDock->setWidget(datasetTabs);
|
||||||
|
dockManager->addDockWidget(ads::BottomDockWidgetArea, datasetDock, leftArea);
|
||||||
|
|
||||||
// 右上 dock:异常列表(对齐原型;颜色块 + 名称 + 位置/深/尺寸 + 勾选显隐,与数据详情异常联动)。
|
// 右上 dock:异常列表(对齐原型;颜色块 + 名称 + 位置/深/尺寸 + 勾选显隐,与数据详情异常联动)。
|
||||||
auto* anomalyList = new QListWidget();
|
auto* anomalyList = new QListWidget();
|
||||||
|
|
@ -250,30 +272,19 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
dockManager->addDockWidget(ads::BottomDockWidgetArea, propDock, rightArea);
|
dockManager->addDockWidget(ads::BottomDockWidgetArea, propDock, rightArea);
|
||||||
|
|
||||||
// ── 中央视图重建(核心)─────────────────────────────────────────────
|
// ── 中央视图重建(核心)─────────────────────────────────────────────
|
||||||
// 两个互斥视图按当前勾选集整体重建:scene.clear() → 对每个勾选 dd_section 加对应 actor。
|
// 按勾选的测线(TM)整体重建:scene.clear() → 对每个勾选 TM 的 dd_section 加对应 actor。
|
||||||
// 二维地图 = buildSurveyLine(红线俯视,浅底背景)+ applyTop2D。
|
// 二维地图 = buildSurveyLine(红线俯视,浅底背景)+ applyTop2D。
|
||||||
// 三维视图 = buildCurtain(断面墙)SetScale(1,1,kCurtainZScale) + applyFree3D(白底)。
|
// 三维视图 = buildCurtain(断面墙)SetScale(1,1,kCurtainZScale) + applyFree3D(白底)。
|
||||||
// frame 全局共享;切视图/勾选变化都调用此函数重建当前视图。
|
// frame/structure 全局共享;切视图/勾选变化都调用此函数重建当前视图。
|
||||||
auto rebuildCentral = [scene, rendererPtr, renderWindowPtr, viewMode, &repo, frame, tree]() {
|
auto rebuildCentral = [scene, rendererPtr, renderWindowPtr, viewMode, &repo, frame, tree,
|
||||||
|
structure]() {
|
||||||
scene->clear();
|
scene->clear();
|
||||||
|
|
||||||
const bool is2D = (*viewMode == ViewMode::Map2D);
|
const bool is2D = (*viewMode == ViewMode::Map2D);
|
||||||
rendererPtr->SetBackground(is2D ? 0.96 : 1.0, is2D ? 0.97 : 1.0, is2D ? 0.99 : 1.0);
|
rendererPtr->SetBackground(is2D ? 0.96 : 1.0, is2D ? 0.97 : 1.0, is2D ? 0.99 : 1.0);
|
||||||
|
|
||||||
// 遍历对象树收集所有勾选的 dd_section,逐个加入当前视图内容。
|
// 渲染单个 dd_section 数据集到当前视图。
|
||||||
QList<QTreeWidgetItem*> stack;
|
auto renderSection = [&](const std::string& id) {
|
||||||
for (int i = 0; i < tree->topLevelItemCount(); ++i) stack.append(tree->topLevelItem(i));
|
|
||||||
while (!stack.isEmpty()) {
|
|
||||||
QTreeWidgetItem* cur = stack.takeFirst();
|
|
||||||
for (int i = 0; i < cur->childCount(); ++i) stack.append(cur->child(i));
|
|
||||||
|
|
||||||
const QString dsId = cur->data(0, kRoleDsId).toString();
|
|
||||||
if (dsId.isEmpty()) continue; // GS/TM 节点忽略
|
|
||||||
if (cur->checkState(0) != Qt::Checked) continue; // 仅显示勾选的
|
|
||||||
const QString ddType = cur->data(0, kRoleDdType).toString();
|
|
||||||
if (ddType != "dd_section") continue; // 当前仅支持剖面网格
|
|
||||||
|
|
||||||
const std::string id = dsId.toStdString();
|
|
||||||
const auto g = repo.loadGrid(id);
|
const auto g = repo.loadGrid(id);
|
||||||
if (is2D) {
|
if (is2D) {
|
||||||
auto line = geopro::render::buildSurveyLine(g, *frame);
|
auto line = geopro::render::buildSurveyLine(g, *frame);
|
||||||
|
|
@ -286,6 +297,22 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
scene->addActor(curtain);
|
scene->addActor(curtain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 遍历对象树收集所有勾选的测线(TM),渲染其 dd_section 数据集(可多条共存)。
|
||||||
|
QList<QTreeWidgetItem*> stack;
|
||||||
|
for (int i = 0; i < tree->topLevelItemCount(); ++i) stack.append(tree->topLevelItem(i));
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
QTreeWidgetItem* cur = stack.takeFirst();
|
||||||
|
for (int i = 0; i < cur->childCount(); ++i) stack.append(cur->child(i));
|
||||||
|
|
||||||
|
const QString tmId = cur->data(0, kRoleTmId).toString();
|
||||||
|
if (tmId.isEmpty()) continue; // GS 节点忽略
|
||||||
|
if (cur->checkState(0) != Qt::Checked) continue; // 仅显示勾选的测线
|
||||||
|
const auto* tm = findTm(*structure, tmId.toStdString());
|
||||||
|
if (!tm) continue;
|
||||||
|
for (const auto& ds : tm->dss)
|
||||||
|
if (ds.ddType == "dd_section") renderSection(ds.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is2D)
|
if (is2D)
|
||||||
|
|
@ -296,13 +323,22 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
renderWindowPtr->Render();
|
renderWindowPtr->Render();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 勾选/取消某 dd_section → 重建当前视图内容(勾的才显示;可多条共存)。
|
// 勾选/取消某测线(TM) → 重建当前视图内容(勾的才显示;可多条共存)。
|
||||||
QObject::connect(tree, &QTreeWidget::itemChanged, tree,
|
QObject::connect(tree, &QTreeWidget::itemChanged, tree,
|
||||||
[rebuildCentral](QTreeWidgetItem* item, int) {
|
[rebuildCentral](QTreeWidgetItem* item, int) {
|
||||||
if (item->data(0, kRoleDsId).toString().isEmpty()) return; // GS/TM 忽略
|
if (item->data(0, kRoleTmId).toString().isEmpty()) return; // GS 忽略
|
||||||
rebuildCentral();
|
rebuildCentral();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 单击测线(TM) → 左下数据列表填充其采集批次(数据集)。
|
||||||
|
QObject::connect(tree, &QTreeWidget::itemClicked, tree,
|
||||||
|
[structure, datasetList](QTreeWidgetItem* item, int) {
|
||||||
|
const QString tmId = item->data(0, kRoleTmId).toString();
|
||||||
|
if (tmId.isEmpty()) return; // GS 节点无数据集
|
||||||
|
const auto* tm = findTm(*structure, tmId.toStdString());
|
||||||
|
if (tm) geopro::app::populateDatasetList(datasetList, tm->dss);
|
||||||
|
});
|
||||||
|
|
||||||
// ── 数据详情共享状态 + 重建 ──────────────────────────────────────────
|
// ── 数据详情共享状态 + 重建 ──────────────────────────────────────────
|
||||||
// 当前选中数据集 id(空=未选)与详情显示模式(反演剖面/原数据);切模式或换选中都重建。
|
// 当前选中数据集 id(空=未选)与详情显示模式(反演剖面/原数据);切模式或换选中都重建。
|
||||||
auto currentDsId = std::make_shared<QString>();
|
auto currentDsId = std::make_shared<QString>();
|
||||||
|
|
@ -359,37 +395,41 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
detailRenderWindowPtr->Render();
|
detailRenderWindowPtr->Render();
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── 单击 DS → 记选中 + 重建数据详情 + 右侧属性(与勾选区分;不改帘面可见性)──
|
// 加载某数据集到「数据详情 + 异常列表 + 属性」(数据列表单击与启动默认共用)。
|
||||||
QObject::connect(
|
auto loadDataset = [&repo, propLabel, currentDsId, rebuildDetail, anomalyList, hiddenAnoms](
|
||||||
tree, &QTreeWidget::itemClicked, tree,
|
const QString& dsId, const QString& name) {
|
||||||
[&repo, propLabel, currentDsId, rebuildDetail, anomalyList, hiddenAnoms](
|
if (dsId.isEmpty()) return;
|
||||||
QTreeWidgetItem* item, int) {
|
*currentDsId = dsId;
|
||||||
const QString dsId = item->data(0, kRoleDsId).toString();
|
|
||||||
if (dsId.isEmpty()) return; // GS/TM 节点无详情
|
|
||||||
const QString ddType = item->data(0, kRoleDdType).toString();
|
|
||||||
if (ddType != "dd_section") return;
|
|
||||||
const QString name = item->text(0);
|
|
||||||
|
|
||||||
*currentDsId = dsId;
|
// 右上异常列表:按该数据集异常重填(默认全显);先清隐藏集再填,避免重建时阻塞信号回灌。
|
||||||
|
const auto anomalies = repo.loadAnomalies(dsId.toStdString());
|
||||||
|
hiddenAnoms->clear();
|
||||||
|
{
|
||||||
|
const QSignalBlocker block(anomalyList); // 重填触发 itemChanged,先屏蔽
|
||||||
|
geopro::app::populateAnomalyList(anomalyList, anomalies);
|
||||||
|
}
|
||||||
|
|
||||||
// 右上异常列表:按该数据集异常重填(默认全显);先清隐藏集再填,避免重建时阻塞信号回灌。
|
rebuildDetail();
|
||||||
const auto anomalies = repo.loadAnomalies(dsId.toStdString());
|
|
||||||
hiddenAnoms->clear();
|
|
||||||
{
|
|
||||||
const QSignalBlocker block(anomalyList); // 重填触发 itemChanged,先屏蔽
|
|
||||||
geopro::app::populateAnomalyList(anomalyList, anomalies);
|
|
||||||
}
|
|
||||||
|
|
||||||
rebuildDetail();
|
// 右下属性(数据集级,与详情模式无关)。
|
||||||
|
const auto g = repo.loadGrid(dsId.toStdString());
|
||||||
|
propLabel->setText(
|
||||||
|
QStringLiteral("数据集: %1\n类型: 剖面网格 (dd_section)\n网格: %2 x %3\n"
|
||||||
|
"vmin / vmax: %4 / %5\n异常: %6 个")
|
||||||
|
.arg(name).arg(g.nx()).arg(g.ny()).arg(g.vmin).arg(g.vmax)
|
||||||
|
.arg(anomalies.size()));
|
||||||
|
};
|
||||||
|
|
||||||
// 右下属性(数据集级,与详情模式无关)。
|
// ── 单击左下数据列表的采集批次(DS) → 加载到数据详情/异常/属性 ──
|
||||||
const auto g = repo.loadGrid(dsId.toStdString());
|
QObject::connect(datasetList, &QListWidget::itemClicked, datasetList,
|
||||||
propLabel->setText(
|
[loadDataset](QListWidgetItem* item) {
|
||||||
QStringLiteral("数据集: %1\n类型: 剖面网格 (dd_section)\n网格: %2 x %3\n"
|
const QString dsId = item->data(geopro::app::kDsIdRole).toString();
|
||||||
"vmin / vmax: %4 / %5\n异常: %6 个")
|
const QString ddType = item->data(geopro::app::kDsDdTypeRole).toString();
|
||||||
.arg(name).arg(g.nx()).arg(g.ny()).arg(g.vmin).arg(g.vmax)
|
if (ddType != "dd_section") return; // 仅剖面网格有详情图
|
||||||
.arg(anomalies.size()));
|
const QString name =
|
||||||
});
|
item->data(Qt::DisplayRole).toString().section('\n', 0, 0);
|
||||||
|
loadDataset(dsId, name);
|
||||||
|
});
|
||||||
|
|
||||||
// ── 异常列表勾选(显隐) → 更新隐藏集 → 重建数据详情 ──
|
// ── 异常列表勾选(显隐) → 更新隐藏集 → 重建数据详情 ──
|
||||||
QObject::connect(anomalyList, &QListWidget::itemChanged, anomalyList,
|
QObject::connect(anomalyList, &QListWidget::itemChanged, anomalyList,
|
||||||
|
|
@ -431,9 +471,27 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
rebuildCentral();
|
rebuildCentral();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── 启动默认:dd_section 已勾选,但 itemChanged 在 connect 之前触发故未渲染。
|
// ── 启动默认:测线已勾选,但 itemChanged 在 connect 之前触发故未渲染;这里重建一次中央内容。
|
||||||
// 这里 connect 之后主动按默认视图(二维地图)重建一次中央内容。
|
|
||||||
rebuildCentral();
|
rebuildCentral();
|
||||||
|
|
||||||
|
// 启动默认:选第一个含 dd_section 的测线 → 填充数据列表 + 加载其首个 dd_section 详情(对齐原型)。
|
||||||
|
for (const auto& gs : *structure) {
|
||||||
|
const geopro::data::TmNode* picked = nullptr;
|
||||||
|
for (const auto& tm : gs.tms) {
|
||||||
|
const bool hasSection =
|
||||||
|
std::any_of(tm.dss.begin(), tm.dss.end(),
|
||||||
|
[](const geopro::data::DsNode& d) { return d.ddType == "dd_section"; });
|
||||||
|
if (hasSection) { picked = &tm; break; }
|
||||||
|
}
|
||||||
|
if (!picked) continue;
|
||||||
|
geopro::app::populateDatasetList(datasetList, picked->dss);
|
||||||
|
for (const auto& ds : picked->dss)
|
||||||
|
if (ds.ddType == "dd_section") {
|
||||||
|
loadDataset(QString::fromStdString(ds.id), QString::fromStdString(ds.name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include "panels/DatasetListPanel.hpp"
|
||||||
|
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// dd 类型 → 中文标注。
|
||||||
|
QString ddTypeLabel(const std::string& ddType)
|
||||||
|
{
|
||||||
|
if (ddType == "dd_section") return QStringLiteral("剖面网格");
|
||||||
|
if (ddType == "dd_voxel") return QStringLiteral("体素");
|
||||||
|
return QString::fromStdString(ddType);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void populateDatasetList(QListWidget* list, const std::vector<geopro::data::DsNode>& dss)
|
||||||
|
{
|
||||||
|
if (!list) return;
|
||||||
|
list->clear();
|
||||||
|
for (const auto& ds : dss) {
|
||||||
|
const QString name = QString::fromStdString(ds.name);
|
||||||
|
const QString label = ddTypeLabel(ds.ddType);
|
||||||
|
QString text = name;
|
||||||
|
if (!label.isEmpty()) text += QStringLiteral("\n%1").arg(label);
|
||||||
|
|
||||||
|
auto* item = new QListWidgetItem(text, list);
|
||||||
|
item->setData(kDsIdRole, QString::fromStdString(ds.id));
|
||||||
|
item->setData(kDsDdTypeRole, QString::fromStdString(ds.ddType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "repo/RepoTypes.hpp"
|
||||||
|
|
||||||
|
class QListWidget;
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
// 数据列表条目角色(与 main.cpp 树一致:Qt::UserRole=dsId、+1=ddType)。
|
||||||
|
constexpr int kDsIdRole = 0x0100; // Qt::UserRole
|
||||||
|
constexpr int kDsDdTypeRole = 0x0101; // Qt::UserRole + 1
|
||||||
|
|
||||||
|
// 用某测线(TM)的数据集(采集批次)填充 QListWidget(对齐原型左下「数据真实显示栏」)。
|
||||||
|
// 每条目 = 名称 +(ddType 标注);UserRole 存 dsId、+1 存 ddType(供单击驱动数据详情)。
|
||||||
|
// 清空旧条目后重填。
|
||||||
|
void populateDatasetList(QListWidget* list, const std::vector<geopro::data::DsNode>& dss);
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
Loading…
Reference in New Issue