From 8a06014e0b266217f9efde4be322a3d03ec9951a Mon Sep 17 00:00:00 2001 From: gaozheng Date: Tue, 16 Jun 2026 10:12:20 +0800 Subject: [PATCH] =?UTF-8?q?fix(vtk):=20=E5=88=87=E7=89=87=E5=8D=95?= =?UTF-8?q?=E5=87=BB=3D=E4=BB=85=E9=80=89=E4=B8=AD(=E4=B8=8D=E5=8A=A8?= =?UTF-8?q?=E7=9B=B8=E6=9C=BA,=E5=8E=BB=E8=B7=B3)+=E9=AB=98=E4=BA=AE?= =?UTF-8?q?=E5=8F=8D=E9=A6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - onPicked 去掉改相机焦点/位置(实测仍致点击跳变)→ 单击仅选中命中切片; 拖动旋转回归默认 TrackballCamera(绕场景中心,不跳)。'以切片为中心旋转'(C38) 因致跳且预期不清,暂去, 后续用更稳方式再加。 - SliceTool::setSelected: 选中切片边框高亮(亮黄粗线)、其余暗灰; InteractionManager 在 单击/新增/关闭/双击 后 updateSelectionVisual → 解决'选中无视觉反馈'。 - ctest 221/221 --- src/render/interact/InteractionManager.cpp | 29 +++++++++++----------- src/render/interact/InteractionManager.hpp | 3 +++ src/render/interact/SliceTool.cpp | 15 +++++++++++ src/render/interact/SliceTool.hpp | 3 +++ 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/render/interact/InteractionManager.cpp b/src/render/interact/InteractionManager.cpp index a9f79c0..4bcfbc6 100644 --- a/src/render/interact/InteractionManager.cpp +++ b/src/render/interact/InteractionManager.cpp @@ -59,6 +59,11 @@ void InteractionManager::safeRender() { if (renderWindow_ && !destroying_) renderWindow_->Render(); } +void InteractionManager::updateSelectionVisual() { + for (std::size_t i = 0; i < slices_.size(); ++i) + slices_[i]->setSelected(static_cast(i) == selected_); +} + void InteractionManager::setVolumeImage(vtkImageData* image, const geopro::core::ColorScale& cs, double vmin, double vmax) { // 体素重建/变更:先释放旧切片(旧 image 即将失效),再附着新 image。 @@ -74,6 +79,7 @@ void InteractionManager::addSlice(SliceAxis axis) { auto tool = std::make_unique(image_, interactor_, axis, colorScale_, vmin_, vmax_); slices_.push_back(std::move(tool)); selected_ = static_cast(slices_.size()) - 1; // 新切片选中 + updateSelectionVisual(); safeRender(); } @@ -84,6 +90,7 @@ void InteractionManager::closeSelected() { // 选中停在原位就近(删后该位变成下一张;删的是末张则退一张),不跳回 0(评审 M2)。 selected_ = slices_.empty() ? -1 : std::min(selected_, static_cast(slices_.size()) - 1); + updateSelectionVisual(); safeRender(); } @@ -124,22 +131,13 @@ int InteractionManager::nearestSlice(const Vec3& worldPoint) const { } void InteractionManager::onPicked(const Vec3& worldPoint) { - // 旋转中心设到命中点(spec C38/D39):焦点与相机位置**同步平移同一 delta**, - // 使渲染图像不变(视向/距离不变)、只把旋转中心移到命中点——否则只改焦点会让视图突然跳变(评审)。 - if (renderer_) { - if (auto* cam = renderer_->GetActiveCamera()) { - double f[3], p[3]; - cam->GetFocalPoint(f); - cam->GetPosition(p); - const double d[3] = {worldPoint[0] - f[0], worldPoint[1] - f[1], worldPoint[2] - f[2]}; - cam->SetFocalPoint(worldPoint[0], worldPoint[1], worldPoint[2]); - cam->SetPosition(p[0] + d[0], p[1] + d[1], p[2] + d[2]); - renderer_->ResetCameraClippingRange(); - } - } - // 若命中点落在某切片上(阈值内),选中之(供滚轮推进/关闭)。 + // 单击 = 仅选中命中的切片(不动相机 → 绝不跳;拖动旋转交给默认 TrackballCamera)。 + // 原"把焦点移到命中点以绕其旋转"实测会让视图跳变,去掉。选中切片高亮 + 供滚轮推进/关闭。 const int idx = nearestSlice(worldPoint); - if (idx >= 0) selected_ = idx; + if (idx >= 0) { + selected_ = idx; + updateSelectionVisual(); + } safeRender(); } @@ -149,6 +147,7 @@ void InteractionManager::onDoubleClicked(const Vec3& worldPoint) { auto* cam = renderer_->GetActiveCamera(); if (!cam) return; selected_ = idx; + updateSelectionVisual(); const Vec3 focal = slices_[static_cast(idx)]->center(); const Vec3 normal = slices_[static_cast(idx)]->normal(); const double dist = cam->GetDistance(); // 保持当前观察距离 diff --git a/src/render/interact/InteractionManager.hpp b/src/render/interact/InteractionManager.hpp index 3fa3f8e..6d75c5c 100644 --- a/src/render/interact/InteractionManager.hpp +++ b/src/render/interact/InteractionManager.hpp @@ -71,6 +71,9 @@ private: // 统一重绘:析构进行中(destroying_)跳过,避免 Qt 拆台时对半析构窗口 Render 崩溃(评审 H3)。 void safeRender(); + // 按 selected_ 刷新各切片高亮(选中亮黄、其余暗淡)。 + void updateSelectionVisual(); + vtkRenderWindowInteractor* interactor_; vtkRenderWindow* renderWindow_; vtkRenderer* renderer_; diff --git a/src/render/interact/SliceTool.cpp b/src/render/interact/SliceTool.cpp index 774b0e3..1129924 100644 --- a/src/render/interact/SliceTool.cpp +++ b/src/render/interact/SliceTool.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -129,6 +130,20 @@ double SliceTool::distanceToPlane(const Vec3& p) const { return std::abs(dot({p[0] - c[0], p[1] - c[1], p[2] - c[2]}, n)); } +void SliceTool::setSelected(bool sel) { + if (!widget_) return; + // 切片边框 = widget 的 PlaneProperty:选中→亮黄粗线,未选中→暗灰细线。 + if (auto* prop = widget_->GetPlaneProperty()) { + if (sel) { + prop->SetColor(1.0, 0.9, 0.1); + prop->SetLineWidth(3.0); + } else { + prop->SetColor(0.5, 0.5, 0.5); + prop->SetLineWidth(1.0); + } + } +} + void SliceTool::close() { if (!widget_) return; widget_->Off(); diff --git a/src/render/interact/SliceTool.hpp b/src/render/interact/SliceTool.hpp index 9f057d4..93b1b81 100644 --- a/src/render/interact/SliceTool.hpp +++ b/src/render/interact/SliceTool.hpp @@ -45,6 +45,9 @@ public: // 沿法向推进切面(滚轮,D46):origin += normal*step,夹在 image 包围盒内。 void advance(double step); + // 选中视觉反馈:选中→高亮边框(亮黄+粗线),未选中→暗淡细线。 + void setSelected(bool sel); + // 世界点到本切面(无限平面)的垂直距离绝对值。供 picker 命中判定"点在哪张切片上"。 double distanceToPlane(const Vec3& worldPoint) const;