fix(vtk): D39 改为自定义 Rotate 绕支点增量旋转(真不跳)
前法错: 设焦点=切片中心会把相机位置挪走(透视视差)→画面平移=跳; 诊断只验了视向、漏看位置。 正确: 按下完全不动相机(不跳); 重写 Rotate(): 有选中物时, 用 T(c)R(up)R(right)T(-c) 把 相机 position/focal/up 绕选中切片中心 c 增量旋转→c 在世界/屏幕都不动、场景绕它转、无跳。 无选中回退默认绕焦点。ctest 221/221
This commit is contained in:
parent
8d94247dd9
commit
5809b88a44
|
|
@ -4,10 +4,13 @@
|
||||||
|
|
||||||
#include <vtkCamera.h>
|
#include <vtkCamera.h>
|
||||||
#include <vtkCellPicker.h>
|
#include <vtkCellPicker.h>
|
||||||
|
#include <vtkMath.h>
|
||||||
#include <vtkNew.h>
|
#include <vtkNew.h>
|
||||||
#include <vtkObjectFactory.h>
|
#include <vtkObjectFactory.h>
|
||||||
|
#include <vtkRenderWindow.h>
|
||||||
#include <vtkRenderWindowInteractor.h>
|
#include <vtkRenderWindowInteractor.h>
|
||||||
#include <vtkRenderer.h>
|
#include <vtkRenderer.h>
|
||||||
|
#include <vtkTransform.h>
|
||||||
|
|
||||||
namespace geopro::render::interact {
|
namespace geopro::render::interact {
|
||||||
|
|
||||||
|
|
@ -74,30 +77,55 @@ void PickInteractorStyle::OnLeftButtonDown() {
|
||||||
// 单击命中 → 选中所在切片(onPick 内仅选中, 不动相机)。
|
// 单击命中 → 选中所在切片(onPick 内仅选中, 不动相机)。
|
||||||
if (onPick) onPick(world);
|
if (onPick) onPick(world);
|
||||||
}
|
}
|
||||||
// D39: 有选中三维体/切片时,按下开始拖动前把焦点设到其中心——焦点与位置同步平移同一 delta,
|
// 不在按下时动相机(动相机=跳);绕选中物旋转在 Rotate() 内做(增量绕支点,不跳)。
|
||||||
// 视向/距离不变(画面不跳),之后默认 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 默认拖动(旋转/平移)。
|
|
||||||
Superclass::OnLeftButtonDown();
|
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<vtkTransform> 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() {
|
void PickInteractorStyle::OnMouseWheelForward() {
|
||||||
if (onWheelStep && onWheelStep(+1)) return; // 有选中切片 → 推进,消费滚轮
|
if (onWheelStep && onWheelStep(+1)) return; // 有选中切片 → 推进,消费滚轮
|
||||||
Superclass::OnMouseWheelForward(); // 否则默认缩放
|
Superclass::OnMouseWheelForward(); // 否则默认缩放
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,9 @@ public:
|
||||||
void OnLeftButtonDown() override;
|
void OnLeftButtonDown() override;
|
||||||
void OnMouseWheelForward() override;
|
void OnMouseWheelForward() override;
|
||||||
void OnMouseWheelBackward() override;
|
void OnMouseWheelBackward() override;
|
||||||
|
// 绕选中物中心旋转(D39):有 getRotateCenter 时, 绕该中心增量旋转整个相机(位置+焦点+up),
|
||||||
|
// 中心在世界/屏幕都不动→不跳; 否则回退默认(绕焦点)。
|
||||||
|
void Rotate() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PickInteractorStyle() = default;
|
PickInteractorStyle() = default;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue