008_BestMPRBaseVtk 改变原有交互方式

161 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

头图

BestMPRBaseVtk 改变原有交互方式

今天我们来尝试修改一下默认的交互方式。其实vtk已经为我们提供了完善的交互类型,我们只需要根据我们的需要使用或重写某个接口即可。基本不需要重新造轮子。


BestMPRBaseVtk 改变原有交互方式1 vtk交互类2 vtkInteractorStyleImage 类2.1 重写部分函数3 调用☞ 源码

关键字: vtkInteractorStylevtkInteractorStyleTrackballCameravtkInteractorStyleImage交互Interactor

1 vtk交互类

vtk交互类型较多,如下图所示:

image-20211214142624288

2 vtkInteractorStyleImage 类

今天我们要使用的是vtkInteractorStyleImage这个类,vtkInteractorStyleImage是一个专门用于图像相机的从交互操作类。以下内容来之谷歌翻译,酌情观看。

vtkInteractorStyleImage允许用户交互操作(旋转、平移、缩放等)相机。vtkInteractorStyleImage专门设计用于处理使用vtkImageActor渲染的图像。有部分事件是冲他的父类vtkInteractorStyle重载,因此鼠标绑定是不同的。(绑定市相机的视图平面垂直于x-y平面),总而言之,2D图像交互的鼠标事件如下:

  • 鼠标左键触发窗口级事件
  • CTRL + 鼠标左键 围绕其视图平面正常旋转相机(谷歌翻译看不懂,直接看图)图1
  • SHIFT + 鼠标左键 移动相机(看图)图2
  • CTRL + SHIFT + 鼠标左键移动(位置缩放)相机(看图)图三
  • 鼠标中建平移相机,同SHIFT + 鼠标左键一样
  • 鼠标右键 移动相机,同CTRL + SHIFT + 鼠标左键一样
  • SHIFT + 鼠标右键 触发选择事件,这个还没有实验出来。

如果SetInteractionModeToImageSlicing()函数被调佣,那么有一些鼠标事件对应的操作被改变,如下:

  • CTRL + 鼠标左键 切过图像
  • SHIFT + 鼠标中键 切过图像
  • CTRL + 鼠标右键 旋转相机

如果SetInteractionModeToImage3D()函数被调用,那么有一些鼠标事件对应的操作被改变,如下:

  • SHIFT + 鼠标左键 旋转相机进行斜切
  • SHIFT + 鼠标中键 切过图像
  • CTRL + 鼠标右键 也会切入图像

在左右模式下,以下案件绑定有效(也就是快捷键):

  • R 重置窗口/级别
  • X 重置为失状视图显示
  • Y 重置为冠状视图显示
  • Z 重置为轴向视图像是

注意:* *渲染器的Actor是没有移动的,所有的操作都是移动的相机。

2.1 重写部分函数

我们需要重写部分里面的函数,今天先实现鼠标滚轮切换图层操作。先来看下效果,如下图所示。

目前代码还是很见得,后面应该会有调整。

 class myVtkInteractorStyleImage : public vtkInteractorStyleImage
 {
 public:
     static myVtkInteractorStyleImage* New();
     vtkTypeMacro(myVtkInteractorStyleImage, vtkInteractorStyleImage);
 ​
 protected:
     ImagePipeLine* ImageViewer;
     int Slice;
     int MinSlice;
     int MaxSlice;
 ​
 public:
     void SetImageViewer(ImagePipeLine* imageViewer)
     {
         this->ImageViewer = imageViewer;
         this->MinSlice = imageViewer->getSliceMin();
         this->MaxSlice = imageViewer->getSliceMax();
         this->Slice = (this->MinSlice + this->MaxSlice) / 2;
         this->ImageViewer->setSlice(this->Slice);
         this->ImageViewer->render();
     }
 ​
 protected:
     virtual void OnMouseWheelForward() override
     {
         this->MinSlice = ImageViewer->getSliceMin();
         this->MaxSlice = ImageViewer->getSliceMax();
 ​
         if (this->Slice < this->MaxSlice)
         {
             this->Slice += 1;
             this->ImageViewer->setSlice(this->Slice);
             this->ImageViewer->render();
         }
     }
 ​
     virtual void OnMouseWheelBackward() override
     {
 ​
         this->MinSlice = ImageViewer->getSliceMin();
         this->MaxSlice = ImageViewer->getSliceMax();
 ​
         if (this->Slice > this->MinSlice)
         {
             this->Slice -= 1;
             this->ImageViewer->setSlice(this->Slice);
             this->ImageViewer->render();
         }
     }
 };
 ​
 vtkStandardNewMacro(myVtkInteractorStyleImage);

3 调用

调用,我这里的调用,可能和比人的有点不一样,我是在设置渲染窗口的时候,替换了其默认的交互样式,如下图,代码注释你们要有选择的看,我也是个半吊子,理解的不一定是正确的。

image-20211214170413260

 void BPPMPRWidget::setRenderWindow(vtkGenericOpenGLRenderWindow *win)
 {
     if(this->RenderWindow == win)                                                       //判断当前窗口是不是传进来的,是就返回不是继续
     {
         return;
     }
 ​
     if(this->RenderWindowAdapter)                                                       // 这将释放所有与旧窗口相关的OpenGL资源
     {
         this->makeCurrent();                                                            //为窗口绘制OpenGL内容做准备,将上下文设置为当前,并为该上下文绑定framebuffer
         this->RenderWindowAdapter.reset(nullptr);                                       //删除并重置指针
     }
 ​
     this->RenderWindow = win;                                                           //赋新值
     if(this->RenderWindow)
     {
         this->RenderWindow->SetReadyForRendering(false);
 ​
         if(!this->RenderWindow->GetInteractor())                                        //如果没有提供交互器,我们默认将创建一个
         {
             vtkNew<QVTKInteractor> iren;                                                //创建一个默认交互器
             this->RenderWindow->SetInteractor(iren);                                    //为RenderWindow添加交互器
             iren->Initialize();                                                         //交互器初始化
 ​
             vtkNew<myVtkInteractorStyleImage> style;                                    //设置交互器默认样式
             style->SetImageViewer(m_PipeLine);
             iren->SetInteractorStyle(style);                                            //设置交互器
         }
         if(this->isValid())
         {
             this->makeCurrent();                                                        //为窗口绘制OpenG内容做准备,将上下文设置为当前,并为该上下文绑定framebuffer paintGL会自动调用。
             this->initializeGL();                                                       //初始化Openg
             this->updateSize();                                                         //更新窗口尺寸
         }
     }
 }

☞ 源码

源码链接:GitHub仓库自取

使用方法:☟☟☟

源码


博客签名2021