fix(vtk): 切片单击=仅选中(不动相机,去跳)+高亮反馈
- onPicked 去掉改相机焦点/位置(实测仍致点击跳变)→ 单击仅选中命中切片; 拖动旋转回归默认 TrackballCamera(绕场景中心,不跳)。'以切片为中心旋转'(C38) 因致跳且预期不清,暂去, 后续用更稳方式再加。 - SliceTool::setSelected: 选中切片边框高亮(亮黄粗线)、其余暗灰; InteractionManager 在 单击/新增/关闭/双击 后 updateSelectionVisual → 解决'选中无视觉反馈'。 - ctest 221/221
This commit is contained in:
parent
ff3ce27978
commit
8a06014e0b
|
|
@ -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<int>(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<SliceTool>(image_, interactor_, axis, colorScale_, vmin_, vmax_);
|
||||
slices_.push_back(std::move(tool));
|
||||
selected_ = static_cast<int>(slices_.size()) - 1; // 新切片选中
|
||||
updateSelectionVisual();
|
||||
safeRender();
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +90,7 @@ void InteractionManager::closeSelected() {
|
|||
// 选中停在原位就近(删后该位变成下一张;删的是末张则退一张),不跳回 0(评审 M2)。
|
||||
selected_ = slices_.empty() ? -1
|
||||
: std::min(selected_, static_cast<int>(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<std::size_t>(idx)]->center();
|
||||
const Vec3 normal = slices_[static_cast<std::size_t>(idx)]->normal();
|
||||
const double dist = cam->GetDistance(); // 保持当前观察距离
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ private:
|
|||
// 统一重绘:析构进行中(destroying_)跳过,避免 Qt 拆台时对半析构窗口 Render 崩溃(评审 H3)。
|
||||
void safeRender();
|
||||
|
||||
// 按 selected_ 刷新各切片高亮(选中亮黄、其余暗淡)。
|
||||
void updateSelectionVisual();
|
||||
|
||||
vtkRenderWindowInteractor* interactor_;
|
||||
vtkRenderWindow* renderWindow_;
|
||||
vtkRenderer* renderer_;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <vtkImageData.h>
|
||||
#include <vtkImagePlaneWidget.h>
|
||||
#include <vtkLookupTable.h>
|
||||
#include <vtkProperty.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
#include <vtkTrivialProducer.h>
|
||||
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue