From 5483a430bce5de57ce6fcc56c7d3ef90a21e7937 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Thu, 11 Jun 2026 19:03:13 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=95=B0=E6=8D=AE=E9=9B=86=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E5=9B=BE=E8=A1=A8=E9=87=8D=E6=9E=84=E4=BA=A4=E6=8E=A5?= =?UTF-8?q?=E6=96=87=E6=A1=A3(=E8=83=8C=E6=99=AF/=E7=9B=AE=E6=A0=87/?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6/=E4=B8=8B=E4=B8=80=E6=AD=A5/=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=9C=B0=E5=9B=BE/=E5=86=B3=E7=AD=96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HANDOFF-dataset-detail-chart.md | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 docs/superpowers/HANDOFF-dataset-detail-chart.md diff --git a/docs/superpowers/HANDOFF-dataset-detail-chart.md b/docs/superpowers/HANDOFF-dataset-detail-chart.md new file mode 100644 index 0000000..9a982df --- /dev/null +++ b/docs/superpowers/HANDOFF-dataset-detail-chart.md @@ -0,0 +1,97 @@ +# 交接文档:数据集详情图表(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。 +- **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 `。ApiClient 把非 object 的 `data` 包成 `{"value": }`。 +**原版也是分页懒加载**(客户端已对齐): + +| 页 | 接口 | 说明 | +|---|---|---| +| 原数据 | `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` — 装配:detailDock `setWidget(..., 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. 后续计划(本分支之后) + +1. **工具条编辑类功能**(网格页占位按钮):白化 / 滤波处理 / 色阶配置 / 异常框注 / 自动标注 / 网格 / 另存为 / 导出。交互较重,建议先 brainstorm 拆解。 +2. **ApiClient 异步化(已单独立项)**:把全局同步阻塞 ApiClient 改异步(QNetworkReply 信号,去 QEventLoop)+ Repository/控制器信号化→全 App 不冻 UI、可并发。架构改动,建议单独 spec+plan。 +3. **更广项目**:数据详情只是一个特性;原型/`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,不加原版没有的特性(曾因等值线"周期重复标注"被纠正,原版每条线只标一个)。