geopro/docs/superpowers/plans/2026-06-18-vtk-3d-anomaly.md

7.6 KiB
Raw Blame History

实现计划VTK 三维异常(#4全量含异常体/列表/过滤)

  • 日期2026-06-18
  • 分支:feat/vtk-3d-view
  • 上位设计:docs/superpowers/specs/2026-06-17-vtk-3d-volume-slice-anomaly-design.md;补充需求 R49-56(切片右键创建异常) + R58-65(三维体详情·异常) + R69-88(异常/异常体列表/属性/过滤)。
  • 关键决策(用户 2026-06-18 定):
    • 异常挂「三维体」remarkSourceId=三维体 ds id不挂切片(切片是临时圈定载体)、不挂源 ds。见记忆 vtk-3d-persistence-structure
    • 全做:圈定 + 保存(含截图) + 3D 渲染 + 异常/异常体列表(对象→异常体→异常) + 选中联动 + 显示过滤 + 删除/删除分组。
    • 不参考 Geopro1.0:按需求 + 行业最佳实践(标准多边形圈定)。
    • 持久化 mock:三维体/切片/异常端点后端均未就绪 → 全 mock(内存)走 I3dSceneRepository,整链端点就绪再切真实。截图先存本地(R88 截图属性待后端新增)。

0. 现状(可复用 vs 新建,实证见探查)

资产 现状
core::Anomaly(name/typeName/markType点线面/localPts Vec2/线样式) 有,但2D(localPts=x距离·y深度),需补 3D 几何
I3dSceneRepository 异常接口(loadAnomalyTree/saveAnomaly/deleteAnomaly/deleteAnomalyGroup + AnomalyTree/AnomalyBody) 接口齐,实现是 stub(Api 回 onErr/空树)
ObjectExceptionPanel(对象→异常体→异常 树) 只读树完整,无勾选/选中/删除/过滤交互
render::buildAnomalies(点/线/面 vtkActor) 有,但坐标=2D(x,depth,0),需 3D(世界点)
异常 DTO(parseExceptions/groupByConsortium) + 真实读取(loadExceptionsByTmAsync) 真实读取链路通(后端就绪后用)
I3dSceneView 异常方法 / VtkSceneController 异常逻辑 / 3D 圈定工具 / 选中联动(3D) / 过滤 全无,需新建

1. 数据模型core::Anomaly 补 3D 几何

src/core/model/Anomaly.hpp 增(保留现有 2D 字段,新增 3D

  • struct Vec3 { double x,y,z; };
  • std::vector<Vec3> worldPts;:异常多边形/折线/点的世界 3D 坐标(落在所在切片平面上)。
  • Vec3 planeNormal{0,0,1}, planeOrigin{};:所在切片平面(法向+一点)——供重定位/正视,及与切片解耦后仍能定位。
  • 持久化补充字段(不入 core入仓储存储或 Anomaly 扩展)idvolumeDsId(=remarkSourceId)、exceptionTypeId/typeNameremarkscreenshotPathconsortiumId(异常体分组,空=未分组)。

core::Anomaly 保持渲染/几何纯数据id/归属/截图等持久化元数据放仓储的 StoredAnomaly 包装(同 StoredVolume/StoredSlice)。

2. 渲染3D 异常 actor + I3dSceneView 接口

  • render::buildAnomalies3D(const std::vector<core::Anomaly>&)(新增或改造 AnomalyActorworldPts 直接建点/折线/闭合多边形 actor世界坐标不再 ×1 深度);样式复用(lineColor/width/dashed);选中高亮(加粗/变色)。
  • I3dSceneView 新增:
    • addAnomaly(const core::Anomaly&) / removeAnomaly(id) / clearAnomalies()
    • setAnomalyVisible(id, bool) / setAnomalySelected(id, bool)(选中联动)
    • pickedAnomalyId() 或经回调 onAnomalyPicked(id)VTK 点选异常→列表)
  • VtkSceneViewmap<id, actor>,实现上述。

3. 圈定工具(切片平面上画多边形)

src/render/interact/AnomalyDrawTool.{hpp,cpp}(新):

  • 输入:当前选中切片的平面(origin/normal) + interactor + renderer。
  • 交互(行业标准):左键逐点加顶点(投影到切片平面);右键/双击/回车闭合Esc 取消;实时预览折线。点类型=单击一点;面=多边形闭合;(线/文字按 markType)。
  • 产物:worldPts(平面上的世界点) + planeNormal/origin → 回调上层。
  • 入口VTK 视图切片右键「创建异常」(已占位) → 启动本工具(以光标拾取点为起点R49)。

4. 保存对话框 + 截图

src/app/AnomalySaveDialog.{hpp,cpp}(新,参考 VolumeParamsDialog 风格):

  • 字段:异常名称、异常类型(下拉,mock 几个类型;真实类型端点 exceptionType/* 只读、后续可接)、备注。
  • 截图(R50):圈定结束截当前 VTK 视图(或异常包络区) → 存本地文件 → 路径+大小入异常记录(SliceExport 同款 PNG 写)。
  • accept → 组装 core::Anomaly(markType/worldPts/plane/样式) + 元数据(name/typeId/remark/screenshot) → saveAnomaly

5. 持久化 mockApi3dRepository挂三维体

  • StoredAnomaly { core::Anomaly geom; id; volumeDsId; exceptionTypeId/typeName; remark; screenshotPath; consortiumId; }map<id, StoredAnomaly> anomalies_
  • saveAnomaly(a, screenshotPath, onOk(id), onErr):生成 anomaly-N,存,回 id。接口已含 screenshotPath 参数)
  • loadAnomalyTree(objectId, onOk(tree), onErr):按 objectId 下所有三维体聚合异常 → 组 AnomalyTree(bodies=异常体分组 + loose=未分组)。mock 阶段:以 volumeDsId 关联,未分组进 loose。
  • deleteAnomaly(id) / deleteAnomalyGroup(bodyId):删/删组。
  • 异常体(consortium)分组mock 内存(map<bodyId, {name,typeName,memberIds}>);真实端点 exceptionConsortium/* 后续接。
  • 接口签名不变;后端整链就绪仅换实现。

6. 列表面板R69-88+ 选中联动 + 过滤

扩展 ObjectExceptionPanel(或在三维分析视图侧新建异常面板,复用其树构建):

  • 树:对象 → 异常体 → 异常 + 未分组异常(R71-77)。
  • 勾选(显隐)、单选(选中) → 信号;选中 ↔ VTK 视图异常高亮双向联动(R84)。
  • 操作(R79):删除异常、删除分组(deleteAnomaly/deleteAnomalyGroup)。
  • 异常属性(R83):选中异常 → 详情(名称/类型/坐标/截图/备注)。
  • 显示过滤(R86-87):全部显示 / 随GS / 随数据集 / 全部隐藏 → 控制 VTK 异常可见性集合。
  • 异常属性·截图(R88):展示截图缩略 + "确定截图大小"。

7. main.cpp 编排

  • 切片右键「创建异常」→ 启动 AnomalyDrawTool(用当前选中切片平面) → 圈定完成 → AnomalySaveDialogscene3dRepo->saveAnomaly → 渲染(view addAnomaly) + 刷新异常面板。
  • 当前对象/三维体变化 → loadAnomalyTree → 填异常面板 + 渲染已存异常。
  • 面板选中/勾选/过滤/删除 → 驱动 view 的 setAnomalyVisible/Selected + 仓储删VTK 点选异常 → 面板选中(联动)。

8. 阶段(每阶段编译绿 + 用户实测)

  • 4a 基础§1 模型 + §2 渲染/接口 + §5 mock 持久化(saveAnomaly/loadAnomalyTree/delete) + main 加载已存异常渲染。可注入一两个测试异常验证 3D 渲染。无圈定/对话框。
  • 4b 圈定+保存§3 圈定工具 + §4 保存对话框(含截图) + 切片右键「创建异常」接通 → 闭环:画→存→显示→删。
  • 4c 列表/异常体/联动/过滤§6 面板交互(选中联动/过滤/删除分组) + 异常体分组 + 异常属性/截图展示。

9. 风险/待确认

  • core::Anomaly 改动影响 2D 路径:补字段不动现有 2D 字段2D 渲染(ContourPlotItem/buildAnomalies)不受影响3D 走新 worldPts 路径。
  • 异常体(consortium)创建入口:需求 R71 有异常体,但"如何把异常归入异常体"的 UI 入口需求未细化 → 4c 落地时按最佳实践补(多选异常→成组),或先只做 loose + 展示分组。
  • 截图属性后端缺(R88 待新增):先本地存,后端加字段再上传。
  • 真实类型/异常体端点只读可接mock 阶段先 mock降耦合可选接真实只读。