diff --git a/src/render/interact/PickInteractorStyle.cpp b/src/render/interact/PickInteractorStyle.cpp index 2593f7f..648d6c3 100644 --- a/src/render/interact/PickInteractorStyle.cpp +++ b/src/render/interact/PickInteractorStyle.cpp @@ -4,10 +4,13 @@ #include #include +#include #include #include +#include #include #include +#include namespace geopro::render::interact { @@ -74,30 +77,55 @@ void PickInteractorStyle::OnLeftButtonDown() { // 单击命中 → 选中所在切片(onPick 内仅选中, 不动相机)。 if (onPick) onPick(world); } - // D39: 有选中三维体/切片时,按下开始拖动前把焦点设到其中心——焦点与位置同步平移同一 delta, - // 视向/距离不变(画面不跳),之后默认 TrackballCamera 即绕该中心旋转。无选中则绕默认焦点。 - // 只在"按下"时设(不是选中时),故切换点选切片不会跳。 - if (getRotateCenter && iren) { - Vec3 c; - if (getRotateCenter(c)) { - const int* p2 = iren->GetEventPosition(); - if (auto* ren = iren->FindPokedRenderer(p2[0], p2[1])) { - if (auto* cam = ren->GetActiveCamera()) { - double f[3], pp[3]; - cam->GetFocalPoint(f); - cam->GetPosition(pp); - cam->SetFocalPoint(c[0], c[1], c[2]); - cam->SetPosition(pp[0] + (c[0] - f[0]), pp[1] + (c[1] - f[1]), - pp[2] + (c[2] - f[2])); - ren->ResetCameraClippingRange(); - } - } - } - } - // 始终保留 TrackballCamera 默认拖动(旋转/平移)。 + // 不在按下时动相机(动相机=跳);绕选中物旋转在 Rotate() 内做(增量绕支点,不跳)。 Superclass::OnLeftButtonDown(); } +void PickInteractorStyle::Rotate() { + Vec3 c; + if (!this->CurrentRenderer || !getRotateCenter || !getRotateCenter(c)) { + Superclass::Rotate(); // 无选中物 → 默认绕焦点旋转 + return; + } + auto* rwi = this->Interactor; + auto* cam = this->CurrentRenderer->GetActiveCamera(); + if (!rwi || !cam) return; + const int dx = rwi->GetEventPosition()[0] - rwi->GetLastEventPosition()[0]; + const int dy = rwi->GetEventPosition()[1] - rwi->GetLastEventPosition()[1]; + const int* size = this->CurrentRenderer->GetRenderWindow()->GetSize(); + if (size[0] <= 0 || size[1] <= 0) return; + // 与 TrackballCamera 同口径的角度映射。 + const double azimuth = dx * (-20.0 / size[0]) * this->MotionFactor; + const double elevation = dy * (-20.0 / size[1]) * this->MotionFactor; + + double up[3], dop[3], right[3]; + cam->GetViewUp(up); + cam->GetDirectionOfProjection(dop); // 归一化的 (focal-pos) + vtkMath::Cross(dop, up, right); // 屏幕"右"轴 + vtkMath::Normalize(right); + + // 绕中心 c 的支点:T(c)·R(up,azimuth)·R(right,elevation)·T(-c),作用于 position/focal;up 只转不平移。 + vtkNew t; + t->Identity(); + t->Translate(c[0], c[1], c[2]); + t->RotateWXYZ(azimuth, up[0], up[1], up[2]); + t->RotateWXYZ(elevation, right[0], right[1], right[2]); + t->Translate(-c[0], -c[1], -c[2]); + + double pos[3], foc[3], npos[3], nfoc[3], nup[3]; + cam->GetPosition(pos); + cam->GetFocalPoint(foc); + t->TransformPoint(pos, npos); + t->TransformPoint(foc, nfoc); + t->TransformVector(up, nup); // 仅旋转部分作用于向量 + cam->SetPosition(npos); + cam->SetFocalPoint(nfoc); + cam->SetViewUp(nup); + cam->OrthogonalizeViewUp(); + if (this->AutoAdjustCameraClippingRange) this->CurrentRenderer->ResetCameraClippingRange(); + rwi->Render(); +} + void PickInteractorStyle::OnMouseWheelForward() { if (onWheelStep && onWheelStep(+1)) return; // 有选中切片 → 推进,消费滚轮 Superclass::OnMouseWheelForward(); // 否则默认缩放 diff --git a/src/render/interact/PickInteractorStyle.hpp b/src/render/interact/PickInteractorStyle.hpp index 8478b8b..294490a 100644 --- a/src/render/interact/PickInteractorStyle.hpp +++ b/src/render/interact/PickInteractorStyle.hpp @@ -34,6 +34,9 @@ public: void OnLeftButtonDown() override; void OnMouseWheelForward() override; void OnMouseWheelBackward() override; + // 绕选中物中心旋转(D39):有 getRotateCenter 时, 绕该中心增量旋转整个相机(位置+焦点+up), + // 中心在世界/屏幕都不动→不跳; 否则回退默认(绕焦点)。 + void Rotate() override; protected: PickInteractorStyle() = default;