最近一段时间一直在对一个开源科学数据可视化的软件进行学习, 起初是简单的插件开发, 随着进度的加深, 现在这个软件本身的一些功能已经不能满足导师的思维......说到这里必需得吐个槽了, 我是学GIS的, 为什么非得让我搞个科学数据可视化的软件来学习呢??? 伴着不解与迷惘, 我走过了一段并不光彩快乐的日子. 回过头一看, 进度还在那里, 怎一个无助了得......吐槽够了, 就得进入正题, 因为这个开源的名为VisIt的软件, 其面向的主要对象是诸多的科学数据, 最好是利用PC集群来进行可视化, 功能还是了得了, 源程序将进150万行, 只多不少. 工程采用CMake来管理, 从我的理解上来看的话, 觉得他代码的设计和系统架构是很好的, 一门扎到代码里头都大了, 但功夫不负有心人, 终于找到了关于交互的部分.

      也许是因为VisIT基于VTK的原因, 其中交互的部分大体上由vtkRenderWindowInteractor这个类来管理, 这样一来, 代码的封将效果就很好了, 如下边的代码所展示的效果:

View Code
 1 void vtkQtRenderWindowInteractor::mousePressEvent(QMouseEvent *me) {
2 if (!Enabled)
3 return;
4
5 int *size = qtRenWin->GetSize();
6 Size[0] = size[0];
7 Size[1] = size[1];
8
9 int ctrl = 0, shift = 0;
10 if (me->modifiers() & Qt::ControlModifier)
11 ctrl = 1;
12 if (me->modifiers() & Qt::ShiftModifier)
13 shift = 1;
14 // Set the alt and altshift flags.
15 alt = (me->modifiers() & Qt::AltModifier);

16 if(me->modifiers() & Qt::AltModifier &&
17 me->modifiers() & Qt::ShiftModifier)
18 {
19 altshift = true;
20 shift = 0;
21 alt = false;
22 }
23 else
24 altshift = false;
25
26 int xp = me->x();
27 int yp = Size[1]- me->y() -1;
28
29 SetEventInformation(xp, yp, ctrl, shift);
30 switch (me->button()) {
31 case Qt::LeftButton:
32 if(altshift)
33 InvokeEvent(vtkCommand::MiddleButtonPressEvent, NULL);
34 else if(alt)
35 InvokeEvent(vtkCommand::RightButtonPressEvent, NULL);
36 else
37 InvokeEvent(vtkCommand::LeftButtonPressEvent, NULL);
38 break;
39 case Qt::MidButton:
40 InvokeEvent(vtkCommand::MiddleButtonPressEvent, NULL);
41 break;
42 case Qt::RightButton:
43 InvokeEvent(vtkCommand::RightButtonPressEvent, NULL);
44 break;
45 default:
46 return;
47 }
48 }


这是其中一部分交互的功能, 响应的是在鼠标交互时按键弹起死的事件.

 

代码的部分就不再多说了, 现在对vtkRenderWindowInteractor这个类的作一下简要的说明:

   vtkRenderWindowInteractor用于获取渲染窗口上发生的鼠标,键盘,事件事件。该类提供了独立于平台的与渲染窗口进行交互的机制,包括picking  和帧速率控制。当vtkRenderWindowInteractor(事实上是他的一个子类)观察到平台的某个事件发生时,他就通过InvokeEvent()方法把该事件转换为VTK事件。该类作为某些具体平台的基类来控制鼠标/键盘/时间消息的传送,通知vtkInteractorObserver和它的子类。注册于该交互器的所有观察者对象vtkInteractorObservers  都会接受到该事件,然后都对该事件进行响应。

         实际上,vtkRenderWindowInteractor的工作方式是这样的:这个类会截取发生在与它关联的vtkRenderWindow(通过vtkRenderWindowInteractor的SetRenderWindow()方法加入的那个渲染窗口)上的事件,然后,vtkRenderWindowInteractor类会根据具体的设备以及操作系统实例化一个对象,比如说,Unix下是vtkXRenderWindowInteractor,而Windows下则是vtkWin32RenderWindowInteractor。当vtkRenderWindowInteractor::Start()方法被调用时,事件的截取功能就会被激活。最后,这些所截取的事件会被送往vtkRenderWindowInteractor::InteractorStyle这个实例进行处理。InteractorStyle是vtkRenderWindowInteractor类里面的一个保护的数据成员,是vtkInteractorObserver类型的指针,而vtkInteractorObserver的作用是监测交互器上所发生的事件,这样,由vtkRenderWindowInteractor所截取的消息就有了归宿。如果要在VTK里要增加新的交互方式的话,应该先从vtkInteractorStyle派生出一个子类,如:vtkInteractorStyleTrackball,vtkInteractorStyleUser,  vtkInteractorStyleJoystickActor, vtkInteractorStyleJoystickCamera,  vtkInteractorStyleUser等。交互允许用户自定义方式。

                                     

                              

 

      应用的流程: (1) 一个vtkRenderWindow对象rWin (2)一个vtkRenderWindowInteractor对象iRen (3)  一个vtkWidget对象widget

则:  iRen->setRenderWindow(rWin);

      widget->setInteractor(iRen);

      iRen负责事件转换(必须指定对哪个窗口的事件进行转换),然后把一个观察者widget 注册到iRen交互器上widget->setInteracotr(iRen),负责观察iRen发送过来的它所截获的渲染窗口上发生的事件, 当事件发生了执行相关的系统自定义操作.