6.0 KiB
设计:三维体/切片 数据详情(只读属性对话框)
日期 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(新增)
// 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 分派:
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 三维视图交互(详情只读查阅,职责清晰)。