117 lines
6.0 KiB
Markdown
117 lines
6.0 KiB
Markdown
# 设计:三维体/切片 数据详情(只读属性对话框)
|
||
|
||
> 日期 2026-06-18。分支 `feat/vtk-3d-view`。收尾/打磨项 #6(见 `docs/superpowers/HANDOFF-vtk-3d.md` §4 末「下一步候选」)。
|
||
> 异常详情已用对话框做掉(`AnomalyPropertiesDialog`),本设计为**三维体 / 切片**补同类只读详情。
|
||
|
||
## 1. 目标与范围
|
||
|
||
三维分析栏右键「数据详情」时,弹出只读属性对话框展示该三维体 / 切片的元数据与统计。
|
||
- **形态**:只读 `QDialog`(仿 `AnomalyPropertiesDialog`),非停靠面板页签。
|
||
- 取舍理由:现成 `DatasetDetailController/Panel` 绑定 2D 的 `IAsyncDatasetRepository` + chartRegistry,而体/切片数据在 `Api3dRepository`(独立 3D 仓储),硬接需跨仓储桥接 + 新策略/视图,代价大、动共享设施风险高。对话框与刚落地的异常详情 UX 一致、零侵入 2D 管线。
|
||
- **内容范围**:参数/位姿随时可取;三维体统计(值域/测点数/范围)体被生成(loadVolume 缓存)后才显示,未生成显「—(生成/渲染后可见)」。
|
||
|
||
## 2. 架构与新增文件
|
||
|
||
仿 `src/app/AnomalyPropertiesDialog.{hpp,cpp}`,`QFormLayout` + `QLabel` 只读表:
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `src/app/VolumePropertiesDialog.{hpp,cpp}` | 三维体属性(参数 + 统计) |
|
||
| `src/app/SlicePropertiesDialog.{hpp,cpp}` | 切片属性(位姿 + 参数) |
|
||
|
||
两个对话框各自独立、构造即填充、`exec()` 模态,无网络、无加载态。
|
||
|
||
## 3. 数据获取
|
||
|
||
只改具体类 `src/data/api/Api3dRepository.{hpp,cpp}`;**接口 `I3dSceneRepository` 与 `LocalSample3dRepository` 不动**(`main.cpp` 持有具体 `scene3dRepo`,见 main.cpp:266,全程直接用)。
|
||
|
||
### 3.1 三维体 getter(新增)
|
||
|
||
```cpp
|
||
// Api3dRepository.hpp 内嵌结构 + 方法
|
||
struct VolumeInfo {
|
||
VolumeBuildParams params;
|
||
std::string name;
|
||
bool loaded = false; // cachedGrid 是否已就绪(= loadVolume 跑过)
|
||
// 以下仅 loaded 时有效:
|
||
double vmin = 0.0, vmax = 0.0; // 来自 cachedGrid
|
||
int nx = 0, ny = 0, nz = 0; // 网格维度
|
||
double dx = 0, dy = 0, dz = 0; // 单元间距(来自 cachedGrid.spacing)
|
||
std::size_t pointCount = 0; // 聚合后参与插值的散点数
|
||
};
|
||
bool volumeInfo(const std::string& dsId, VolumeInfo& out) const; // 非体返回 false
|
||
```
|
||
|
||
- `loaded` 取 `StoredVolume::cachedGrid.has_value()`;统计字段从 `cachedGrid`(vmin/vmax、`vol.nx()/ny()/nz()`、`spacing`)填。
|
||
- **测点数持久化**:`StoredVolume` 增 `std::optional<std::size_t> pointCount`,在 `finalizeVolume`(散点聚合完成处)写入 `pts.v.size()`。`volumeInfo` 透出。
|
||
|
||
### 3.2 切片数据
|
||
|
||
复用已有 `bool sliceSpec(const std::string& dsId, SliceSpec& out) const`(main.cpp 已在用)取位姿;名称用 `detailRequested` 信号已携带的 `name`,不新增 getter。
|
||
|
||
## 4. 触发与接线(`main.cpp`)
|
||
|
||
`detailRequested` 仅来自三维分析栏(`Column3DAnalysis`,项非体即切片;右键菜单「数据详情」已接,无需改 Column3DAnalysis),现连接 `detailCtrl.openDataset`(对 3D dsId 会降级失败)。改为按 ddCode 分派:
|
||
|
||
```cpp
|
||
QObject::connect(ca, &Column3DAnalysis::detailRequested, &window,
|
||
[&window, scene3dRepo](const QString& dsId, const QString& ddCode, const QString& name) {
|
||
if (ddCode == QStringLiteral("dd_slice")) {
|
||
I3dSceneRepository::SliceSpec sp;
|
||
if (scene3dRepo->sliceSpec(dsId.toStdString(), sp)) {
|
||
SlicePropertiesDialog dlg(name, sp, &window); dlg.exec();
|
||
}
|
||
} else { // dd_voxel
|
||
Api3dRepository::VolumeInfo info;
|
||
if (scene3dRepo->volumeInfo(dsId.toStdString(), info)) {
|
||
VolumePropertiesDialog dlg(name, info, &window); dlg.exec();
|
||
}
|
||
}
|
||
});
|
||
```
|
||
|
||
`src/app/CMakeLists.txt` 加两个新 `.cpp`。
|
||
|
||
## 5. 内容字段
|
||
|
||
### 三维体(`VolumePropertiesDialog`)
|
||
- 名称
|
||
- 源数据集(`sourceDatasetIds`,逗号连接)
|
||
- 插值模型(IDW / Kriging)+ 幂指数(IDW 时显 `power`)
|
||
- 网格间距(`XY=cellXY m Z=cellZ m`)
|
||
- 超距(`maxDist m`)
|
||
- 色阶来源(`colorScaleId`,空显「首个源数据集」)
|
||
- **统计**(loaded 才有,否则全显「—(生成/渲染后可见)」):
|
||
- 值域(`vmin ~ vmax`)
|
||
- 网格(`nx × ny × nz`)
|
||
- 测点数(`pointCount`)
|
||
- 范围(`nx·dx × ny·dy × nz·dz` 米)
|
||
|
||
### 切片(`SlicePropertiesDialog`)
|
||
- 名称
|
||
- 所属三维体(`volumeDsId`)
|
||
- 轴向(0 上下 / 1 前后 / 2 左右 / 3 任意)
|
||
- 平面三点 Origin / Point1 / Point2(各 `(x, y, z)` 米,2 位小数)
|
||
- 色阶来源(`colorScaleId`,空显「首个源数据集」)
|
||
|
||
> 切片**不含统计项**:采样分辨率/值域来自渲染时的切面网格,仓储层不持久化(`StoredSlice` 仅存 `spec`+`name`)。回写渲染产物属额外 plumbing,守 YAGNI 不做。位姿/参数已完整。
|
||
|
||
## 6. 错误处理
|
||
|
||
- `volumeInfo` / `sliceSpec` 取不到(非体/非切片)→ 返回 false,不弹空对话框(理论不发生,触发来自该行)。
|
||
- 统计未就绪 → 占位「—(生成/渲染后可见)」,不报错。
|
||
|
||
## 7. 测试
|
||
|
||
- 新增 gtest(`tests/` 内 Api3dRepository 测套,若无则新建)覆盖 `volumeInfo`:
|
||
- `createVolume` 后、`loadVolume` 前:`volumeInfo` 返回 true、`params`/`name` 正确、`loaded=false`、`pointCount=0`。
|
||
- `loadVolume` 成功后:`loaded=true`、`vmin<vmax`、`nx/ny/nz>0`、`pointCount>0`。
|
||
- 非体 dsId:返回 false。
|
||
- 对话框为纯只读 UI(无逻辑分支),不做单测,靠 GUI 实测(Claude 无法 GUI 验证,交用户)。
|
||
|
||
## 8. 影响面 / 不变量
|
||
|
||
- 接口 `I3dSceneRepository` 与 `LocalSample3dRepository` 零改动 → 真实后端就绪后切换不受影响。
|
||
- `finalizeVolume` 仅多写一个 `pointCount`,不改插值/渲染行为。
|
||
- 不与 VTK 三维视图交互(详情只读查阅,职责清晰)。
|