下面,本教程将介绍如何在MFC下打开vtk文件,最终的效果如图所示:
如果你看过一些三维重建相关的论文,那么一定对这个图像很熟悉。很多论文都会以这个图像作为例子讲解,好了,闲话少说,直接讲实现。
早期的vtk版本(比如vtk5.x.x),example里面自带MFC的三个例子(对话框,单文档,多文档),不知为何现在的新版本删除了,不过没有关系,重新实现一遍就行了,代码也不多。
首先,你需要保证你的vs2017能够创建MFC项目,如果不能,可以通过
visual studio installer安装,具体过程,请百度,这里不再赘述。
我们先来建立一个MFC应用程序,暂且命名为“vtkdlg”,后续将以这个名称产生的代码来讲解:
点击确认,然后选择“基于对话框”,点击“完成”:
VTK是使用C++编写的,要使用VTK需要包含VTK发布的头文件,我们直接在vtkdlgDlg.h文件中添加以下代码:
#include "vtkDataSetMapper.h"
#include "vtkDataSetReader.h"
#include "vtkActor.h"
#include "vtkMFCWindow.h"
#include "vtkRenderer.h"
#include "vtkProperty.h"
#include "vtkWin32OpenGLRenderWindow.h"
点击“生成”,哎呀,找不到头文件!还记得教程1里面有个vtk-prefix文件夹吗?里面放着有,点击“项目”–>属性–>VC++目录–>包含目录,示意图如下:
修改确认后,再点击“生成”,成功了!
接下来,开始撸代码,在vtkdlgDlg.h头文件的CvtkdlgDlg类中添加以下代码,具体作用等写完所有代码后一并分析:
public:CString input_path;vtkMFCWindow* pvtkMFCWindow;vtkActor* pvtkActor;vtkDataSetMapper* pvtkDataSetMapper;vtkDataSetReader* pvtkDataSetReader;vtkRenderer* pvtkRenderer;vtkRenderWindow* pvtkRenderWindow;POINT ptBorder;void execute_pipeline();
在vtkdlgDlg.cpp文件中,找到CvtkdlgDlg的构造函数,修改如下:
CvtkdlgDlg::CvtkdlgDlg(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_VTKDLG_DIALOG, pParent)
{m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);this->pvtkActor = vtkActor::New();this->pvtkDataSetMapper = vtkDataSetMapper::New();this->pvtkDataSetReader = nullptr;this->pvtkRenderer = vtkRenderer::New();this->pvtkMFCWindow = nullptr;this->ptBorder = CPoint(0, 0);
}
在vtkdlgDlg.cpp中添加execute_pipeline函数的实现:
void CvtkdlgDlg::execute_pipeline()
{if (this->pvtkDataSetReader){this->pvtkDataSetMapper->SetInputConnection(this->pvtkDataSetReader->GetOutputPort());this->pvtkActor->SetMapper(this->pvtkDataSetMapper);this->pvtkActor->GetProperty()->SetColor(0.0, 0.0, 1.0);this->pvtkRenderer->SetBackground(1.0, 1.0, 1.0);this->pvtkRenderer->AddActor(this->pvtkActor);}else{this->pvtkRenderer->SetBackground(1.0, 1.0, 1.0);}this->pvtkRenderer->ResetCamera();
}
在CvtkdlgDlg::OnInitDialog()函数中添加以下代码,这部分代码写在//TODO后,return TRUE之前:
// TODO: 在此添加额外的初始化代码this->pvtkMFCWindow = new vtkMFCWindow(this->GetDlgItem(IDC_STATIC));CRect cRectClient;this->pvtkMFCWindow->GetClientRect(&cRectClient);this->pvtkMFCWindow->GetRenderWindow()->AddRenderer(this->pvtkRenderer);execute_pipeline();
下面切换到“资源视图”,我们来编辑对话框,只需要两步,很简单。
(1)删除其余控件,只留下“确认”,把“确认”改成“打开”。
(2)添加一个Picture Control空间。
这一步的效果图如下:
双击“打开”按钮,修改为以下代码,并在文件开头添加包含头文件#include string:
void CvtkdlgDlg::OnBnClickedOk()
{// TODO: 在此添加控件通知处理程序代码//CDialogEx::OnOK();CString sz = _T("MyType Files (*.vtk)|*.vtk");CFileDialog dlg(true, _T(".*"), NULL, OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, sz, this);if (IDOK == dlg.DoModal()){this->input_path = dlg.GetPathName();UpdateData(false);this->pvtkRenderer->RemoveActor(this->pvtkActor);std::string str(CT2A(dlg.GetPathName()));if (!this->pvtkDataSetReader)this->pvtkDataSetReader = vtkDataSetReader::New();this->pvtkDataSetReader->SetFileName(str.c_str());execute_pipeline();if (this->pvtkMFCWindow)this->pvtkMFCWindow->RedrawWindow();}
}
然后在类向导里面重载虚函数PostNcDestory,添加OnDestory的消息处理
代码修改如下:
void CvtkdlgDlg::PostNcDestroy()
{// TODO: 在此添加专用代码和/或调用基类delete this;CDialogEx::PostNcDestroy();
}void CvtkdlgDlg::OnDestroy()
{CDialogEx::OnDestroy();// TODO: 在此处添加消息处理程序代码if (this->pvtkMFCWindow != nullptr)delete this->pvtkMFCWindow;this->pvtkRenderer->Delete();this->pvtkDataSetMapper->Delete();if (this->pvtkDataSetReader != nullptr)this->pvtkDataSetReader->Delete();this->pvtkDataSetReader = nullptr;this->pvtkActor->Delete();
}
主要代码已经写好了,再次点击“生成”。完了!有一大堆无法解析的外部符号。再次回到之前的vtk-prefix文件夹,里面有lib库。点击“项目”–>属性–>链接器–>输入–>附件依赖项,将所有的lib都添加,用通配符的写法就是*.lib:
依旧没有解决问题,其实这里需要编译64位的版本,如下修改即可:
好了,编译成功!我们来运行一下,失败了,没完没了吗!在这里还有最后一步,将vtk-prefix文件夹中的bin文件夹下的所有dll文件拷贝到编译工程下即可,另外还有一个中方法,拷贝到system路径下(这种方式会对所有的程序都生效),我使用的是拷贝到编译工程下:
再次运行,弹出了错误,这已经不是代码的问题了,是新版本的vtk代码还需要有一个环境初始化过程,在以前的版本(5.x.x)是没有这个问题的,在vtkdlgDlg.h文件中添加以下代码:
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2); // VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);
最后,你可能还会遇到依旧不能运行的情况,如果单步执行下去,定位到是这行代码出问题:
this->pvtkMFCWindow = new vtkMFCWindow(this->GetDlgItem(IDC_STATIC));
可以进行如下修改:
修改成“使用多字节字符集”。
再次运行,you got it!
怎么和说好的不一样,那是还没有打开文件,限于篇幅太长,讲在下一讲打开文件和分析代码。
更多VTK教程,请VX搜索CodeKit。