本文已参与「新人创作礼」活动,一起开启掘金创作之路。
BestMPRBaseVtk 改变原有交互方式
今天我们来尝试修改一下默认的交互方式。其实vtk已经为我们提供了完善的交互类型,我们只需要根据我们的需要使用或重写某个接口即可。基本不需要重新造轮子。
BestMPRBaseVtk 改变原有交互方式1 vtk交互类2 vtkInteractorStyleImage 类2.1 重写部分函数3 调用☞ 源码
关键字:
vtkInteractorStyle
、vtkInteractorStyleTrackballCamera
、vtkInteractorStyleImage
、交互
、Interactor
1 vtk交互类
vtk交互类型较多,如下图所示:
2 vtkInteractorStyleImage 类
今天我们要使用的是vtkInteractorStyleImage
这个类,vtkInteractorStyleImage
是一个专门用于图像相机的从交互操作类。以下内容来之谷歌翻译,酌情观看。
vtkInteractorStyleImage
允许用户交互操作(旋转、平移、缩放等)相机。vtkInteractorStyleImage
专门设计用于处理使用vtkImageActor
渲染的图像。有部分事件是冲他的父类vtkInteractorStyle
重载,因此鼠标绑定是不同的。(绑定市相机的视图平面垂直于x-y平面),总而言之,2D图像交互的鼠标事件如下:
- 鼠标左键触发窗口级事件
- CTRL + 鼠标左键 围绕其视图平面正常旋转相机(谷歌翻译看不懂,直接看图)
- SHIFT + 鼠标左键 移动相机(看图)
- 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 调用
调用,我这里的调用,可能和比人的有点不一样,我是在设置渲染窗口的时候,替换了其默认的交互样式,如下图,代码注释你们要有选择的看,我也是个半吊子,理解的不一定是正确的。
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仓库自取
使用方法:☟☟☟