fix(render): 切片与体素纵向一致 — 把纵向夸张烤进体素 image(切片穿过体素而非在旁)

- 反馈: 切片显示在 3D 图形旁边/比例不符。根因: 切片(vtkImagePlaneWidget)作用于体素 image 原始
  米坐标(1x), 而体素体绘制/帘面是 3x(actor SetScale) → 纵向比例不一致, 切片错位。
- 修: buildVoxelFromScatters 加 zDisplayScale, 把纵向夸张烤进输出 image 的 z 原点/间距
  (IDW 采样仍用真实 cellZ); app 传 kCurtainZScale 并去掉 volume 的 actor SetScale。
  现体绘制/切片/帘面同在 3x 坐标 → 切片穿过体素、与帘面纵向一致。
- 全 40 测试绿; app 构建干净。(render_verify 仍用默认 1x 在原始坐标核对配准, 不受影响。)
This commit is contained in:
gaozheng 2026-06-08 11:46:39 +08:00
parent f57291a127
commit 65283492fb
3 changed files with 14 additions and 8 deletions

View File

@ -397,11 +397,12 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
if (!is2D && (*showVoxel || *showSlice) && crs) {
const auto profs = repo.loadVoxelScatters();
const auto vcs = repo.loadScatterColorScale("grid1");
auto vr = geopro::render::buildVoxelFromScatters(profs, vcs, *crs, *frame);
// 纵向夸张烤进 image(zDisplayScale=kCurtainZScale),使体绘制/切片/帘面纵向一致。
auto vr = geopro::render::buildVoxelFromScatters(profs, vcs, *crs, *frame, 1.0, 0.5, 2.0,
4.0, kCurtainZScale);
if (vr.valid()) {
if (*showVoxel) {
vr.volume->SetScale(1.0, 1.0, kCurtainZScale);
rendererPtr->AddVolume(vr.volume);
rendererPtr->AddVolume(vr.volume); // 夸张已烤进 image无需 actor SetScale
}
vtkRenderWindowInteractor* interactor = renderWindowPtr->GetInteractor();
if (*showSlice && interactor) {

View File

@ -33,7 +33,8 @@ VoxelResult buildVoxelFromScatters(const std::vector<geopro::core::ScatterField>
double cellXY,
double cellZ,
double power,
double maxDist)
double maxDist,
double zDisplayScale)
{
// 1) 配准所有点到世界局部米 + 深度,组装 IDW 输入点集。
geopro::core::PointSet pts;
@ -89,10 +90,11 @@ VoxelResult buildVoxelFromScatters(const std::vector<geopro::core::ScatterField>
if (!(vmin < vmax)) { vmin = 0.0; vmax = 1.0; }
}
// 5) 体绘制 + 暴露 image(供切片)。
// 5) 体绘制 + 暴露 image(供切片)。纵向夸张烤进 image 的 z 原点/间距(IDW 已用真实 cellZ 采样)
// 使体绘制/切片/帘面纵向一致(切片穿过体素而非在旁)。
VoxelResult out;
out.volume = buildVoxel(vol, cs, spec.ox, spec.oy, spec.oz, spec.dx, spec.dy, spec.dz, vmin,
vmax, out.image);
out.volume = buildVoxel(vol, cs, spec.ox, spec.oy, spec.oz * zDisplayScale, spec.dx, spec.dy,
spec.dz * zDisplayScale, vmin, vmax, out.image);
return out;
}

View File

@ -24,6 +24,8 @@ struct VoxelResult {
// 垂向 z = -ylist(深度向下,与帘面 z 取负一致)。
// IDWmaxDist 裁剪约束插值域(两交叉测线→十字片,设计 §10)NaN 留空→体绘制透明。
// crs 须为「项目 CRS(如 EPSG:4547) → EPSG:4326」frame 与帘面/地图共用以保证空间配准。
// zDisplayScale把纵向夸张"烤进"输出 image 的 z 间距与原点(IDW 采样仍用真实 cellZ)
// 使体绘制 + 切片(vtkImagePlaneWidget 作用于此 image) + 帘面(actor SetScale 同倍)三者纵向一致。
// 输入不足(无点)返回 valid()==false 的空结果。
VoxelResult buildVoxelFromScatters(const std::vector<geopro::core::ScatterField>& profiles,
const geopro::core::ColorScale& cs,
@ -32,6 +34,7 @@ VoxelResult buildVoxelFromScatters(const std::vector<geopro::core::ScatterField>
double cellXY = 1.0,
double cellZ = 0.5,
double power = 2.0,
double maxDist = 4.0);
double maxDist = 4.0,
double zDisplayScale = 1.0);
} // namespace geopro::render