geopro/docs/superpowers/specs/2026-06-11-dataset-detail-v...

342 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 数据集详情视图(平面图表)改造 设计
- 日期2026-06-11
- 分支建议:`feat/dataset-detail-chart`
- 状态:**ERT 反演dd_inversion_data展示功能已落地并经用户验收**;其余 dd 类型 + 工具条编辑功能待后续
## 状态更新2026-06-11
**架构偏离(重要):** spec 原定渲染器为 **QGraphicsView**,实际落地改用 **QwtPlot轴/交互/图例)+ VTK 算法层(等值线几何)+ 连续/离散色阶**(见返工方案 `plans/2026-06-11-dataset-detail-chart-v2-qwt.md`,权威)。展示结果视觉等价,下文 §5.2/§8 的 QGraphicsView 细节已被 QwtPlot 方案取代,保留作背景参考。
**已完成(仅 `dd_inversion_data` ERT 反演§2.2 展示范围内):** 原数据散点(方形点/白描边/连续色阶/x 轴顶部 + **hover 显 X/Y/值**+ 网格等值面(填充栅格 + 黑色等值线 + 沿线数值标注 + NaN 白边裁剪)+ 色阶图例 + 异常叠加 + 底部异常表/描述 + 多 Tab + 网格数据懒加载 + 页签内滚动/分割条 + 实时平移/滚轮缩放。数据加载已异步化(见 `specs/2026-06-11-apiclient-async-design.md`)。
**2026-06-12 渲染保真修复:** colorBar 是混合 hex+CSS-rgba 格式且 rgba 的 **alpha 为 01 浮点**;原 `DatasetChartDto``AlphaScale::Bit255` 解析致 12/18 段近透明(散点/网格/图例全发白)。修为 `AlphaScale::Unit`(一行根因修复,通用生效)。散点 `ColorMapService` 连续插值的归一化位置已证 1:1 等于原版 Plotly colorscale。新增 `ScatterHoverTip` 复刻原版 hovertemplate。详见 `HANDOFF-dataset-detail-chart.md §0.1`
**未完成:**
- **其余 dd 类型的详情图渲染**§2.4`dd_ert_measurement_data`、`dd_ert_measurement_gr_data`、`dd_grid`、`dd_trajectory_data`、测井(深度/时序折线、GPR`dd/gpr/channel/image`、TEM 等。控制器目前对非 `dd_inversion_data` 直接「暂不支持该类型预览」。**现实约束:当前租户仅 ERT/TEM/GPR 三类GPR 对象无数据、无测井数据 → 多数类型无活样本,须先取样本。** 实现计划见 `plans/2026-06-11-dataset-detail-other-dd-types.md`(如已生成)。
- **工具条编辑功能**§2.3,范围外/后续单独立项):白化 / 滤波处理 / 色阶配置 / 异常框注 / 自动标注 / 网格化 / 另存为 / 导出 / 描述富文本 / 大视图全屏。当前为占位按钮。
- 加载态:网格懒加载已有「加载中」遮罩;原数据初次加载仅 busy 光标,未做骨架屏。
- 参考材料:
- 客户端菜单:`D:\Projects\GEOPRO\Geopro3.0 菜单.xlsx`「客户端」页签R051R096、「测井参数表」「DD类型」
- 原 web 系统:`http://tenant.geomative.cn/#/projectSpace/datasetMange/datasetInfo`(经 Playwright 操作页面 + 抓取 JS chunk 做源码级分析)
- API`docs/apis/business_OpenAPI.json`
- 参考截图:`assets/web-datasetinfo-scatter.png`(原数据散点)、`assets/web-datasetinfo-grid-with-anomaly.png`(网格等值面 + 异常叠加 + 异常表)
---
## 1. 背景与问题
客户端工作台的「数据详情」dock 当前实现有两个问题:
1. **用了 VTK 渲染**`main.cpp` 下方「数据详情」dock 是一个独立的 `QVTKOpenGLStereoWidget` + `vtkRenderer``rebuildDetail` lambda 用 `vtkBandedPolyDataContourFilter`/散点/电极 actor 配合 `applyTop2D` 正交相机"平躺"渲染剖面。数据集详情本质是**平面图表**,不该走 3D 渲染管线。
2. **从未真正接上数据集选择**`main.cpp:705-713` 数据集列表单击只调 `nav.selectDataset(dsId)`(驱动右下「数据集属性」表单),`main.cpp:604` 创建的 `currentDsId` 此后**再无任何赋值**`itemClicked` 也不触发 `rebuildDetail`。即详情图表收不到选中的 dsId点数据集时它是空的。
本设计将「数据详情」dock 重建为**本地面板 + 平面图表**QGraphicsView接真实 API并真正接上数据集选择链路目标 100% 复刻原 web 系统 datasetInfo 页面的展示功能。
---
## 2. 目标与范围
### 2.1 目标
- 数据详情 dock 改为平面图表QGraphicsView**不再使用 VTK 渲染窗口**VTK 仅作几何算法库)。
- 100% 复刻原 web datasetInfo 的**展示**:原数据散点视图、网格等值面视图、色阶图例、等值线/标注、异常叠加 + 异常列表。
- 接真实 API`ApiDatasetRepository`)。
- 架构按 **dd 类型驱动的图表策略框架**搭建,首版落地 `dd_inversion_data`ERT 反演),其余 dd 类型作为框架内后续扩展。
### 2.2 范围内(仅展示)
- 原数据/网格数据 视图切换
- 网格等值面渲染(混合方案,见 §8+ 等值线 + 标注
- 原数据散点渲染
- 色阶图例(原数据 type1 / 网格 type2
- 显示异常/电极/等值线 开关
- 异常叠加(剖面上)+ 底部异常列表数据集级§7.3 辨析)
- 多 Tab 壳一个或多个数据集详情页R095
### 2.3 范围外(编辑/工具类,后续单独立项)
网格化参数GridDialog、色阶配置colorEditor、白化WhiteningDialog、滤波/迭代处理、异常框注/自动标注AutoAnnotationDialog、另存为SaveAsDialog、导出ExportDialog、描述富文本编辑、大视图(Esc) 全屏。
### 2.4 后续 dd 类型(框架内扩展,非本 spec
其余 dd 类型详情图见下文 **§2.52026-06-12 全量实测编目)** 与实现计划 `plans/2026-06-11-dataset-detail-other-dd-types.md`。客户端按真实数据类型走 `ChartStrategyRegistry` 分派。
### 2.5 数据类型全景:设计 taxonomyExcelvs 实测运行 ddCode + 渲染映射2026-06-12
> 用脚本直连 API 全量遍历两个账号(威立雅 + 赛盈地空"数据多"账号20 项目/108 TM/752 DS+ 逐个打开详情看截图确认渲染。**关键纠正:详情渲染由数据集"真实数据类型"决定URL 详情链接的 `ddCode` 经常标错,客户端分派须用 ds 元数据的真实类型。**
#### 2.5.1 实测 10 种 ddCode → 7 种渲染视图(均有活样本、看截图确认)
| 渲染视图 | ddCode | 数据类型 | 客户端 |
|---|---|---|---|
| **① 原数据(Plotly散点,cauto) + 网格数据(等值面+等值线)** | `dd_inversion_data` | ERT/TEM 反演剖面、视电阻率数据 | ✅ 已做 |
| **② 柱状图(Y=电阻欧姆,X=电极点) + 列表** | `dd_ert_measurement_gr_data` | ERT接地电阻 | ❌ |
| **③ 散点伪剖面(斜距/伪深度,视电阻率着色,反演运算工具) + 数据列表** | `dd_ert_measurement_data` | ERT原始数据 | ❌ |
| **④ 轨迹:地图 + 列表 + 高程 3页签** | `dd_trajectory_data` | ERT电极坐标、TEM坐标 | ❌ |
| **⑤ 列表(序号/x/y)** | `dd_grid` | 白化数据 | ❌ |
| **⑥ 雷达剖面灰度图像(B-scan) + 单道波形(A-scan) + 对比度/灰度色阶/频谱** | `dd_gpr_channel_detail`、`dd_gpr_channel_image` | 雷达单通道剖面/图片列表 | ❌ |
| **⑦ 地图轨迹(真实GIS底图 + GPS路径 + 起点/终点)**RTK 另带坐标点设置/解状态过滤面板) | `dd_radar_channel_trajectory`、`dd_radar_rtk_trajectory` | 雷达单通道轨迹/RTK轨迹 | ❌ |
| (无独立可视详情,疑数据中间态) | `dd_radar_preprocess_data` | 雷达预处理数据 | — |
**共 7 种渲染视图,客户端已做 1 种(①);待做 6 种:② 柱状图、③ 散点伪剖面、④ 轨迹、⑤ 列表、⑥ 雷达剖面图像、⑦ 地图轨迹。**
#### 2.5.2 与 `Geopro3.0 菜单.xlsx`「DD类型」设计 taxonomy 的对应
Excel「DD类型」页签是**设计期格式蓝图**,用的是另一套命名(`dd_Section`/`dd_Track`/`dd_ERTRawData`/`dd_GPRSection`/`dd_Images`/`dd_TimeVarious`…)。与实际运行 ddCode **命名对不上、语义对得上**
| Excel 设计格式 | 描述(Excel) | 对应实测运行 ddCode | 样本 |
|---|---|---|---|
| `dd_Section`"最重要":水平/垂直剖面) | 反演剖面 | `dd_inversion_data`(①)、`dd_gpr_channel_detail`(⑥) | ✅ |
| `dd_ERTRawData` | ERT原始数据 | `dd_ert_measurement_data`(③)、`dd_ert_measurement_gr_data`(②) | ✅ |
| `dd_GPRSection`(设计注:讨论是否并入 dd_Section | 雷达剖面 | `dd_gpr_channel_detail`/`image`(⑥) | ✅ |
| `dd_Track`(坐标+轨迹合并) | 电极坐标/采集轨迹 | `dd_trajectory_data`(④)、`dd_radar_*_trajectory`(⑦) | ✅ |
| `dd_Images` | 图片类 | `dd_gpr_channel_image`(⑥) | ✅ |
| `dd_Files` | 文件打包(如三维雷达原始包) | `dd_radar_preprocess_data`(疑) | ✅部分 |
| `dd_TimeVarious` | 时间连续变量 | =设计中的 TEM时序/timeSensor 折线 | ❌ 无样本 |
| `dd_Stratigraphy` | 地层编录/**测井** | =设计中的测井折线/深度 | ❌ 无样本 |
| `dd_Segy` | 地震 SEGY(只展示) | — | ❌ 无地震数据 |
| `dd_Sampling` | 采样/化学(XRF/VOCs) | — | ❌ |
| `dd_LinearVarious` / `dd_Structual3D` / `dd_Property3D` / `dd_Video` | 线性变量/三维结构/三维属性/视频 | — | ❌ |
| `dd_KML`/`dd_GeoJson`/`dd_shp`/`dd_dem`/`dd_bim`/`dd_czml`… | 背景资料**图层**(导入/预览/坐标对齐) | — | 非"数据详情图",是地图图层 |
**结论:** Excel 是"应有哪些数据格式"的设计蓝图;实测 10 种是"现在真有数据、详情页真能出图"的子集(电法 ERT + 地质雷达 GPR 两大类的落地。两者语义吻合Excel 里 时序(dd_TimeVarious)/测井(dd_Stratigraphy)/地震(dd_Segy)/采样/三维模型/视频 等当前**无活样本BLOCKED**(与 plan §1.2 一致KML/shp/dem/bim 等是地图图层,不属本 spec 的详情图范畴。
#### 2.5.3 枚举 DS 的 API实测可用踩坑记录
`POST my/profile/project/page`{pageNo,pageSize} → `GET projectStruct/queryProjectStruct/{pid}`扁平节点type=1=项目/GStype=2=TMparentId 链表层级TM 可挂项目或 GS 下)→ `POST dsObject/data/page` body **`{projectId, structParentId:<tmId>, structParentConfType:2, classifyTypeList:[3], pageNo, pageSize}`**(字段是 `structParentId` 不是 `tmObjectId`;必须带 `classifyTypeList:[3]` 否则后端 `code:500``pageNo` 不是 `pageNum`;时序类另走 `dsObject/timeSensor/data/page`;后端间歇 500 需重试。DS 字段:`ddCode`+`dsTypeCode`(英文)+`name`(中文类型名)+`dsName`(文件)。
> 现实约束:当前可访问租户实测有样本的方法类为 ERT/TEM/GPR测井/地震/采样/三维/时序无活样本。无样本类详情页**无可参照**,须待数据样本到位后再精确 1:1 复刻。
---
## 3. 原 web 系统分析(源码级)
> 方法Playwright 操作 datasetInfo 页面 → 抓取无障碍快照、网络请求、localStorage、活 API 响应;进一步抓取并分析前端 JS chunk`contourChartAdapter`/`plotlyScatterSimpleChart`/`contourPage`/`colorUtils` 等)。无 sourcemap代码已压缩但可读。
### 3.1 页面结构(客户端只取内容区,左侧 web 导航不复刻)
标题ds 名)→ `原数据 | 网格数据` 切换 → 工具条 → 图表 → 色阶图例 →(网格视图)底部 `异常列表 | 描述` 表。
### 3.2 原数据散点 —— Plotly `scattergl``plotlyScatterSimpleChart`
```
type:"scattergl", mode:"markers",
marker:{ size:10-12, color:vlist, colorscale, zmin/zmax, symbol:"square",
line:{color:white, width:1} }
yaxis.scaleanchor = x // x:y 等比锁定
colorbar:{ title:"数值", thickness:15, len:.7 } // 可选
```
方形点、按 `vlist` 经色阶着色、白描边、等比。
**客户端用 `QGraphicsRectItem`(方块)按色阶着色复刻输出,不引入 Plotly。**
### 3.3 网格等值面 —— 自制 marching-squares 引擎(`contourChartAdapter`canvas
源码为自带等值线库(`window.contourCore`API`computeContours / marchingSquares / pathFinding / levels / smooth / nullHandling / labels / colorbar / renderers / axes / Overlay`。
- **渲染模式**`heatmap``putImageData` 逐格 + canvas 缩放平滑)/ `fill`(填充色带 `drawFilledPaths`/ `lines`(等值线 `drawStrokePaths`/ `fill+lines`(默认显示:色带 + 等值线 + 标注)。
- **levels** = colorBar 离散分段值;`mapColors(v, vmin, vmax, colorscale)` 着色。
- **额外处理**2× 双线性上采样(`DEFAULT_UPSAMPLE_SCALE:2`+ 平滑(`DEFAULT_SMOOTHING:.3`+ 简化容差(`simplifyTolerance` 默认 `.5`,滑块)+ **数据凸包裁剪**`makeBinaryMask`/`createClipPath`/`DEFAULT_CLIP_LEVEL:.95`,对应截图里随地形起伏的不规则白边)+ 标注(`showLabels:true`)。
### 3.4 数据接口(全部真实 API 验活)
| 用途 | 接口 | 返回(关键字段) |
|---|---|---|
| 原数据散点 | `GET dd/ert/inversion/getErtRawDataScatterGraph/{dsId}` | `xlist/ylist/vlist/hlist/projectXList/projectYList`(各 1D本例 240、`min/max` |
| 网格等值面 | `GET dd/ert/inversion/rows/{dsId}` | `DDErtInversionGraphDataVO``x[nx]`、`y[ny]`、`v[ny][nx]`、`z[ny][nx]`(地形)、`elevation[nx]`、`vmin/vmax`、`sectionType`(1垂直/2水平) |
| 色阶 | `POST lvl/colorGradation/getDetail`body `{dsObjectId, businessCode:"", type}`type1=原数据 / type2=网格) | `data.properties.colorBar=[[值,"rgba(r,g,b,a)"],…]`、`lvlMinMax`、`lineConfig{showLines,color,lineType}`、`labelConfig{showLabels,color}` |
| 异常 | `GET exception/queryException/{dsId}` | 见 §6.4(与 `core::Anomaly` 一致) |
> 注:网格等值面数据来自服务端**已网格化**的 `inversion/rows`,前端不做插值;前端"网格"按钮是把 `xSpacing/xsize…` POST 给 `inversion/grid` 让服务端重算(范围外)。
---
## 4. 架构总览
**核心思路**:详情 dock 的渲染器从「VTK 3D 管线」换成「VTK 仅算等值面几何 + QGraphicsView 画 2D 场景」。数据模型、仓储接口复用,新增渲染器 + 面板壳 + dd 策略 + API 仓储 + 一个小详情控制器;并真正接上数据集选择链路。
```
┌─ 数据详情 dock重建──────────────────────────────────────┐
│ DatasetDetailPanel (QTabWidget 壳, 每 ds 一页, R095 多Tab) │
│ └─ DatasetDetailPage │
│ ├─ 标题栏ds 名) │
│ ├─ 原数据 / 网格数据 切换 + 显示异常/电极/等值线 开关 │
│ ├─ DatasetChartView : QGraphicsView ← 新渲染器 │
│ │ scene: 等值面色带 / 散点方块 / 坐标轴 / 异常 / 图例 │
│ └─ AnomalyTablePanelds 级异常表, 行显隐→图表叠加) │
└─────────────────────────────────────────────────────────────┘
右上「对象异常」面板(不动)= TM 异常总和, 眼睛→中央 VTK 地图
右下「数据集属性」面板(不动)= dynamicForm 表单
▲ 渲染输入(复用现有 core 模型) ▲ dd 类型分派
┌─ chart 层(新)──────────────────┐ ┌─ 策略注册(新)──────────────┐
│ ContourBuilder (src/render/) │ │ IDatasetChartStrategy │
│ VTK 仅算法: 上采样+平滑→ │ │ + ErtInversionStrategy(首个)│
│ vtkBandedPolyDataContourFilter │ │ registry: ddCode → strategy │
│ → 分层带多边形+等值线(几何,无窗口)│ │ (扩展点: 测井/时序/GPR…) │
└──────────────────────────────────┘ └──────────────────────────────┘
▲ 数据模型(复用,零改动)
┌─ core::Grid / ScatterField / ColorScale / Anomaly ──────────┐
└─────────────────────────────────────────────────────────────┘
▲ 加载
┌─ IDatasetRepository接口已存在───────────────────────────┐
│ loadGrid / loadScatter / loadColorScale / loadAnomalies │
│ · ApiDatasetRepository新, 真实 API, §6.3
│ · LocalSampleRepository保留, 离线/测试) │
└─────────────────────────────────────────────────────────────┘
▲ 编排(新小控制器, 不污染 WorkbenchNavController
┌─ DatasetDetailController新, 持 IDatasetRepository + 注册表)┐
│ 在 main.cpp 与 nav.selectDataset 并联挂到 datasetList 单击 │
│ 读 ddCode → 选策略 → 拉数据 → 发信号 → 面板被动渲染 │
└─────────────────────────────────────────────────────────────┘
```
**关键边界**
- **中央 2D/3D 地图视图仍是 VTK**(在地图上显示数据集是 VTK 的正职),本次只换数据详情 dock。
- **VTK 在新链路里只当算法库**(无 render window**新增依赖仅 Qt Widgets 的 `QGraphicsView`**LGPL 合规),无第三方图表库。
---
## 5. 组件细化
### 5.1 `ContourBuilder`(新,`src/render/`VTK 仅算法)
复用 `GridContourActor.cpp:36-82` 已验证的「`core::Grid` → `vtkStructuredGrid``vtkDataSetSurfaceFilter``vtkBandedPolyDataContourFilter`(按 colorBar 真实非均匀分段 + `GenerateContourEdgesOn`)」管线,**只在输出端分叉**:不建 mapper/actor而是从 `banded->GetOutput()`(port0, cell 标量) 提取色带多边形、从 port1 提取等值线折线。
混合保真预处理(见 §8入网格先 **2× 双线性上采样 + 高斯平滑** → banded → 按 NaN 掩膜做**数据凸包裁剪** → 等值线 Douglas-Peucker **简化**(容差参数)。
- 入:`core::Grid`(含 NaN 标记无效区)+ `core::ColorScale`(分段值)+ `ContourOptions{upsample, smooth, simplifyTol, showLines, showLabels}`
- 出:`std::vector<BandPolygon{ core::Rgba color; std::vector<core::Vec2> ring; }>` + `std::vector<ContourLine{ double level; std::vector<core::Vec2> pts; }>`
- 纯函数、无 Qt 依赖、可单测(给定网格→断言色带数/层级/裁剪边界)。
### 5.2 `DatasetChartView : QGraphicsView`(新,`src/app/panels/chart/`
`QGraphicsScene`,对外:`showContour(grid, scale, opts)` / `showScatter(field, scale)` / `setAnomalies(list, hidden)` / `setOverlays(showAnomaly, showElectrode, showContourLine)`
- Item色带 `QGraphicsPathItem`(填充)、等值线 `QGraphicsPathItem`、散点 `QGraphicsRectItem`(方块, 白描边)、异常 `QGraphicsPathItem`(可拾取)、电极顶部标记、标注 `QGraphicsSimpleTextItem`
- **坐标轴**viewport 层 overlay 自绘,监听 `transform` 变化重算刻度(缩放/平移时轴钉边缘)。**y 轴用高程、向上为正**(场景 y 翻转);散点视图 **x:y 等比**(对齐 Plotly `scaleanchor`)。
- 交互:滚轮缩放、拖动平移、点击异常高亮、重置视图。
- **同一个类**供详情页、(后续)大视图、自动框注对话框复用——普通 QWidget、无 OpenGL 上下文负担。
### 5.3 dd 类型策略(新,扩展点,`src/app/panels/chart/`
```cpp
struct IDatasetChartStrategy {
virtual ~IDatasetChartStrategy() = default;
virtual std::string ddCode() const = 0;
virtual void load(DatasetDetailController&, const std::string& dsId) = 0; // 决定拉哪些数据、画什么
};
```
- `ErtInversionStrategy`(首个,`ddCode()=="dd_inversion_data"`):原数据→`loadScatter`+散点;网格→`loadGrid`+`ContourBuilder`+色带/等值线;异常→`loadAnomalies`。
- `ChartStrategyRegistry``ddCode → strategy`;未注册 → 页内占位「暂不支持该类型预览」(优雅降级)。
### 5.4 `ApiDatasetRepository`(新,实现 `IDatasetRepository`,真实 API`src/data/api/`
| 方法 | 接口 | 解析(→ `src/data/parse/` |
|---|---|---|
| `loadScatter(dsId)` | `getErtRawDataScatterGraph/{dsId}` | → `ScatterField`xlist/ylist/hlist/vlist→x/y/z/vprojectX/Y |
| `loadGrid(dsId)` | `inversion/rows/{dsId}` | `DDErtInversionGraphDataVO``Grid`x/y/v/z/elevation/vmin/vmax |
| `loadColorScale(dsId, variant)` | `colorGradation/getDetail`(type1/2) | `properties.colorBar[[值,rgba]]``ColorScale::addStop` |
| `loadAnomalies(dsId)` | `queryException/{dsId}` | → `core::Anomaly[]`§6.4 |
> 现有 `IDatasetRepository` 的 `loadColorScale` 需加 `variant`(原数据/网格) 参数;`loadScatterColorScale` 可并入。`LocalSampleRepository` 保留为离线/测试桩。
### 5.5 `AnomalyTablePanel`(新或复用 `AnomalyListPanel``src/app/panels/`
ds 级异常表,列:名称 / 异常类型 / 几何类型 / 创建时间 / 备注 / 操作(仅展示版:显隐眼睛;定位)。行显隐 → 发信号驱动 `DatasetChartView::setAnomalies` 的 hidden 集(对齐现有 `hiddenAnoms` 语义)。
### 5.6 `DatasetDetailPanel` / `DatasetDetailPage`(新,`src/app/panels/`
- `DatasetDetailPanel``QTabWidget`,按 dsId 去重托管多个 `DatasetDetailPage`R095
- `DatasetDetailPage`:标题 + 原数据/网格数据 切换 + 叠加开关 + `DatasetChartView` + `AnomalyTablePanel`
### 5.7 `DatasetDetailController`(新,`src/controller/`
`IDatasetRepository&` + `ChartStrategyRegistry&`slot `openDataset(dsId, ddCode)`:选策略→拉数据→`emit chartReady(pageModel)`;被动视图。**不并入 `WorkbenchNavController`**(后者只持 `IProjectRepository`、专注项目/结构/异常树导航,混入图表数据会破坏单一职责)。
---
## 6. 数据模型与映射
### 6.1 复用的 core 模型(零改动)
- `core::Grid``Field.hpp``nx/ny/valueAt(i,j)`、`x/y`、`z[nx*ny]`、`elevation[nx]`、`vmin/vmax` ⇆ `DDErtInversionGraphDataVO`
- `core::ScatterField``x/y/z/v`、`projX/projY` ⇆ 散点 VO。
- `core::ColorScale`:阶梯色阶 `addStop/colorAt/stopValues` ⇆ colorBar。
- `core::Anomaly``markType`(点/线/面)、`localPts`、`lineColor/lineWidth/dashed` ⇆ queryException。
### 6.2 NaN / 无效区
`inversion/rows``v` 在测区外为无效;`core::Grid` 用 NaN 标记,`ContourBuilder` 据此做凸包裁剪§8渲染成不规则白边。
### 6.3 色阶colorBar
`properties.colorBar``[[值字符串, "rgba(r,g,b,a)"], …]`(本例 17 段),`type1`(原数据)/`type2`(网格) 颜色相同、分段值不同。映射:每段 `addStop(parseDouble(值), core::parseColor(rgba))``lineConfig` 驱动等值线显隐/色/线型。
### 6.4 异常queryException → core::Anomaly活数据验证
```
exceptionName → name
exceptionTypeName(异常区) → typeName
exceptionMarkType(1点/2线/3面) → markType
exceptionMarkTypeName(多段线…) → 表"几何类型"列
location.coordinate[{x,y}] → localPts (剖面局部坐标: x=桩号, y=高程)
legend.polylineColor/Width → lineColor/lineWidth
legend.polylineShape=="dash"→ dashed
createTime/remark → 表"创建时间/备注"列
geographicalCoordinates / latitudeLongitude → (地图用, 详情视图不需要)
```
> 客户端已有 `parseExceptions` 映射此结构(`Anomaly.hpp` 注释印证),活数据已验证一致。
---
## 7. 数据流与交互
### 7.1 选择 → 渲染
`datasetList` 单击 → 同时:(a) `nav.selectDataset(dsId)`(现状,驱动右下属性表单);(b) `detailCtrl.openDataset(dsId, ddCode)`(新)→ 选策略 → 拉 scatter/grid/colorScale/anomalies → `emit chartReady``DatasetDetailPanel` 渲染。
### 7.2 Tab 与联动R055-057, R095
- 双击数据集 = 新建或聚焦已开页(按 dsId 去重);单击 = 聚焦已开页(若已打开)。
- 活动 Tab 切换 → 反向高亮数据集列表对应项。
- 视图切换 原数据/网格数据;叠加开关 显示异常/电极/等值线。
### 7.3 异常归属辨析(决策记录)
原 web datasetInfo 是**单页**,底部异常表是单页布局产物。客户端是**多面板工作台**,存在两处不同作用域的异常显示,**经决策保留两者、各管各的视图**
| 位置 | 接口 | 作用域 | 眼睛控制 |
|---|---|---|---|
| 右上「对象异常」面板(现状不动) | `queryExceptionByTmObjectId/{tmId}` | 对象/TM 级(勾选驱动,多 TM 聚合) | 中央 VTK 2D/3D **地图** |
| 详情 dock 底部「异常列表」(本 spec, 复刻 web | `queryException/{dsId}` | 数据集级(更直观) | **图表剖面**叠加 |
剖面上的**异常叠加**属"画在图上",天然归详情视图;右上面板的列表与地图叠加不变。
---
## 8. 渲染保真度(混合方案)
网格等值面采用 **VTK 算法 + 预处理** 混合方案(~95% 保真,复用 VTK不重写整套引擎
1. **2× 双线性上采样** `core::Grid`(对齐 web `DEFAULT_UPSAMPLE_SCALE:2`)——可用 `vtkImageData` + `vtkImageResize`/手写双线性。
2. **高斯平滑**(对齐 web `DEFAULT_SMOOTHING:.3`)。
3. `vtkBandedPolyDataContourFilter` 按 colorBar 分段值出**色带多边形 + 等值线**。
4. **数据凸包裁剪**:按 NaN 掩膜裁掉测区外(对齐 web `makeBinaryMask`/`clipLevel .95`),得不规则白边。
5. 等值线 **Douglas-Peucker 简化**(容差参数,默认 0.5,对应"简化容差")。
6. 默认 `fill+lines + showLabels`;等值线色/显隐由 colorBar `lineConfig` 驱动。
原数据散点:`QGraphicsRectItem` 方块、按色阶着色、白描边、**x:y 等比**(对齐 Plotly `scaleanchor`)。
> 与「轻量 VTK banded 原生」(~85%, 矩形范围/块状) 和「高保真整体移植引擎」(~100%, 工作量最大) 相比,混合方案是保真度/工作量的折中。
---
## 9. 错误 / 空 / 加载态
- 加载中:图表区骨架/转圈。
- 空态:异常表「暂无数据」;未注册 ddCode「暂不支持该类型预览」无网格/散点数据时空图占位。
- 错误API 失败 → 页内内联错误(沿用 `RepoResult` 错误传播,不崩)。
- 跨项目上下文/数据过期:优雅降级。主题令牌复用(明暗一致)。
---
## 10. 测试策略GoogleTest/CTest
- **单元**`ContourBuilder`(给网格→断言色带数/层级/凸包裁剪/简化点数);`ColorScale`colorBar 解析、`colorAt` 边界);解析器(散点/反演网格/色阶/异常 VO→模型`ChartStrategyRegistry` 查找与降级。
- **组件**`DatasetChartView` 按数据生成 scene item 数;叠加开关隐藏对应 item`AnomalyTablePanel` 行开关发信号;`DatasetDetailPanel` 按 dsId 去重 Tab。
- **集成**`DatasetDetailController.openDataset` 编排(用 `LocalSampleRepository` 桩)→ 断言 `chartReady` 负载。
- **视觉**:对照 `assets/web-datasetinfo-*.png` 人工核对散点/等值面/异常叠加。
---
## 11. 风险与开放问题
1. **凸包裁剪精度**web 用 binary mask + clipLevel .95VTK 侧用 NaN 掩膜裁剪需调参,可能与 web 边界略有出入(在 95% 目标内可接受)。
2. **坐标轴钉边重算**QGraphicsView 缩放时轴刻度重算是已知但非免费的模式,需专门处理。
3. **`IDatasetRepository.loadColorScale` 签名变更**(加 variant会动到 `LocalSampleRepository` 与现有 VTK 详情调用点——后者将随本次重建移除,注意配平。
4. **其它 dd 类型无活样本**(测井/GPR/TEM 详情页):框架预留,落地需数据样本。
5. **大数据集性能**:散点 240 点、网格 32×100→上采样 64×200 量级QGraphicsView 可承受更大测线需评估web 用 `hightPerformaceContainer`,本版先不优化)。
---
## 12. 落地顺序(供 plan 细化)
1. `core::Grid` NaN 支持 + `ContourBuilder`VTK 几何提取 + 上采样/平滑/裁剪/简化)+ 单测。
2. `ApiDatasetRepository`4 接口 + 解析)+ `loadColorScale` variant + 单测。
3. `DatasetChartView`(散点/等值面/轴/图例/异常叠加 + 交互)。
4. dd 策略框架 + `ErtInversionStrategy` + 注册表。
5. `AnomalyTablePanel` + `DatasetDetailPage/Panel`(多 Tab
6. `DatasetDetailController` + `main.cpp` 接线(移除旧 VTK 详情 dock接上数据集单击/双击 + 反向联动)。
7. 视觉核对 + 集成测试。