74 lines
4.1 KiB
C++
74 lines
4.1 KiB
C++
#pragma once
|
||
#include <functional>
|
||
|
||
#include <vtkInteractorStyleTrackballCamera.h>
|
||
|
||
#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<void(const Vec3& worldPoint)> onPick;
|
||
// 双击世界点。用于正视所在切片。
|
||
std::function<void(const Vec3& worldPoint)> onDoubleClick;
|
||
// 滚轮步进:dir=+1 前/-1 后。返回 true 表示已被消费(有选中切片推进),
|
||
// false 则执行默认相机缩放。
|
||
std::function<bool(int dir)> onWheelStep;
|
||
// 取当前旋转中心(D39):有选中三维体/切片→填其中心、返回 true;否则 false(绕默认焦点)。
|
||
// 在"按下开始拖动"时调用一次,把焦点设到该中心(位置同步补偿,画面不变)→ 之后绕它旋转、不跳。
|
||
std::function<bool(Vec3& center)> getRotateCenter;
|
||
// 取消选中切片(Esc 键触发)。拉近后满屏切片、点不到空白处取消时的可靠出口。
|
||
std::function<void()> onDeselect;
|
||
// 精确判定:当前光标【射线】是否穿过某张切片的真实矩形(origin/point1/point2)内。
|
||
// 不靠带容差/夹取的 picker 命中点 → 切片边界外不再误判命中(用户实测的外扩)。
|
||
// 点帘面/其它非切片物/边界外 → 返回 false → 单击即取消选中。
|
||
std::function<bool()> 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
|