9.4 KiB
交接文档:数据集详情图表(dataset-detail-chart)
给下一个会话:读完本文件 + 文末"立即要做的事"即可无缝接手。日期 2026-06-11。
1. 背景
geopro 是 Qt6 / C++ 离线桌面客户端,目标是像素级 1:1 复刻 web 系统
http://tenant.geomative.cn/#/projectSpace/datasetMange/datasetInfo(赛盈地空)的「数据集详情」视图。
本轮专做 ERT 反演数据(ddCode=dd_inversion_data)的详情视图。
硬约束:禁止 QWebEngine/Chromium(离线要求)。图表用本地 QwtPlot(轴/交互/图例)+ VTK 算法层(等值线几何)+ 连续/离散色阶,不是 web 渲染。验收标准是视觉等价 + 交互一致(非字节级像素 diff)。
标准测试 ds:id=1458990939709440(ddCode=dd_inversion_data)。原版网格视图参考截图:仓库根 web-grid-E3b.png(未入库,可重新用 Playwright 截)。
2. 目标
数据详情含两个页签,均已完成:
- 原数据:Plotly scattergl 风格散点(方形点/白描边/连续色阶/x 轴顶部)。
- 网格数据:填充等值面 + 黑色等值线 + 沿线数值标注 + 不规则白边(NaN 裁剪)+ 底部异常表/描述。
3. 技术栈与构建
- Qt6 Widgets;Qwt 6.2(源码在
external/qwt-src/,用cmake/qwt.cmake以 CMake 构建静态库,不要用 qmake——本机 VS2026 缺 vswhere,qmake 不可用)。- 关键:qwt.cmake 必须
target_compile_definitions(qwt PRIVATE QWT_MOC_INCLUDE=1),否则 61 个链接错误;需链接 Qt6 Widgets/Concurrent/PrintSupport/Svg。
- 关键:qwt.cmake 必须
- VTK 9.6 仅用算法层(
vtkBandedPolyDataContourFilter/vtkStripper/vtkSplineFilter/vtkDataSetSurfaceFilter),不做 VTK 渲染。 - CMake(VS 自带 4.2.3)+ Ninja + MSVC 14.51;GoogleTest/CTest;vcpkg(仅非 Qt 依赖)。
- 构建:
powershell.exe -ExecutionPolicy Bypass -File scripts/dev-build.ps1- ⚠️ 若报
LNK1104 无法打开 geopro_desktop.exe,是 exe 正在运行:先Get-Process geopro_desktop | Stop-Process -Force再构建。
- ⚠️ 若报
- 测试:
powershell.exe -ExecutionPolicy Bypass -File scripts/dev-test.ps1(当前 75/75 绿)。- 单测过滤:
build/release/tests/geopro_tests.exe --gtest_filter=ContourBands.*
- 单测过滤:
4. 数据 API(均经 Playwright 实测)
Auth header:geomativeauthorization: Geomative <token>。ApiClient 把非 object 的 data 包成 {"value": <data>}。
原版也是分页懒加载(客户端已对齐):
| 页 | 接口 | 说明 |
|---|---|---|
| 原数据 | lvl/colorGradation/getDetail(type1) + dd/ert/inversion/getErtRawDataScatterGraph/{id} |
2 个请求,~0.8s |
| 网格数据 | dd/ert/inversion/rows/{id} + lvl/colorGradation/getDetail(type2) + exception/queryException/{id} |
3 个,rows 服务端网格化波动 1–4s |
rows:x[nx]、y[ny]、v[ny][nx](电阻率,含 NaN=无数据)、z[ny][nx](高程)、vmin/vmax。标准 ds 为 nx=300,ny=100。colorGradation:properties.colorBar=[[值,"rgba()"],…](type1 散点连续/type2 网格离散,~17 段)+lineConfig{showLines,color,lineType}+labelConfig{showLabels,color}。- 配色机制(实测纠正过):不是 log;是 colorBar 值线性归一化到 [0,1] + 非均匀色阶停靠点 + 连续插值(散点)/离散分带(网格)。
5. 架构与关键文件
数据流:DatasetListPanel 双击 → DatasetDetailController.openDataset(同步阻塞拉原数据 2 请求)→ chartReady(ChartData) → DatasetDetailPanel(多 ds 的 QTabWidget) → DatasetDetailPage(buildTabbedPanel 原数据/网格 两页签) → 两个 View。切到网格页签 → gridDataNeeded 冒泡 → loadGridData(懒加载 3 请求)→ gridReady(GridData) → GridDataChartView.setGridData。
src/controller/DatasetDetailController.{hpp,cpp}— openDataset / loadGridData(懒加载);busy_ 重入守卫 + catch(...) 防死锁。signal: chartReady/gridReady/loadFailed/focusRequested。src/app/panels/chart/:RawDataChartView.*— 散点视图模板(白底浅 palette、QwtPlotGrid 网格线、过原点 QwtPlotMarker 零线、QwtPlotRescaler 锁定 x:y 真实比尺(aspect=1, ref=xTop)、LivePanner、x 轴在 xTop、独立 ColorBarWidget)。析构 delete colorSvc_。GridDataChartView.*— 网格视图。x 轴在 xBottom。布局:toolbar(固定) + QScrollArea(setWidgetResizable) 内含 QSplitter(竖直){ chartArea(plot+colorBar, minH280) | 异常表/描述(minH160) }。→ 页签内滚动 + 可拖分割条。ContourPlotItem.*(QwtPlotItem)— 填充走栅格:QImage(ARGB32, K=4 上采样, 双线性插值 +colorAtDiscrete离散着色 + 任一邻格 NaN→像素透明=白边裁剪),draw 时 blit;等值线走矢量:buildContourBands取 lines;标注:resolveLineLevels采样吸附级别,每条线只标一个(弧长中点,旋转)。异常叠加(点/线/面)。ScatterPlotItem.*— 散点项(xTop/yLeft,7px 方块白描边,连续配色,n=min(x,y) 防越界)。ColorMapService.*— colorAtContinuous(线性插值)/colorAtDiscrete(阶梯),from core::ColorScale。ColorBarWidget.*— 独立色阶条,居中约 74% 宽(非满宽)、等宽色带、白底深字。LivePanner.*— canvas 事件过滤器:左键实时平移(连续平移两轴+replot) + 滚轮缩放(以光标为中心,上滚=放大,消费事件避免冒泡触发外层滚动条)。取代了 QwtPlotPanner/QwtPlotMagnifier。
src/render/ContourBands.{hpp,cpp}—buildContourBands(Grid, ColorScale, ContourOptions{upsample=2,smooth=0.3,makeLines})→{bands, lines}。VTK:网格→上采样→平滑→toCellGrid(剔 NaN 格)→surface→banded→(lines: vtkStripper 连段 + vtkSplineFilter 样条平滑, 不再 DP 简化)。src/data/dto/DatasetChartDto.*、src/data/api/ApiDatasetRepository.*— JSON 解析(v 行数校验 qWarning、markType 钳制)。src/app/main.cpp— 装配:detailDocksetWidget(..., ads::CDockWidget::ForceNoScrollArea)(禁 ADS 把标题/页签卷入整体滚动条);gridDataNeeded→loadGridData、gridReady→setGridData 接线。
6. 关键设计决策(及为什么)
- 真实比尺锁定(用户选定,区别于原版的响应式填充):QwtPlotRescaler aspect=1,剖面呈真实"宽扁"。
- 填充用栅格而非多边形:300×100 网格 banded 多边形约 3 万个,逐帧+实时拖动会卡;QImage 一次成图 + blit 流畅。
- 等值线样条平滑:banded 边是大量 2 点短线段→ vtkStripper 连接 + vtkSplineFilter 拟合平滑曲线(贴近原版圆滑)。
- 滚轮事件必须消费:否则冒泡触发 ADS/外层滚动条。
- 页签内滚动:ForceNoScrollArea(dock) + 视图内 QScrollArea(裹 splitter),使标题/页签/工具条固定、仅内容区滚动。
- 同步阻塞是全 App 共性问题:ApiClient 用 QEventLoop 死等→每次请求冻 UI。已定单独立项异步化(见下)。
7. 当前进度
- 分支
feat/dataset-detail-chart,领先 main 37 commits,工作区干净(除未入库的web-grid-E3b.png)。 - 两个视图 + 交互 + 懒加载 + 布局全部完成并经用户逐项验收通过。
- cpp-reviewer 审查已做:HIGH 全修(散点越界 / colorSvc 析构泄漏 / QwtPlot autoDelete 注释 / 控制器 catch(...) 防 busy 死锁)+ 值得的 MEDIUM/LOW(清死代码、填充等比限幅、DTO 校验/枚举钳制、ContourLine.level 默认 NaN)。提交
78f96db。75/75 测试绿。
8. 立即要做的事(接手第一步)
收尾本分支——已问用户"如何收尾",4 选项待其回答:①合并回 main(本地) ②推送建 PR(origin=gitea) ③保持现状 ④丢弃。
合并/PR 前先清掉未入库的 web-grid-E3b.png(保持工作区干净)。等用户给出选择后执行(用 superpowers:finishing-a-development-branch)。
9. 后续计划(本分支之后)
- 工具条编辑类功能(网格页占位按钮):白化 / 滤波处理 / 色阶配置 / 异常框注 / 自动标注 / 网格 / 另存为 / 导出。交互较重,建议先 brainstorm 拆解。
- ApiClient 异步化(已单独立项):把全局同步阻塞 ApiClient 改异步(QNetworkReply 信号,去 QEventLoop)+ Repository/控制器信号化→全 App 不冻 UI、可并发。架构改动,建议单独 spec+plan。
- 更广项目:数据详情只是一个特性;原型/
D:\Projects\GEOPRO\Geopro3.0 菜单.xlsx(客户端 tab) 里还有其他数据类型、三维视图、其他菜单。
10. 相关文档与记忆
- 设计/计划:
docs/superpowers/specs/2026-06-11-dataset-detail-view-design.md、docs/superpowers/plans/2026-06-11-dataset-detail-chart-v2-qwt.md(v2 QwtPlot 返工方案,权威)、docs/superpowers/plans/2026-06-11-dataset-detail-chart.md。 - 外部返工方案:
docs/Geopro3.0_二维图表返工技术方案.md。 - API 文档:
docs/apis(business_OpenAPI.json)。 - 记忆(务必遵守):
~/.claude/projects/D--Git-lanbingtech-geopro/memory/:reply-in-chinese— 全程中文回复。study-original-via-playwright— 任何不确定必须用 Playwright 实地看原版,禁止联想猜测。no-embellishment-replicate-exactly— 严格 1:1,不加原版没有的特性(曾因等值线"周期重复标注"被纠正,原版每条线只标一个)。