61 lines
5.8 KiB
Markdown
61 lines
5.8 KiB
Markdown
# M1 视图重构:按目标用户(物探工程师)与原型对齐的正确模型
|
||
|
||
> **背景**:前几版把"单数据集反演剖面"当成主视图、把 2D/3D 做成相机角度(平面剖面下无意义)、把体素塞成树兄弟节点 —— 均为脚手架,偏离产品。本计划按**原型 + 目标用户工作流**重建。REQUIRED SUB-SKILL: subagent-driven-development。
|
||
|
||
---
|
||
## ✅ 实施结果与关键修正(2026-06-07,经离屏 PNG 核对,已合入 feat/m1-core)
|
||
**Task A、Task B 均已完成并接入 app**(详见 STATUS §1)。实施中**修正了本计划最初一处错误模型**,以下为**最终正确做法**(下次照此,勿回退):
|
||
- ❌ 原设想"二维地图 = 俯视帘面顶边" **不成立**:竖直帘面俯视只剩一条发丝线 → 俯视图基本空白(已用 `verify_curtain_top.png` 证实)。
|
||
- ✅ **正确**:**二维地图 与 三维视图 是两种不同渲染内容**(不是同一物体换相机):
|
||
- **二维地图** = `render::buildSurveyLine`(`MapLineActor`):测线 `lat/lon` 轨迹画成**红色折线**俯视(浅底)。
|
||
- **三维视图** = `render::buildCurtain`(`CurtainActor`):竖直断面墙,**z 取负**(深度向下不倒置)、**纵向夸张 actor->SetScale(1,1,3)**、**分段色带**(colorBar 真实分段值,非连续插值)。墙沿弯曲测线弯属真实。
|
||
- **数据详情** = `render::buildGridContour`:#18 平面剖面,**y 取负 + 显式 structuredGrid(不假设等距)+ colorBar 真实分段值 + 纵向夸张 SetScale(1,1.5,1)**。
|
||
- ✅ 坐标统一:三者共用 `core::GeoLocalFrame`(lat/lon→局部米)。体素(projX/Y,CRS 未确认)暂不接入。
|
||
- ✅ **验证手段**:`tests/spike/render_verify.cpp` 离屏渲 PNG 肉眼核对(本会话教训:必须看像素)。
|
||
---
|
||
|
||
## 目标用户与工作流(物探/地质工程师)
|
||
看测区/测线/数据集 → 在**地图**看测线布在哪 → 看某测线的**反演剖面**圈定异常 → 在**三维**看断面空间结构/体素/地形。
|
||
|
||
## 正确模型(对齐原型四区)
|
||
- **左 对象树**:GS→TM→DS,复选框勾选 → 控制在中央场景显示哪些测线。
|
||
- **中央 二维地图 / 三维视图**:**同一个 VTK 3D 场景 + 一个相机开关**(spec §5.3/K-1「VTK 一统」):
|
||
- 关键:**剖面渲染成"竖直帘面"**——沿测线 `lat/lon` 立在世界坐标,纵向为深度 `y`,面上按 `colorBar` 着色 `v[j][i]`。
|
||
- **二维地图** = 俯视正交相机 → 看到测线(帘面顶边)俯视布局,像地图(底图瓦片 M1.5,M1 先浅底+经纬/比例)。
|
||
- **三维视图** = 透视相机 → 看到立体的断面墙、空间关系。
|
||
- 因内容是立体的,2D/3D **真有区别**(俯视=线、透视=墙)。
|
||
- **下方 数据详情**:选中数据集 → 该数据集**专业分析图**(ERT 反演剖面 #18:平面 banded 等值面+等值线,带色阶;异常标注后续)。独立 QVTK,**不是中央主图**。
|
||
- **右 异常列表 / 属性**。
|
||
|
||
## 坐标统一(帘面/地图共用世界系)
|
||
- 世界系 = **lat/lon → 局部米(等距圆柱投影)**:`x=(lon-lon0)*111320*cos(lat0)`, `y=(lat-lat0)*110540`,原点取测区中心。`core/geo` 加 `GeoLocalFrame`(或复用 CrsTransform EPSG:4326→局部)。
|
||
- 网格有 `lat[100]/lon[100]`(测线水平迹线)+ `y[22]`(深度/高程)→ 帘面点 `(x_i,y_i, y[j])`,值 `v[j][i]`。多条测线共用同一世界系 → 自动配准。
|
||
- **体素搁置**:散点只有 `projX/projY`(真实 CRS 未确认,§5),无法与 lat/lon 帘面配准 → 本次不做;CRS 确认后回归(STATUS §5)。
|
||
|
||
---
|
||
|
||
## Task A:render — 地理局部系 + 帘面 Actor
|
||
**Files:** `src/core/geo/GeoLocalFrame.{hpp,cpp}`、`src/render/actors/CurtainActor.{hpp,cpp}`、`tests/...`
|
||
- [ ] `GeoLocalFrame(lat0, lon0)`:`Xy toLocal(lat, lon)`(等距圆柱);单测一两个点。
|
||
- [ ] `CurtainActor::build(const core::Grid& g, const core::ColorScale& cs, const GeoLocalFrame& frame)→vtkActor`:`vtkStructuredGrid`,点 `(i,j)` = `frame.toLocal(g.lat[i], g.lon[i])` 的 (x,y) + z = `g.y[j]`(深度,向下可取负或按高程);标量 `v[j][i]`;`vtkDataSetMapper` + LUT(复用 `buildLut`);返回 actor(竖直帘面)。单测构建不崩 + 点数 = nx*ny。
|
||
- [ ] render CMake 按需加 VTK 组件(已有的够则不加)。提交 `feat(render): GeoLocalFrame + CurtainActor(测线竖直帘面)`。
|
||
|
||
## Task B:工作台布局重建(中央地图/3D 单场景 + 下方数据详情)
|
||
**Files:** `src/app/main.cpp`(重构布局)
|
||
- [ ] 布局:左 对象树(复选框)/ 中 单一 QVTK 场景(帘面)/ **下 数据详情 QVTK(平面 #18)** / 右 属性。中央工具条只保留「二维」「三维」相机开关(去掉体素按钮)。
|
||
- [ ] 中央场景:勾选 DS(dd_section)→ 用 `GeoLocalFrame`(由该测区 lat/lon 范围定原点)构建 `CurtainActor` 加入场景;取消勾选移除;多测线共存。「二维/三维」切相机(`applyTop2D`=俯视正交、`applyFree3D`=透视),作用整场景。
|
||
- [ ] 下方数据详情:选中(单击)DS → 在独立 QVTK 用 `buildGridContour`(平面 banded #18)显示该数据集剖面 + 属性(nx×ny/vmin/vmax)。
|
||
- [ ] 去掉树里的「三维体素」节点(repo loadStructure 改回只含网格 DS)+ 去掉 voxel 相关 UI(代码可保留 VoxelActor/buildVoxelFromScatters 备用,但不接入 UI)。
|
||
- [ ] 构建(先 taskkill)+ 冒烟。提交 `refactor(app): 中央地图/3D 单场景(竖直帘面)+ 下方数据详情(#18), 去除混乱模式与体素节点`。
|
||
|
||
## 验收(登录后人工)
|
||
- 勾选测线 → 三维视图里出现**立着的彩色断面墙**;
|
||
- 切「二维」→ 俯视看到测线(墙顶边)布局(像地图);「三维」→ 立体墙,**二者明显不同**;
|
||
- 单击数据集 → 下方"数据详情"出现平面反演剖面(#18);
|
||
- 不再有"三维体素"兄弟节点、不再有内容/相机混淆。
|
||
|
||
## Self-Review
|
||
- 对齐原型四区 + spec §5.3/K-1 单场景相机;剖面=竖直帘面使 2D/3D 有真实区别。
|
||
- 体素搁置(CRS 未确认),诚实记录,非省略。
|
||
- 回写 spec §4/§9 + STATUS。
|