vtk平移、旋转,连接MFC问题总结(拓展VTK 到MFC上,思路说的很好)

最近在用vtk+MFC写一个程序,因为初学vtk,照着vtk的例子实现了一些功能,但是有几个问题深深的困惑了我,久久得不到解决。搜遍网络也没找到相应的例子。今天终于解决了,发出来大家一起学习。

1、vtk提供了交互样式(vtkInteractionStyle),但是封装的实在太死,而且基本都是响应键盘鼠标消息。假如为了便于操作要让模型绕X轴、Y轴或Z轴旋转,怎么办?我们想到了Actor的RotateX RotateY等方法,但是当我写好了这种相机不动,Actor旋转的代码后,悲剧发生了。

    vtk内置的交互样式响应鼠标用了vtkInteractorStyleTrackballCamera,是操作相机进而实现交互了,如果此时Actor绕X轴旋转了,你再移动相机观察前视图,会发现前视图也变化了。。这可不是我们想看见的。问题在于同一个窗口使用了2种原理不同的交互方式。办法只有统一起来,要么都操作相机,要么都操作Actor。那么怎么操作相机来实现绕X轴旋转呢?下面给出代样例代码:

vtkTransform* trans = vtkTransform::New();
trans->PostMultiply();   //一定用这种方式,这里很容易理解错
for (int i = 0;; i++)
{
reWin->Render();
double pos[3];
pos[0]= render->GetActiveCamera()->GetPosition()[0];
    pos[1] = render->GetActiveCamera()->GetPosition()[1];
pos[2] = render->GetActiveCamera()->GetPosition()[2];
double viewup[3];
viewup[0]= render->GetActiveCamera()->GetViewUp()[0];
viewup[1] = render->GetActiveCamera()->GetViewUp()[1];
viewup[2] = render->GetActiveCamera()->GetViewUp()[2];
trans->Identity();
trans->Translate(-cent[0], -cent[1], -cent[2]);  //cent是模型中心点
trans->RotateX(1);
trans->Translate(cent[0], cent[1], cent[2]);
double* viewupnew = trans->TransformDoubleVector(viewup);    //旋转相机向上向量
render->GetActiveCamera()->SetViewUp(viewupnew); 
double posnew[3];
trans->TransformPoint(pos, posnew);     //以模型中心点及X方向轴为轴,旋转相机位置

render->GetActiveCamera()->SetPosition(posnew);


render->ResetCamera();

}

trans->Delete();

这里有个问题特别注意:render->GetActiveCamera()->GetViewUp()返回一个指针,如果定义一个指针来接收这个返回值:double* vec=render->GetActiveCamera()->GetViewUp() ,double* pos=render->GetActiveCamera()->GetPosition(),运行程序老是出错。起初以为是返回了一段单独的内存,后来反复调试发现先后调用上述两个语句后,vec和pos指向同一个变量,悲剧!也许vtk返回的指针都是指向同一段内存(没有深究),总之最好别用指针来接vtk返回的指针了。有了上述代码的基本概念,绕任意轴旋转都没问题了。

2、平移问题:假如我想要在一个按钮上点一下,让模型平移一下,而不通过鼠标,怎么办?vtk可没有给出现成的接口。详细阅读了vtkInteractortrackballCamera的实现代码后,照着那个pan成员函数做了一个,有了这个样例,我们就可以随心所欲的写自己的平移了,代码如下:

void Pan(vtkRenderer* render,vtkRenderWindow* reWin)
{

double viewFocus[4], focalDepth, viewPoint[3];
double newPickPoint[4], oldPickPoint[4], motionVector[3];


// Calculate the focal depth since we'll be using it a lot


vtkCamera *camera = render->GetActiveCamera();
camera->GetFocalPoint(viewFocus);


render->SetWorldPoint(viewFocus[0], viewFocus[1], viewFocus[2],viewFocus[3]);
render->WorldToDisplay();
viewFocus[0] = render->GetDisplayPoint()[0];
viewFocus[1] = render->GetDisplayPoint()[1];
viewFocus[2] = render->GetDisplayPoint()[2];
viewFocus[3] = render->GetDisplayPoint()[3];
focalDepth = viewFocus[2];


double x[2];
x[0]= reWin->GetSize()[0];
x[1] = reWin->GetSize()[1];
double x1 = x[0] / 2, y1 = x[1] / 2;


render->SetDisplayPoint(x1, y1, focalDepth);
render->DisplayToWorld();
oldPickPoint[0] = render->GetWorldPoint()[0];
oldPickPoint[1] = render->GetWorldPoint()[1];
oldPickPoint[2] = render->GetWorldPoint()[2];
oldPickPoint[3] = render->GetWorldPoint()[3];
// Has to recalc old mouse point since the viewport has moved,
// so can't move it outside the loop
y1 = y1 + 0.5;


render->SetDisplayPoint(x1, y1, focalDepth);
render->DisplayToWorld();
newPickPoint[0] = render->GetWorldPoint()[0];
newPickPoint[1] = render->GetWorldPoint()[1];
newPickPoint[2] = render->GetWorldPoint()[2];
newPickPoint[3] = render->GetWorldPoint()[3];


// Camera motion is reversed


motionVector[0] = oldPickPoint[0] - newPickPoint[0];
motionVector[1] = oldPickPoint[1] - newPickPoint[1];
motionVector[2] = oldPickPoint[2] - newPickPoint[2];


camera->GetFocalPoint(viewFocus);
camera->GetPosition(viewPoint);
camera->SetFocalPoint(motionVector[0] + viewFocus[0],
motionVector[1] + viewFocus[1],
motionVector[2] + viewFocus[2]);


camera->SetPosition(motionVector[0] + viewPoint[0],
motionVector[1] + viewPoint[1],
motionVector[2] + viewPoint[2]);


reWin->Render();

}

上述代码核心在于设备坐标和世界坐标的相互转换,很容易理解,不多做解释。

3、vtk和MFC联合的问题

 vtk给的实例都是把vtkMFCWindow作为成员变量放在CView里边。这样做非常难受,,要控制个消息什么的也不好弄。解决办法是自己建立一个CVtkView,继承CView,对着vtkMfcWindow的实现代码,把代码拷贝到CVtkView相应消息处理程序中,然后就可以随心所欲的编写自己的CVtkView了,同时也继承了vtkMFC的所有功能,灵活多了。

猜你喜欢

转载自blog.csdn.net/eric_e/article/details/80008831
MFC