geopro/src/render/interact/PickInteractorStyle.hpp

74 lines
4.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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