# 数据集详情视图(平面图表)改造 设计 - 日期: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 为 0–1 浮点**;原 `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`「客户端」页签(R051–R096)、「测井参数表」「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.5(2026-06-12 全量实测编目)** 与实现计划 `plans/2026-06-11-dataset-detail-other-dd-types.md`。客户端按真实数据类型走 `ChartStrategyRegistry` 分派。 ### 2.5 数据类型全景:设计 taxonomy(Excel)vs 实测运行 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=项目/GS,type=2=TM,parentId 链表层级;TM 可挂项目或 GS 下)→ `POST dsObject/data/page` body **`{projectId, structParentId:, 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: 等值面色带 / 散点方块 / 坐标轴 / 异常 / 图例 │ │ └─ AnomalyTablePanel(ds 级异常表, 行显隐→图表叠加) │ └─────────────────────────────────────────────────────────────┘ 右上「对象异常」面板(不动)= 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 ring; }>` + `std::vector 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/v,projectX/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 .95;VTK 侧用 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. 视觉核对 + 集成测试。