feat(view): 右上异常列表面板 + 与数据详情异常显隐联动(对齐原型, 增量1)
- panels/AnomalyListPanel(populateAnomalyList): 颜色块 + 名称(类型) + 由 location.coordinate 派生「位置 Xm·深 Ym·尺寸 Zm」; 可勾选(默认显示), UserRole 存异常下标。 - 右侧 dock 拆上下: 右上「异常列表」/ 右下「属性」(补"异常 N 个")。 - 单击数据集→重填列表(QSignalBlocker 防回灌)+ 清空隐藏集; 勾选变化→更新 hiddenAnoms → rebuildDetail 逐异常按下标过滤显隐(取消勾选→该异常虚线隐藏)。 - 计划落地 plans/2026-06-08-m1-prototype-layout.md(六面板对齐原型, 增量序列); STATUS §6.10 更新。 - app 构建干净; 待人工登录复核交互。
This commit is contained in:
parent
42a7ed16d4
commit
127e9a0b21
|
|
@ -18,7 +18,8 @@
|
||||||
- 二维地图 = `MapLineActor`:测线 `lat/lon` 轨迹**红线**俯视(浅底),像地图。
|
- 二维地图 = `MapLineActor`:测线 `lat/lon` 轨迹**红线**俯视(浅底),像地图。
|
||||||
- 三维视图 = `CurtainActor`:沿测线的**竖直断面墙**(分段色带,z 纵向夸张×3,沿弯曲测线弯)。中央工具条**仅**「二维地图/三维视图」(对齐原型,无体素按钮)。
|
- 三维视图 = `CurtainActor`:沿测线的**竖直断面墙**(分段色带,z 纵向夸张×3,沿弯曲测线弯)。中央工具条**仅**「二维地图/三维视图」(对齐原型,无体素按钮)。
|
||||||
- **下方 数据详情**:工具条「原数据/网格数据」切换 +「显示异常」开关(对齐原型命名)。单击数据集 → 网格数据=`GridContourActor` 平面剖面(#18,colorBar 真实非均匀分段值上色,纵向夸张×1.5);原数据=`ScatterActor` 彩色方块散点(#17,x=距离/y=深度取负,用散点自带色阶);显示异常=`AnomalyActor` 在上图叠加异常 dashed 折线(同纵向夸张对齐)。
|
- **下方 数据详情**:工具条「原数据/网格数据」切换 +「显示异常」开关(对齐原型命名)。单击数据集 → 网格数据=`GridContourActor` 平面剖面(#18,colorBar 真实非均匀分段值上色,纵向夸张×1.5);原数据=`ScatterActor` 彩色方块散点(#17,x=距离/y=深度取负,用散点自带色阶);显示异常=`AnomalyActor` 在上图叠加异常 dashed 折线(同纵向夸张对齐)。
|
||||||
- **右 属性**:名称/网格 nx×ny/vmin·vmax。
|
- **右上 异常列表**(对齐原型):单击数据集→列该数据集异常(颜色块+名称(类型)+派生「位置/深/尺寸」),勾选框显隐,与数据详情异常叠加联动(取消勾选→该异常虚线隐藏)。
|
||||||
|
- **右下 属性**:名称/网格 nx×ny/vmin·vmax/异常数。
|
||||||
- 单元测试累计 **36 个全绿**(core/data/net/render;含 Scatter 2 + Anomaly 4 + VoxelRegister 1、修复了陈旧的 Curtain mapper 类型断言);离屏 `verify_section/map/curtain_3d/scatter/section_anomaly/voxel_top/voxel_3d.png` 均核对正确(scatter 吻合 ref_17、异常吻合 ref_18、体素 footprint 吻合 ref voxel_hslice 的两臂支撑)。
|
- 单元测试累计 **36 个全绿**(core/data/net/render;含 Scatter 2 + Anomaly 4 + VoxelRegister 1、修复了陈旧的 Curtain mapper 类型断言);离屏 `verify_section/map/curtain_3d/scatter/section_anomaly/voxel_top/voxel_3d.png` 均核对正确(scatter 吻合 ref_17、异常吻合 ref_18、体素 footprint 吻合 ref voxel_hslice 的两臂支撑)。
|
||||||
|
|
||||||
## 2. 各 Phase 完成度
|
## 2. 各 Phase 完成度
|
||||||
|
|
@ -73,12 +74,12 @@
|
||||||
7. 多测线:当前样本仅 1 条 dd_section(grid1);多条共存机制已就绪,加数据即叠加。
|
7. 多测线:当前样本仅 1 条 dd_section(grid1);多条共存机制已就绪,加数据即叠加。
|
||||||
8. 取景微调(数据详情/帘面的相机余量);纵向夸张倍数(剖面1.5/帘面3)可做成可调。
|
8. 取景微调(数据详情/帘面的相机余量);纵向夸张倍数(剖面1.5/帘面3)可做成可调。
|
||||||
9. render 仍部分内联在 main.cpp;可逐步抽到 view/controller。
|
9. render 仍部分内联在 main.cpp;可逐步抽到 view/controller。
|
||||||
10. **布局对齐原型**(权威参考 `http://prototype.geomative.cn/`,用户指定;截图存 `.playwright-mcp/`)。原型为**四区六面板**,当前 app 为简化版,缺:
|
10. **布局对齐原型**(权威参考 `http://prototype.geomative.cn/`;截图存 `.playwright-mcp/`)。**计划见 `plans/2026-06-08-m1-prototype-layout.md`(六面板 + view/ 抽取,增量序列)**。进度:
|
||||||
- **左下「数据真实显示栏」**:选中 TM(测线)后列其采集批次(=DS 数据集),tab「数据/文件」。当前 app 把 DS 直接塞树里。
|
- ✅ **增量1 右上「异常列表」**(2026-06-08,`panels/AnomalyListPanel`,与数据详情显隐联动;待人工复核)。
|
||||||
- **右上「异常列表」**:异常条目(名称/深度/尺寸/电阻率 + 颜色标记 + 眼睛显隐),与数据详情「显示异常」联动。
|
- ⬜ **增量2 左下「数据列表」**+ 对象树到 TM 层(DS 移出树入数据列表)。
|
||||||
- **数据详情工具条**:原型还有 色阶配置/滤波处理/显示等值线标签/纵化容差滑块/显示电极/网格 等(当前仅原数据·网格数据·显示异常)。
|
- ⬜ **增量3 3D「视图详情」图层浮层**(体素的正确归宿;体素引擎已就绪,UI 待此接入)。
|
||||||
- **电极标记**:剖面顶部倒三角▼电极位 + 数值标签;**底图影像**(3D 卫星底图 + 测线落地)= DEM/底图任务(CRS 阻塞)。
|
- ⬜ **增量4 数据详情富工具条 + 电极标记 + 数值标签**;底图影像=DEM/底图任务。
|
||||||
诚实记录:已对齐者=中央二维/三维切换、数据详情原数据/网格数据/显示异常、对象树、属性。
|
- 架构:新面板抽到 `src/app/panels/`(暂随 app 编译,如 login/),控制 main.cpp 体量;后续可升 `src/view/` 库。
|
||||||
|
|
||||||
## 7. 渲染验证手段(务必用)
|
## 7. 渲染验证手段(务必用)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
# M1 工作台布局对齐原型(六面板结构 + view/ 抽取)
|
||||||
|
|
||||||
|
> **权威参考**:原型 `http://prototype.geomative.cn/`(用户指定;截图存 `.playwright-mcp/`)。
|
||||||
|
> **背景**:当前 app 是简化版(左对象树 / 中二维三维+数据详情 / 右属性)。功能积木齐全
|
||||||
|
> (帘面/测线线/#18/#17散点/异常/体素引擎),但缺原型那套"面板/图层"结构,导致没有正确的
|
||||||
|
> 交互入口(曾误把体素塞成工具条开关,已移除 `42a7ed1`)。本计划按原型补齐面板。
|
||||||
|
> **铁律**:渲染积木改动先 `render_verify` 出 PNG;app 交互须人工登录肉眼复核。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 原型六面板(权威,逐一核对截图)
|
||||||
|
|
||||||
|
1. **左上 对象显示栏**:项目 → GS-01北区/GS-02南区 → ERT1..4(测线 TM)。复选框 + 彩色线型图标
|
||||||
|
+ 数量徽标 + "+"。**注**:原型树到 **TM(测线)** 层;**DS(采集批次)在左下数据列表**,不在树里。
|
||||||
|
2. **左下 数据真实显示栏 - [选中TM]**:tab「数据(n) / 文件(n)」;列该测线的**采集批次(DS)**
|
||||||
|
(名 #日期 + 道数)。筛选 + 上传图标。单击采集批次 → 驱动数据详情 + 属性。
|
||||||
|
3. **中上 二维地图 / 三维视图**(工具条):右上「n/m 测线可见」+ 全屏。
|
||||||
|
- 三维:卫星底图 + 测线落地线 + 电极 + 左上**「视图详情」图层浮层**(勾选显示哪些图层:
|
||||||
|
测线/帘面/**体素**/地形)+ 右上 天地图底图选择 + 右下 坐标·比例尺。
|
||||||
|
- 二维:测线俯视(底图瓦片 M1.5)。
|
||||||
|
4. **中下 数据详情**(已有雏形):采集批次 tab;「原数据/网格数据」;工具条(异常标注/色阶配置/
|
||||||
|
滤波/显示异常/显示等值线标签/纵化容差/显示电极/显示等值线/网格…);剖面图 + 顶部电极▼ +
|
||||||
|
数值标签 + 异常叠加;色阶条。
|
||||||
|
5. **右上 异常列表 / 对象属性**(tab):异常条目(名 + 位置·深度·尺寸 + 颜色标记 + 眼睛显隐)。
|
||||||
|
筛选 + 添加。与数据详情异常叠加联动。
|
||||||
|
6. **右下 属性**:数据集(采集批次/通道/状态/日期/测线/区)。
|
||||||
|
|
||||||
|
## 当前 app vs 原型差距
|
||||||
|
- 树含 DS(应移到左下数据列表,树到 TM 止)。
|
||||||
|
- 缺 左下数据列表、右上异常列表、3D视图详情图层浮层、电极标记、数值标签、底图、数据详情富工具条。
|
||||||
|
- main.cpp 全内联(~430 行);再加面板会破 800 行铁律 → **须抽到 `src/view/panels/`**(spec §3)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 架构决策:抽到 view/ 面板(spec §3)
|
||||||
|
新增面板不再堆进 main.cpp。按 spec §3 建 `src/view/panels/`:
|
||||||
|
`ObjectTreePanel`、`DatasetListPanel`、`CentralViewPanel`(含 2D/3D + 图层浮层)、`DataDetailPanel`、
|
||||||
|
`AnomalyListPanel`、`PropertyPanel`。main.cpp 仅装配 dock + 连线(或后续引入 controller)。
|
||||||
|
**渐进**:每抽一个面板即构建+人工复核,绿了再下一个,避免一次性大爆破。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 增量序列(每步可独立构建 + 提交;UI 须人工登录复核)
|
||||||
|
|
||||||
|
### 增量 1:右上「异常列表」面板 ✅ 已完成(2026-06-08)
|
||||||
|
> `src/app/panels/AnomalyListPanel.{hpp,cpp}`(`populateAnomalyList`:颜色块+名称(类型)+派生「位置/深/尺寸」,
|
||||||
|
> 可勾选默认显示,UserRole 存异常下标)。右上 dock「异常列表」+ 右下「属性」(上下分)。单击数据集→重填列表
|
||||||
|
> (QSignalBlocker 防回灌)+ hiddenAnoms 清空;勾选变化→更新 hiddenAnoms→rebuildDetail 逐异常按下标过滤显隐。
|
||||||
|
> 属性补"异常 N 个"。app 构建干净;**待人工登录复核**(列表出 3 异常、取消勾选→对应虚线隐藏)。
|
||||||
|
> 提交见下。**原计划如下(存档)**:
|
||||||
|
- `src/view/panels/AnomalyListPanel.{hpp,cpp}`(QWidget + QListWidget/QTreeWidget)。
|
||||||
|
- 数据:`repo.loadAnomalies(id)`;core `Anomaly` 已有 name/typeName/markType/localPts/lineColor。
|
||||||
|
派生**位置(质心距离)**、**深度(质心 y)**、**尺寸(bbox 对角/跨度)** 自 localPts;颜色用 lineColor。
|
||||||
|
(电阻率 Ωm 无源字段,M1 暂不显示或显"—";如需后续用 grid 在异常处采样。)
|
||||||
|
- 每条目:色块 + 名称 + "位置 Xm·深 Ym·尺寸 Zm" + 眼睛显隐。
|
||||||
|
- 联动:单击数据集→填充列表;眼睛 toggle → 该异常 actor `SetVisibility`(buildAnomalies 已每异常一 actor,
|
||||||
|
需让 DataDetailPanel 暴露按 index 设可见或重建时按显隐集过滤)。
|
||||||
|
- 放右上 dock(与"属性"分上下或 tab)。**人工复核**:单击数据集→右上列出 3 异常;眼睛切换隐藏对应虚线。
|
||||||
|
- 提交 `feat(view): 右上异常列表面板 + 与数据详情异常显隐联动`。
|
||||||
|
|
||||||
|
### 增量 2:左下「数据列表」+ 树结构调整(树到 TM,DS 入数据列表)
|
||||||
|
- repo.loadStructure 改为树到 **TM** 层(GS→TM),DS 不再进树;新增 `listDatasets(tmId)` 或复用结构。
|
||||||
|
(当前样本仅 1 DS grid1 挂 ERT1;多 TM/DS 为 mock 结构,先支持单条,预留多条。)
|
||||||
|
- `src/view/panels/DatasetListPanel`:tab 数据/文件;列选中 TM 的采集批次;单击 → 数据详情 + 属性。
|
||||||
|
- 树单击 TM → 填充数据列表;移除"单击树DS"旧路径。
|
||||||
|
- **人工复核**:点 ERT1 → 左下列出采集批次 → 单击 → 数据详情出图。
|
||||||
|
- 提交 `feat(view): 左下数据列表 + 对象树到测线层(DS 移出树)`。
|
||||||
|
|
||||||
|
### 增量 3:3D「视图详情」图层浮层(体素的正确归宿)
|
||||||
|
- 中央三维视图左上浮层(QWidget overlay on QVTK,或工具区):勾选显示 测线/帘面/**体素**/(地形)。
|
||||||
|
- 勾"体素" → 调 `buildVoxelFromScatters`(已验证)加入 3D 场景;勾选驱动 rebuildCentral 的图层集。
|
||||||
|
- main() 设 PROJ_DATA(体素配准需 proj.db;按候选路径,部署随包附带)。
|
||||||
|
- **人工复核**:三维视图勾"体素"→ 出十字片体素,与帘面同系;取消则移除。
|
||||||
|
- 提交 `feat(view): 3D 视图详情图层浮层(测线/帘面/体素) + 体素正经接入`。
|
||||||
|
|
||||||
|
### 增量 4:数据详情富工具条 + 电极 + 数值标签(对齐原型中下)
|
||||||
|
- 工具条补 色阶配置/显示电极/显示等值线 等(按需,部分 M1 可占位)。
|
||||||
|
- 剖面顶部电极▼标记(grid.lat/lon 或 x 轴电极位);可选数值标签。
|
||||||
|
- 提交 `feat(view): 数据详情电极标记 + 工具条对齐原型`。
|
||||||
|
|
||||||
|
### (增量 5,可选)右下属性面板规范化 + 整体 dock 透视持久化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Self-Review
|
||||||
|
- 严格按原型六面板;体素归 3D 图层浮层(修正"工具条开关"错误)。
|
||||||
|
- 面板抽到 view/(spec §3),守 800 行铁律;每增量可构建+复核+提交。
|
||||||
|
- 渲染积木复用既有(已 PNG 验证);异常显隐/体素接入复用 buildAnomalies/buildVoxelFromScatters。
|
||||||
|
- 回写 STATUS §6.10 / 本计划完成度。
|
||||||
|
|
@ -14,7 +14,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)
|
||||||
|
|
||||||
target_include_directories(geopro_desktop PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(geopro_desktop PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,9 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QSignalBlocker>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QSurfaceFormat>
|
#include <QSurfaceFormat>
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
|
|
@ -43,6 +46,7 @@
|
||||||
#include "ApiClient.hpp"
|
#include "ApiClient.hpp"
|
||||||
#include "AuthService.hpp"
|
#include "AuthService.hpp"
|
||||||
#include "login/LoginWindow.hpp"
|
#include "login/LoginWindow.hpp"
|
||||||
|
#include "panels/AnomalyListPanel.hpp"
|
||||||
|
|
||||||
#include "CameraPreset.hpp"
|
#include "CameraPreset.hpp"
|
||||||
#include "Scene.hpp"
|
#include "Scene.hpp"
|
||||||
|
|
@ -56,6 +60,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QVTKOpenGLStereoWidget.h>
|
#include <QVTKOpenGLStereoWidget.h>
|
||||||
|
|
@ -228,14 +233,21 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
leftDock->setWidget(tree);
|
leftDock->setWidget(tree);
|
||||||
dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock);
|
dockManager->addDockWidget(ads::LeftDockWidgetArea, leftDock);
|
||||||
|
|
||||||
// 右 dock:属性。
|
// 右上 dock:异常列表(对齐原型;颜色块 + 名称 + 位置/深/尺寸 + 勾选显隐,与数据详情异常联动)。
|
||||||
|
auto* anomalyList = new QListWidget();
|
||||||
|
anomalyList->setAlternatingRowColors(true);
|
||||||
|
auto* anomalyDock = new ads::CDockWidget(QStringLiteral("异常列表"));
|
||||||
|
anomalyDock->setWidget(anomalyList);
|
||||||
|
auto* rightArea = dockManager->addDockWidget(ads::RightDockWidgetArea, anomalyDock);
|
||||||
|
|
||||||
|
// 右下 dock:属性。
|
||||||
auto* propLabel = new QLabel(QStringLiteral("(单击左侧数据集查看属性与平面剖面)"));
|
auto* propLabel = new QLabel(QStringLiteral("(单击左侧数据集查看属性与平面剖面)"));
|
||||||
propLabel->setWordWrap(true);
|
propLabel->setWordWrap(true);
|
||||||
propLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
propLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
propLabel->setMargin(8);
|
propLabel->setMargin(8);
|
||||||
auto* rightDock = new ads::CDockWidget(QStringLiteral("数据集 / 属性"));
|
auto* propDock = new ads::CDockWidget(QStringLiteral("属性"));
|
||||||
rightDock->setWidget(propLabel);
|
propDock->setWidget(propLabel);
|
||||||
dockManager->addDockWidget(ads::RightDockWidgetArea, rightDock);
|
dockManager->addDockWidget(ads::BottomDockWidgetArea, propDock, rightArea);
|
||||||
|
|
||||||
// ── 中央视图重建(核心)─────────────────────────────────────────────
|
// ── 中央视图重建(核心)─────────────────────────────────────────────
|
||||||
// 两个互斥视图按当前勾选集整体重建:scene.clear() → 对每个勾选 dd_section 加对应 actor。
|
// 两个互斥视图按当前勾选集整体重建:scene.clear() → 对每个勾选 dd_section 加对应 actor。
|
||||||
|
|
@ -295,12 +307,13 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
// 当前选中数据集 id(空=未选)与详情显示模式(反演剖面/原数据);切模式或换选中都重建。
|
// 当前选中数据集 id(空=未选)与详情显示模式(反演剖面/原数据);切模式或换选中都重建。
|
||||||
auto currentDsId = std::make_shared<QString>();
|
auto currentDsId = std::make_shared<QString>();
|
||||||
auto detailMode = std::make_shared<DetailMode>(DetailMode::Section18);
|
auto detailMode = std::make_shared<DetailMode>(DetailMode::Section18);
|
||||||
auto showAnomalies = std::make_shared<bool>(true); // 默认显示异常(对齐原型)
|
auto showAnomalies = std::make_shared<bool>(true); // 默认显示异常(对齐原型)
|
||||||
|
auto hiddenAnoms = std::make_shared<std::set<int>>(); // 异常列表中被取消勾选(隐藏)的异常下标
|
||||||
|
|
||||||
// 按当前选中 DS + 详情模式重建下方数据详情(平躺俯视正交,纵向夸张填面板)。
|
// 按当前选中 DS + 详情模式重建下方数据详情(平躺俯视正交,纵向夸张填面板)。
|
||||||
// 勾选「显示异常」时在 #18/#17 上叠加异常 dashed 折线(同纵向夸张对齐)。
|
// 勾选「显示异常」时在 #18/#17 上叠加异常 dashed 折线(同纵向夸张对齐)。
|
||||||
auto rebuildDetail = [&repo, detailRendererPtr, detailRenderWindowPtr, currentDsId, detailMode,
|
auto rebuildDetail = [&repo, detailRendererPtr, detailRenderWindowPtr, currentDsId, detailMode,
|
||||||
showAnomalies]() {
|
showAnomalies, hiddenAnoms]() {
|
||||||
detailRendererPtr->RemoveAllViewProps();
|
detailRendererPtr->RemoveAllViewProps();
|
||||||
if (currentDsId->isEmpty()) { // 未选数据集:清空即可
|
if (currentDsId->isEmpty()) { // 未选数据集:清空即可
|
||||||
detailRenderWindowPtr->Render();
|
detailRenderWindowPtr->Render();
|
||||||
|
|
@ -330,12 +343,15 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
detailRendererPtr->AddViewProp(a);
|
detailRendererPtr->AddViewProp(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 异常叠加(与剖面同坐标系/同纵向夸张)。
|
// 异常叠加(与剖面同坐标系/同纵向夸张)。逐异常构建以按列表显隐(下标=原 vector 序)过滤。
|
||||||
if (*showAnomalies) {
|
if (*showAnomalies) {
|
||||||
const auto anomalies = repo.loadAnomalies(id);
|
const auto anomalies = repo.loadAnomalies(id);
|
||||||
for (auto& act : geopro::render::buildAnomalies(anomalies)) {
|
for (int i = 0; i < static_cast<int>(anomalies.size()); ++i) {
|
||||||
act->SetScale(1.0, kDetailYScale, 1.0);
|
if (hiddenAnoms->count(i)) continue; // 列表中取消勾选→隐藏
|
||||||
detailRendererPtr->AddViewProp(act);
|
for (auto& act : geopro::render::buildAnomalies({anomalies[i]})) {
|
||||||
|
act->SetScale(1.0, kDetailYScale, 1.0);
|
||||||
|
detailRendererPtr->AddViewProp(act);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
geopro::render::applyTop2D(detailRendererPtr);
|
geopro::render::applyTop2D(detailRendererPtr);
|
||||||
|
|
@ -346,7 +362,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
// ── 单击 DS → 记选中 + 重建数据详情 + 右侧属性(与勾选区分;不改帘面可见性)──
|
// ── 单击 DS → 记选中 + 重建数据详情 + 右侧属性(与勾选区分;不改帘面可见性)──
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
tree, &QTreeWidget::itemClicked, tree,
|
tree, &QTreeWidget::itemClicked, tree,
|
||||||
[&repo, propLabel, currentDsId, rebuildDetail](QTreeWidgetItem* item, int) {
|
[&repo, propLabel, currentDsId, rebuildDetail, anomalyList, hiddenAnoms](
|
||||||
|
QTreeWidgetItem* item, int) {
|
||||||
const QString dsId = item->data(0, kRoleDsId).toString();
|
const QString dsId = item->data(0, kRoleDsId).toString();
|
||||||
if (dsId.isEmpty()) return; // GS/TM 节点无详情
|
if (dsId.isEmpty()) return; // GS/TM 节点无详情
|
||||||
const QString ddType = item->data(0, kRoleDdType).toString();
|
const QString ddType = item->data(0, kRoleDdType).toString();
|
||||||
|
|
@ -354,16 +371,37 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
const QString name = item->text(0);
|
const QString name = item->text(0);
|
||||||
|
|
||||||
*currentDsId = dsId;
|
*currentDsId = dsId;
|
||||||
|
|
||||||
|
// 右上异常列表:按该数据集异常重填(默认全显);先清隐藏集再填,避免重建时阻塞信号回灌。
|
||||||
|
const auto anomalies = repo.loadAnomalies(dsId.toStdString());
|
||||||
|
hiddenAnoms->clear();
|
||||||
|
{
|
||||||
|
const QSignalBlocker block(anomalyList); // 重填触发 itemChanged,先屏蔽
|
||||||
|
geopro::app::populateAnomalyList(anomalyList, anomalies);
|
||||||
|
}
|
||||||
|
|
||||||
rebuildDetail();
|
rebuildDetail();
|
||||||
|
|
||||||
// 右侧属性(数据集级,与详情模式无关)。
|
// 右下属性(数据集级,与详情模式无关)。
|
||||||
const auto g = repo.loadGrid(dsId.toStdString());
|
const auto g = repo.loadGrid(dsId.toStdString());
|
||||||
propLabel->setText(
|
propLabel->setText(
|
||||||
QStringLiteral("数据集: %1\n类型: 剖面网格 (dd_section)\n网格: %2 x %3\n"
|
QStringLiteral("数据集: %1\n类型: 剖面网格 (dd_section)\n网格: %2 x %3\n"
|
||||||
"vmin / vmax: %4 / %5")
|
"vmin / vmax: %4 / %5\n异常: %6 个")
|
||||||
.arg(name).arg(g.nx()).arg(g.ny()).arg(g.vmin).arg(g.vmax));
|
.arg(name).arg(g.nx()).arg(g.ny()).arg(g.vmin).arg(g.vmax)
|
||||||
|
.arg(anomalies.size()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── 异常列表勾选(显隐) → 更新隐藏集 → 重建数据详情 ──
|
||||||
|
QObject::connect(anomalyList, &QListWidget::itemChanged, anomalyList,
|
||||||
|
[hiddenAnoms, rebuildDetail](QListWidgetItem* item) {
|
||||||
|
const int idx = item->data(geopro::app::kAnomalyIndexRole).toInt();
|
||||||
|
if (item->checkState() == Qt::Checked)
|
||||||
|
hiddenAnoms->erase(idx);
|
||||||
|
else
|
||||||
|
hiddenAnoms->insert(idx);
|
||||||
|
rebuildDetail();
|
||||||
|
});
|
||||||
|
|
||||||
// ── 数据详情工具条「反演剖面/原数据」:切模式 → 重建数据详情 ──
|
// ── 数据详情工具条「反演剖面/原数据」:切模式 → 重建数据详情 ──
|
||||||
QObject::connect(actSection, &QAction::triggered, detailWidget,
|
QObject::connect(actSection, &QAction::triggered, detailWidget,
|
||||||
[detailMode, rebuildDetail]() {
|
[detailMode, rebuildDetail]() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include "panels/AnomalyListPanel.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QListWidgetItem>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "model/ColorScale.hpp"
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// 颜色块图标边长(像素)。
|
||||||
|
constexpr int kSwatch = 12;
|
||||||
|
|
||||||
|
// 由 localPts 算「位置(质心x)·深(质心y)·尺寸(包络对角)」摘要文本。
|
||||||
|
// 异常坐标在剖面距离/深度空间(x=距离米, y=深度米)。
|
||||||
|
QString summarize(const geopro::core::Anomaly& a)
|
||||||
|
{
|
||||||
|
if (a.localPts.empty()) return QStringLiteral("(无几何)");
|
||||||
|
double cx = 0.0, cy = 0.0;
|
||||||
|
double minx = a.localPts[0].x, maxx = a.localPts[0].x;
|
||||||
|
double miny = a.localPts[0].y, maxy = a.localPts[0].y;
|
||||||
|
for (const auto& p : a.localPts) {
|
||||||
|
cx += p.x; cy += p.y;
|
||||||
|
if (p.x < minx) minx = p.x;
|
||||||
|
if (p.x > maxx) maxx = p.x;
|
||||||
|
if (p.y < miny) miny = p.y;
|
||||||
|
if (p.y > maxy) maxy = p.y;
|
||||||
|
}
|
||||||
|
const auto n = static_cast<double>(a.localPts.size());
|
||||||
|
cx /= n; cy /= n;
|
||||||
|
const double span = std::hypot(maxx - minx, maxy - miny);
|
||||||
|
return QStringLiteral("位置 %1m · 深 %2m · 尺寸 %3m")
|
||||||
|
.arg(cx, 0, 'f', 0)
|
||||||
|
.arg(cy, 0, 'f', 0)
|
||||||
|
.arg(span, 0, 'f', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lineColor 字符串("#RRGGBB"/"rgba(...)") → 颜色块 QPixmap。
|
||||||
|
QPixmap swatch(const std::string& colorStr)
|
||||||
|
{
|
||||||
|
const auto c = geopro::core::parseColor(colorStr, geopro::core::AlphaScale::Bit255);
|
||||||
|
QPixmap pm(kSwatch, kSwatch);
|
||||||
|
pm.fill(QColor(c.r, c.g, c.b));
|
||||||
|
return pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void populateAnomalyList(QListWidget* list, const std::vector<geopro::core::Anomaly>& anomalies)
|
||||||
|
{
|
||||||
|
if (!list) return;
|
||||||
|
list->clear();
|
||||||
|
for (std::size_t i = 0; i < anomalies.size(); ++i) {
|
||||||
|
const auto& a = anomalies[i];
|
||||||
|
const QString name = QString::fromStdString(a.name.empty() ? "异常" : a.name);
|
||||||
|
const QString type = QString::fromStdString(a.typeName);
|
||||||
|
QString text = name;
|
||||||
|
if (!type.isEmpty()) text += QStringLiteral("(%1)").arg(type);
|
||||||
|
text += QStringLiteral("\n%1").arg(summarize(a));
|
||||||
|
|
||||||
|
auto* item = new QListWidgetItem(QIcon(swatch(a.lineColor)), text, list);
|
||||||
|
item->setData(kAnomalyIndexRole, static_cast<int>(i));
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Checked); // 默认显示
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "model/Anomaly.hpp"
|
||||||
|
|
||||||
|
class QListWidget;
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
// 异常索引存于条目的 Qt::UserRole(= 在原异常 vector 中的下标,用于显隐映射)。
|
||||||
|
constexpr int kAnomalyIndexRole = 0x0100; // Qt::UserRole
|
||||||
|
|
||||||
|
// 用异常填充 QListWidget(对齐原型右上「异常列表」):每条目 = 颜色块图标 + 名称 +
|
||||||
|
// 派生「位置 Xm · 深 Ym · 尺寸 Zm」(由 location.coordinate 质心/包络算)。
|
||||||
|
// 条目可勾选:勾=显示(默认全勾);勾选状态变化由调用方连接驱动该异常 actor 显隐。
|
||||||
|
// 清空旧条目后重填。
|
||||||
|
void populateAnomalyList(QListWidget* list, const std::vector<geopro::core::Anomaly>& anomalies);
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
Loading…
Reference in New Issue