在实际工作当中,为解决与QmitkAbstractMultiWidget窗口视图的鼠标交互,凭借着以往的经验,我第一时间想到使用VTK中的相机视角调整。以下为解决问题的过程,以及经验。
项目部分展示:
首先第一个需求,禁用掉MITK中默认的鼠标左键切换数据节点视角功能。这个功能我一开始使用Qt的事件过滤器将鼠标点击事件&移动事件进行过滤,发现在过滤之前,切换数据节点的操作已经执行。这个方法失败了。
但由于MITK的继承树中,继承了Qt的三大类也就是QWidget,所以我想到了既然不能在之前截获掉操作,那么在之后进行覆盖呢?所以我又想到了重写Qt鼠标事件。
当然,Qt的鼠标事件一样也是在切换数据节点之后才触发,但是,当相机视角进行切换时,再通过重写鼠标点击事件,移动事件,释放事件。就可以再次手动对相机视角进行调整,从而达到鼠标左键点击开始到移动结束,不断的覆盖原先的操作,达到禁用鼠标左键的切换视角操作。
void mouseMoveEvent(QMouseEvent* event) override
{
if (is_leftMousePress) //当鼠标左键按下时
{
vtkCamera *camera = this->GetRenderWindow("3d")->GetVtkRenderWindow()
->GetRenderers()->GetFirstRenderer()->GetActiveCamera(); //拿到相机camera->SetPosition(position); //重置相机位置
camera->SetFocalPoint(focalPoint);
camera->SetViewUp(viewUp);
}}
其中is_leftMousePress通过鼠标点击事件进行标记,表示鼠标左键点击。通过重写鼠标点击事件和鼠标释放事件对is_leftMousePress变量进行赋值,达到操控目的。position,focalPoint,viewUp三个变量为double类型的数组,数组元素个数为3。用于切换相机的位置,通过以上的操作就能达到禁用鼠标左键对数据节点视角进行切换的目的。
随后,第二个要求是禁用鼠标右键对数据节点的缩放,同时还要对附加对数据节点视角切换的功能,这个怎么做呢?
首先要禁用掉鼠标右键的缩放操作,就要设置VTK的交互属性,也就是继承VTK交互器vtkRenderWindowInteractor重写其中的鼠标右键点击事件virtual void RightButtonPressEvent() 。
然后在鼠标右键点击移动后,设置指定的交互窗口,达到禁用效果,如下所示:
vtkRenderWindow * renderWindow = this->GetRenderWindow("3d")->GetVtkRenderWindow();
CustomInteractor* renderWindowInteractor = CustomInteractor::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize(); //初始化交互器
renderWindowInteractor->Start(); //启动交互器
其中CustomInteractor类是我继承vtkRenderWindowInteractor后重写的类,由于鼠标右键的交互操作被禁用,所以只能人为计算并调用接口,对相机视角进行操作,达到数据节点的视角切换目的。
float deltaX = renderWindowInteractor->getStartPosition()[0] - static_cast<float>(pos.x());
float deltaY = static_cast<float>(pos.y()) - renderWindowInteractor->getStartPosition()[1];
vtkCamera* camera = this->GetRenderWindow("3d")->GetVtkRenderWindow()
->GetRenderers()->GetFirstRenderer()->GetActiveCamera();camera->Azimuth(static_cast<double>(deltaX) * CustomInteractor::getSensitivityX()); //水平旋转
camera->Elevation(static_cast<double>(deltaY) * CustomInteractor::getSensitivityY()); //垂直旋转
这里通过人为计算鼠标移动的位置和上一次鼠标所在位置,得到相对偏移位置,最后乘以旋转系数,调用VTK相机水平旋转和垂直旋转接口,达到切换数据节点视角的功能。到此,目的就已经达成大半了,最后经过测试,发现相机视角范围只能是-90-90度之间,也就是180度旋转。对用户的体验不够友好。
经过查找,发现是相机渲染时没有保持正确的朝向和视角,导致无法调整超过180度。最后添加camera->OrthogonalizeViewUp();函数解决问题。
float deltaX = renderWindowInteractor->getStartPosition()[0] - static_cast<float>(pos.x());
float deltaY = static_cast<float>(pos.y()) - renderWindowInteractor->getStartPosition()[1];
vtkCamera* camera = this->GetRenderWindow("3d")->GetVtkRenderWindow()
->GetRenderers()->GetFirstRenderer()->GetActiveCamera();camera->Azimuth(static_cast<double>(deltaX) * CustomInteractor::getSensitivityX()); //水平旋转
camera->Elevation(static_cast<double>(deltaY) * CustomInteractor::getSensitivityY()); //垂直旋转camera->OrthogonalizeViewUp();
最后跑流程的时候,发现鼠标在2D窗口视图也会影像3D窗口的交互,通过拿到3D窗口的大小,与鼠标当前坐标点进行计算,限制3D窗口的交互范围,至此问题全部解决。
vtkRenderWindow * renderWindow = this->GetRenderWindow("3d")->GetVtkRenderWindow();
int *sizeWindow = renderWindow->GetSize(); //拿到窗口大小
int width = sizeWindow[0];
int height = sizeWindow[1];
由于工作性质,无法透露更多详细代码。
我是程序员玉无涯,国内的一位资深医疗软件开发工程师,我们下次再见。