#pragma once #include #include #include "interact/SlicePlaneMath.hpp" namespace geopro::render::interact { // 自定义交互样式:在 TrackballCamera 基础上加拾取与切片交互(spec §9.3)。 // 左键按下 → vtkPropPicker 拾取 → 命中则相机 focalPoint=命中点(拖动绕其旋转), // 并把命中世界点回调出去(InteractionManager 据此选中所在切片)。 // 左键双击 → 回调双击世界点(InteractionManager 找最近切片 → 相机正视其法向)。 // 滚轮前/后 → 回调步进方向(±1),由 manager 推进选中切片;无选中则回退默认缩放。 // 保留 TrackballCamera 的相机拖动/缩放等基础交互(仅在命中/有选中切片时改写行为)。 // // 回调由 InteractionManager 注入(render 层不认业务,只发"命中点/双击/滚轮"事件)。 class PickInteractorStyle : public vtkInteractorStyleTrackballCamera { public: static PickInteractorStyle* New(); vtkTypeMacro(PickInteractorStyle, vtkInteractorStyleTrackballCamera); // 单击命中世界点(已命中某 prop)。用于设焦点+选中切片。 std::function onPick; // 双击世界点。用于正视所在切片。 std::function onDoubleClick; // 滚轮步进:dir=+1 前/-1 后。返回 true 表示已被消费(有选中切片推进), // false 则执行默认相机缩放。 std::function onWheelStep; // 取当前旋转中心(D39):有选中三维体/切片→填其中心、返回 true;否则 false(绕默认焦点)。 // 在"按下开始拖动"时调用一次,把焦点设到该中心(位置同步补偿,画面不变)→ 之后绕它旋转、不跳。 std::function getRotateCenter; // 取消选中切片(Esc 键触发)。拉近后满屏切片、点不到空白处取消时的可靠出口。 std::function onDeselect; // 精确判定:当前光标【射线】是否穿过某张切片的真实矩形(origin/point1/point2)内。 // 不靠带容差/夹取的 picker 命中点 → 切片边界外不再误判命中(用户实测的外扩)。 // 点帘面/其它非切片物/边界外 → 返回 false → 单击即取消选中。 std::function hitTestSlice; void OnMouseMove() override; void OnLeftButtonUp() override; void OnLeftButtonDown() override; void OnMouseWheelForward() override; void OnMouseWheelBackward() override; void OnKeyPress() override; // Esc → onDeselect(取消选中切片) // 绕选中物中心旋转(D39):有 getRotateCenter 时, 绕该中心增量旋转整个相机(位置+焦点+up), // 中心在世界/屏幕都不动→不跳; 否则回退默认(绕焦点)。 void Rotate() override; protected: PickInteractorStyle() = default; private: // 在当前鼠标位置拾取世界点;命中返回 true 并填 out。 bool pickWorld(Vec3& out); // 手动双击判定:QVTK+Windows 下 vtkRenderWindowInteractor::GetRepeatCount() 不可靠(评审 M5)。 // 记上次左键按下时刻+屏幕位置,两次按下间隔 < kDoubleClickMs 且位置相近视为双击。 double lastDownTime_ = -1.0; // 单调时钟(毫秒),-1=无 int lastDownPos_[2] = {0, 0}; // 左键按下时是否命中【切片】(精确:经 hitTestSlice 判点在切片矩形内,非"任意可拾取物")。 // 抬键若为单击(无拖动)且未命中切片 → 取消选中(点空/点体/帘面/其它非切片物)。 // 体 PickableOff、帘面虽可拾取但 hitTestSlice 判其非切片 → 都走取消。拖动则不取消(保留旋转)。 bool downHitSlice_ = false; // 旋转支点:按下(拖动起点)时经 getRotateCenter 捕获一次,拖动中固定不漂(光标会动→不可每帧重取)。 // 选中切片=其中心;否则=光标射线穿过的体中段点。无则 hasRotatePivot_=false→默认绕焦点。 Vec3 rotatePivot_{}; bool hasRotatePivot_ = false; }; } // namespace geopro::render::interact