From eb8cb9e7eed9f42cc2dd90e19e4015c5d13cbcc8 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Tue, 16 Jun 2026 10:26:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(vtk):=20=E5=88=87=E7=89=87=E6=97=8B?= =?UTF-8?q?=E8=BD=AC=E6=94=AF=E7=82=B9=E7=94=A8=E5=88=87=E7=89=87=E4=B8=AD?= =?UTF-8?q?=E5=BF=83=E8=80=8C=E9=9D=9E=E7=82=B9=E5=87=BB=E7=82=B9(?= =?UTF-8?q?=E6=A0=B9=E5=9B=A0=E4=BF=AE=E5=A4=8D,=E6=8D=AE=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AF=81=E6=8D=AE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 诊断日志证据: onPicked 改相机后 dir(视向) before==after, 补偿正确、点击瞬间画面不变; 但命中点 world 明显偏离体中心 → 之前以'点击点'为焦点, 拖动绕偏心点旋转→大幅摆动(=用户的'跳')。 根因修复: 旋转焦点设为**切片中心**(slices_[idx]->center(), ≈体中心, spec C38 '以切片为中心'), 焦点+位置同步平移保持画面不变 → 点击不跳、拖动绕切片中心居中旋转、不甩。 未命中切片则不动相机。 --- src/render/interact/InteractionManager.cpp | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/render/interact/InteractionManager.cpp b/src/render/interact/InteractionManager.cpp index 4bcfbc6..bcef9ee 100644 --- a/src/render/interact/InteractionManager.cpp +++ b/src/render/interact/InteractionManager.cpp @@ -131,12 +131,28 @@ int InteractionManager::nearestSlice(const Vec3& worldPoint) const { } void InteractionManager::onPicked(const Vec3& worldPoint) { - // 单击 = 仅选中命中的切片(不动相机 → 绝不跳;拖动旋转交给默认 TrackballCamera)。 - // 原"把焦点移到命中点以绕其旋转"实测会让视图跳变,去掉。选中切片高亮 + 供滚轮推进/关闭。 const int idx = nearestSlice(worldPoint); - if (idx >= 0) { - selected_ = idx; - updateSelectionVisual(); + if (idx < 0) { + safeRender(); // 未命中切片:不动相机(拖动绕当前中心旋转,不甩) + return; + } + selected_ = idx; + updateSelectionVisual(); + + // 旋转中心 = 切片中心(spec C38 "以切片为中心旋转"),**不是点击点**: + // 实测点击点常远离体中心,绕它拖动旋转会大幅摆动(=用户看到的"跳");切片中心≈体中心 → 居中、不甩。 + // 焦点与相机位置同步平移同一 delta → 视向/距离不变、点击瞬间画面不动;之后 TrackballCamera 绕切片中心旋转。 + if (renderer_) { + if (auto* cam = renderer_->GetActiveCamera()) { + const Vec3 c = slices_[static_cast(idx)]->center(); + double f[3], p[3]; + cam->GetFocalPoint(f); + cam->GetPosition(p); + const double d[3] = {c[0] - f[0], c[1] - f[1], c[2] - f[2]}; + cam->SetFocalPoint(c[0], c[1], c[2]); + cam->SetPosition(p[0] + d[0], p[1] + d[1], p[2] + d[2]); + renderer_->ResetCameraClippingRange(); + } } safeRender(); }