From 65283492fb89ba71ad409d1665627412c741abcd Mon Sep 17 00:00:00 2001 From: gaozheng Date: Mon, 8 Jun 2026 11:46:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(render):=20=E5=88=87=E7=89=87=E4=B8=8E?= =?UTF-8?q?=E4=BD=93=E7=B4=A0=E7=BA=B5=E5=90=91=E4=B8=80=E8=87=B4=20?= =?UTF-8?q?=E2=80=94=20=E6=8A=8A=E7=BA=B5=E5=90=91=E5=A4=B8=E5=BC=A0?= =?UTF-8?q?=E7=83=A4=E8=BF=9B=E4=BD=93=E7=B4=A0=20image(=E5=88=87=E7=89=87?= =?UTF-8?q?=E7=A9=BF=E8=BF=87=E4=BD=93=E7=B4=A0=E8=80=8C=E9=9D=9E=E5=9C=A8?= =?UTF-8?q?=E6=97=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 反馈: 切片显示在 3D 图形旁边/比例不符。根因: 切片(vtkImagePlaneWidget)作用于体素 image 原始 米坐标(1x), 而体素体绘制/帘面是 3x(actor SetScale) → 纵向比例不一致, 切片错位。 - 修: buildVoxelFromScatters 加 zDisplayScale, 把纵向夸张烤进输出 image 的 z 原点/间距 (IDW 采样仍用真实 cellZ); app 传 kCurtainZScale 并去掉 volume 的 actor SetScale。 现体绘制/切片/帘面同在 3x 坐标 → 切片穿过体素、与帘面纵向一致。 - 全 40 测试绿; app 构建干净。(render_verify 仍用默认 1x 在原始坐标核对配准, 不受影响。) --- src/app/main.cpp | 7 ++++--- src/render/VoxelFromScatters.cpp | 10 ++++++---- src/render/VoxelFromScatters.hpp | 5 ++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/app/main.cpp b/src/app/main.cpp index 19f0271..1260151 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -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) { diff --git a/src/render/VoxelFromScatters.cpp b/src/render/VoxelFromScatters.cpp index 3a48667..ce32faa 100644 --- a/src/render/VoxelFromScatters.cpp +++ b/src/render/VoxelFromScatters.cpp @@ -33,7 +33,8 @@ VoxelResult buildVoxelFromScatters(const std::vector 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 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; } diff --git a/src/render/VoxelFromScatters.hpp b/src/render/VoxelFromScatters.hpp index c98945b..b7eed17 100644 --- a/src/render/VoxelFromScatters.hpp +++ b/src/render/VoxelFromScatters.hpp @@ -24,6 +24,8 @@ struct VoxelResult { // 垂向 z = -ylist(深度向下,与帘面 z 取负一致)。 // IDW:maxDist 裁剪约束插值域(两交叉测线→十字片,设计 §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& profiles, const geopro::core::ColorScale& cs, @@ -32,6 +34,7 @@ VoxelResult buildVoxelFromScatters(const std::vector 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