diff --git a/docs/superpowers/HANDOFF-vtk-category-view-refactor.md b/docs/superpowers/HANDOFF-vtk-category-view-refactor.md index d9a39fb..a0f2bd5 100644 --- a/docs/superpowers/HANDOFF-vtk-category-view-refactor.md +++ b/docs/superpowers/HANDOFF-vtk-category-view-refactor.md @@ -64,7 +64,7 @@ f00a214 feat(data): VoxelGenerateRequest/SliceGenerateRequest DTO + toJson 2. **dict 填充**:main 创建 `DatasetFieldDictionary` 并传 `new ColumnDrawer(centerWidget, &dict)`;对每个反演 dsType 调 `loadDatasetFormAsync`→`parseFieldMapping`→`dict.setFields`(装置/日期筛选才生效,现 dict=nullptr 退化不筛)。 3. **工具条接入**:实例化 `VtkViewToolbar` 叠加中央 QVTK,信号接 sceneCtrl(viewRequested/zoom/fit 接现有 c3 对应槽 :647 区;axesSettingsRequested→弹 `AxesSettingsDialog`→应用坐标轴);VE 控件迁工具条。 4. **VolumeParamsDialog 扩展**:左侧勾选源 ds 树(按 GS 分组·可二次增删) + 右侧「生成位置」下拉(项目内 GS/TM,默认 源单GS→该GS/跨GS→项目根)→ 填 `req.structParentId/structParentConfType`。 -5. **异常迁三维体段(Task 11 本体)**:给 `CategorySection`(voxel 段)/`CategoryAnalysisTab` 加异常子区 + `setItemChecked`/sliceRequested/sliceDelete/sliceSave 等 API(迁 `Column3DAnalysis` :395 refreshAnomalies 控件);main `refreshAnomalies`(:~397) 改用 analysisTab。 +5. **三维体段三级树 + 异常按归属挂体/切片(Task 11 本体,已重新设计,见 spec §8 / plan Task 11)**:**取消独立异常区**——异常作叶子挂归属实体(体/切片)下。归属链 `异常→所在切片→切片所属体`,挂载目标由「切片是否已保存成 dd_slice」决定(已存挂切片、临时挂体)。改 `Anomaly`(volumeDsId→remarkSourceId+remarkSourceType)、Api3d 异常 mock 按归属存查、main 创建逻辑判断切片是否保存、三维体段「体→切片/异常」三级树。多体渲染本就支持(`dsProps_` 按 dsId),`volumeOwnerDs_`=当前切片源体。 6. **退役旧栏**:删 main 中 c3/ca 旧接线(:641/669-760 区)、col3D()/colAnalysis() 调用、`Column3D*` 实例;删 ColumnDrawer 的 col3D_/colAnalysis_ 成员+访问器;评估删 splitByDimension(dim2D 改轻量过滤)。 - 切片保存/关闭(:584/623 setItemChecked)、createSlice projectId(:579/745) 随 #5/#1 一并处理。 diff --git a/docs/superpowers/plans/2026-06-24-vtk-category-view-refactor.md b/docs/superpowers/plans/2026-06-24-vtk-category-view-refactor.md index 8d64cce..d236053 100644 --- a/docs/superpowers/plans/2026-06-24-vtk-category-view-refactor.md +++ b/docs/superpowers/plans/2026-06-24-vtk-category-view-refactor.md @@ -1028,23 +1028,36 @@ git commit -m "feat(data): createVolume/createSlice 扩参+请求体DTO组装(mo --- -### Task 11: 三维体/切片/异常段呈现(异常迁三维体段) +### Task 11: 三维体段「体→切片/异常」三级树 + 异常按归属挂体/切片(spec §8) + +> **设计修订(2026-06-24)**:取消「独立异常区」的旧设计。异常不再单列、不再"随当前活动体"展示,而是作为叶子挂在它**归属的实体节点**(体 或 切片)下。归属按 `异常→所在切片→切片所属体` 链确定,挂载目标由「切片是否已保存成 dd_slice」决定(见 spec §8)。多体渲染本就支持(`VtkSceneView::dsProps_` 按 dsId 各存 actor);`volumeOwnerDs_`/`currentVolumeImage_` = 当前切片操作所基于的体(非"唯一可渲体")。 **Files:** -- Modify: `src/app/panels/columns/CategorySection.cpp`(三维体段:异常子区)、`CategoryAnalysisTab.cpp` -- Modify: `src/app/main.cpp`(refreshAnalysis 改注入三维体段/切片段) +- Modify: `src/core/model/Anomaly.hpp`(`volumeDsId` → `remarkSourceId` + `remarkSourceType`) +- Modify: `src/data/api/Api3dRepository.{hpp,cpp}`(`saveAnomaly`/`loadAnomalyTree` mock 按 remarkSource 存/查;anomalyRows 供树注入) +- Modify: `src/app/main.cpp`(创建异常时判断所在切片是否已保存 → 设 remarkSourceId/Type;refreshAnomalies 改注入三维体段树) +- Modify: `src/app/panels/columns/CategorySection.cpp` / `CategoryAnalysisTab.{hpp,cpp}`(三维体段三级树 + 切片/异常勾选·详情·删除转发) +- Test: `tests/...`(remarkSource 归属判定纯函数 + Api3d 异常 mock 存查) -**实现要点:** 三维体段(`spec.id=="voxel"`)的段体下,复用现 `Column3DAnalysis` 的 3D 异常列表/显示过滤档位/单条显隐控件(迁入本段,随当前活动体展示,逻辑沿用 main.cpp:394-427 refreshAnomalies);切片段(`id=="slice"`)按 `parentId`=父体分组。三维体「正在生成」本期不做异步态(spec §8)。 +**Interfaces / 数据模型:** +- `enum class RemarkSourceType { Volume = 1, Slice = 2 };`(对齐后端 remark 概念) +- `Anomaly`:删 `volumeDsId`,加 `std::string remarkSourceId;`(体 dsId 或 切片 dsId)+ `RemarkSourceType remarkSourceType;`。 +- 纯函数(可单测):`struct AnomalyMount { std::string remarkSourceId; RemarkSourceType type; };` + `AnomalyMount resolveAnomalyMount(bool sliceIsSaved, const std::string& savedSliceDsId, const std::string& volumeDsId);` + —— 已保存切片→{sliceDsId, Slice};否则→{volumeDsId, Volume}。 -- [ ] **Step 1: 三维体段加异常子区**(迁 Column3DAnalysis 异常控件) -- [ ] **Step 2: 切片段按父体分组**(populateDatasetList 的 parentId 建树天然支持) -- [ ] **Step 3: build + 手动验证**(生成体→出现在三维体段;保存切片→切片段挂父体下;异常→三维体段异常子区) -- [ ] **Step 4: 提交** +- [ ] **Step 1(逻辑层,可单测): Anomaly 模型 + resolveAnomalyMount** + 改 `Anomaly`(remarkSourceId/Type,全量改其引用点:VtkSceneView addAnomaly/removeAnomaly 按 id 跟踪不受影响,仅 main 创建处赋值变);写 `resolveAnomalyMount` 纯函数 + 单测(已保存切片挂切片 / 临时切片挂体 两例)。**build test 绿**。 +- [ ] **Step 2(逻辑层): Api3dRepository 异常 mock 按归属存查** + `StoredAnomaly` 按 remarkSourceId/Type 存;`loadAnomalyTree(sourceId)` 或新增 `anomalyRows(remarkSourceId)` 返回该体/切片下异常行(DsRow 形态,ddCode 自定如 `dd_anomaly`,parentId=remarkSourceId)供树注入;`saveAnomaly` 存 remarkSource。单测:挂体/挂切片分别能查回。 +- [ ] **Step 3: main 创建异常逻辑**(main:~502 区) + 画异常时从 `interactionMgr` 取当前选中切片状态:已保存切片→其 dsId(`selectSavedSlice`/`selectedSavedSliceId` 核实接口);临时切片→`volumeOwnerDs_`。调 `resolveAnomalyMount` 设 `a.remarkSourceId/remarkSourceType`。(**先核实 interactionMgr 如何区分"当前切片已保存 vs 临时"+取其 dsId**,不凭印象。) +- [ ] **Step 4(UI,需真实验证): 三维体段三级树** + `refreshAnomalies` 改:把异常行按 remarkSourceId 注入三维体段树——挂体异常作体节点子、挂切片异常作切片节点子;切片作体节点子(parentId=volumeDsId)。`CategoryAnalysisTab`/`CategorySection`(voxel 段)补:体/切片/异常三级建树 + 异常/切片勾选·详情·删除信号转发(迁 `Column3DAnalysis` 对应控件逻辑)。 +- [ ] **Step 5: build + 手动验证**(生成体→体节点;体上画异常(切片未存)→异常挂体下;保存切片→切片挂体下;切片上画异常→异常挂该切片下;勾选/详情/删除各级生效) +- [ ] **Step 6: 提交**(分逻辑层[Step1-3] 与 UI[Step4] 两 commit;前者可 build test 绿,后者 build app + 真实验证) -```bash -git add src/app/panels/columns/CategorySection.cpp src/app/panels/columns/CategoryAnalysisTab.cpp -git commit -m "feat(ui): 三维体/切片/异常段呈现(异常迁三维体段)" -``` +> **波及**:`Anomaly.volumeDsId` 改名会触及现有所有读取点(VtkSceneView 渲染按 worldPts/plane,不读 volumeDsId;main saveAnomaly 赋值;Api3dRepository StoredAnomaly)——Step 1 一并改全。切片保存/关闭(main setItemChecked)随三级树勾选 API 一并迁。 --- diff --git a/docs/superpowers/specs/2026-06-24-vtk-category-view-refactor-design.md b/docs/superpowers/specs/2026-06-24-vtk-category-view-refactor-design.md index 8877251..70fb1f8 100644 --- a/docs/superpowers/specs/2026-06-24-vtk-category-view-refactor-design.md +++ b/docs/superpowers/specs/2026-06-24-vtk-category-view-refactor-design.md @@ -59,8 +59,12 @@ │ ▾ ☐ ERT2 (GS) [右键:生成体]│ │ ▼ 视电阻率数据 [日期▾][装置类型▾]│ │ ▼ 瞬变电磁数据 [日期▾] │ 无装置类型筛选 -│ ▼ 三维体 [日期▾] │ 已生成体(+正在生成态)+异常 -│ ▼ 切片 [日期▾] │ 已保存切片(挂父体下) +│ ▼ 三维体 [日期▾] │ 体→[切片们 + 直接挂体的异常]三级树 +│ ▾ 体A │ +│ ▾ 切片S1(挂体A) │ +│ 异常a1(挂S1) │ +│ 异常a2(挂体A,临时切片上画) │ +│ ▼ 切片 [日期▾] │ 已保存切片(挂父体下,与三维体段切片同源) └──────────────────────────────────────┘ ``` @@ -130,9 +134,16 @@ checkedSourcesChanged 复用现有 `Api3dRepository`(mock)与 `refreshAnalysis` 合并注入机制,仅重新组织到段: -> 三维体归属由「生成位置」选择决定:默认单 GS→该 GS、跨 GS→项目根,用户可改为项目内任意 **GS / TM**(`structParentConfType` 可 1 或 2)。后端契约 `docs/api/vtk-3d-openapi.json` 已同步至 v0.6-draft(`structParentConfType` 放开 1/2 + 默认规则);客户端 `createVolume` 接真实端点时需补 `structParentId/structParentConfType`,并新增按三维体 id 查异常的 `queryException/{remarkSourceId}` 调用。 -- **三维体段**:列已生成的体(客户端 mock + 后端 `dd_voxel`),按归属(项目/GS/TM)分组。(**「正在生成…」状态**:现 `createVolume` 同步登记、首次 `loadVolume` 惰性插值,本期**不引入异步生成态机**、体即时出行;如需占位仅作纯展示文案、不做进度。)异常挂三维体(记忆 `vtk-3d-persistence-structure`):现 `Column3DAnalysis` 的 3D 异常列表 / 显示过滤档位 / 单条显隐,迁入三维体段内(随当前活动体展示)。 -- **切片段**:列已保存切片(`dd_slice`),按父体分组(`parentId` = 所属体)。 +> 三维体归属由「生成位置」选择决定:默认单 GS→该 GS、跨 GS→项目根,用户可改为项目内任意 **GS / TM**(`structParentConfType` 可 1 或 2)。后端契约 `docs/api/vtk-3d-openapi.json` 已同步至 v0.6-draft(`structParentConfType` 放开 1/2 + 默认规则);客户端 `createVolume` 接真实端点时需补 `structParentId/structParentConfType`,并新增按归属实体 id 查异常的 `queryException/{remarkSourceId}` 调用。 + +**三维体段是「体 → 切片 / 异常」三级树**(**取消独立异常区**——异常不再单列,而是作为叶子挂在它归属的实体节点下): + +- **三维体段**:列已生成的体(客户端 mock + 后端 `dd_voxel`),按归属(项目/GS/TM)分组。(**「正在生成…」状态**:现 `createVolume` 同步登记、首次 `loadVolume` 惰性插值,本期**不引入异步生成态机**、体即时出行。)体节点下挂:① 基于该体生成的**切片**子节点;② **直接挂体的异常**(见归属规则)。多体可同时勾选渲染(`dsProps_` 按 dsId 各存 actor),切片/异常操作针对「当前激活体」`volumeOwnerDs_`(=切片源体 `currentVolumeImage_`)。 +- **异常归属(核心规则)**:异常**必基于切片**(在某切片平面上画),切片**必基于体**(`SliceSpec.volumeDsId`)。查找链 `异常 → 所在切片 → 切片所属体`。挂载目标按**该切片是否已保存成 `dd_slice`** 决定: + - 切片**已保存**(是 `dd_slice` 实体)→ 异常挂**该切片**(`remarkSourceType=切片`,`remarkSourceId=切片dsId`)。 + - 切片**未保存**(临时圈定平面)→ 异常挂**切片所属体**(`remarkSourceType=体`,`remarkSourceId=体dsId=volumeOwnerDs_`)。 + - 数据模型:`Anomaly` 由原写死的 `volumeDsId` 改为 `remarkSourceId` + `remarkSourceType`(体/切片二选一),对齐后端 remark 概念。仍 mock 存储。 +- **切片段**:列已保存切片(`dd_slice`),按父体分组(`parentId` = 所属体)。与三维体段内的切片子节点同源(同一批 `sliceRows`)。 体素 / 切片 / 异常的渲染、生成、保存路径不变(`VtkSceneController` / `InteractionManager` / `Api3dRepository`),只改列表的承载位置。