VTK教程3--------打开vtk文件

下面,本教程将介绍如何在MFC下打开vtk文件,最终的效果如图所示:
VTK教程3--------打开vtk文件_第1张图片
如果你看过一些三维重建相关的论文,那么一定对这个图像很熟悉。很多论文都会以这个图像作为例子讲解,好了,闲话少说,直接讲实现。
早期的vtk版本(比如vtk5.x.x),example里面自带MFC的三个例子(对话框,单文档,多文档),不知为何现在的新版本删除了,不过没有关系,重新实现一遍就行了,代码也不多。
首先,你需要保证你的vs2017能够创建MFC项目,如果不能,可以通过
visual studio installer安装,具体过程,请百度,这里不再赘述。
我们先来建立一个MFC应用程序,暂且命名为“vtkdlg”,后续将以这个名称产生的代码来讲解:
VTK教程3--------打开vtk文件_第2张图片
点击确认,然后选择“基于对话框”,点击“完成”:
VTK教程3--------打开vtk文件_第3张图片
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++目录–>包含目录,示意图如下:
VTK教程3--------打开vtk文件_第4张图片
修改确认后,再点击“生成”,成功了!
接下来,开始撸代码,在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空间。
这一步的效果图如下:
VTK教程3--------打开vtk文件_第5张图片
双击“打开”按钮,修改为以下代码,并在文件开头添加包含头文件#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的消息处理
VTK教程3--------打开vtk文件_第6张图片
VTK教程3--------打开vtk文件_第7张图片
代码修改如下:

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:
VTK教程3--------打开vtk文件_第8张图片
依旧没有解决问题,其实这里需要编译64位的版本,如下修改即可:
VTK教程3--------打开vtk文件_第9张图片
好了,编译成功!我们来运行一下,失败了,没完没了吗!在这里还有最后一步,将vtk-prefix文件夹中的bin文件夹下的所有dll文件拷贝到编译工程下即可,另外还有一个中方法,拷贝到system路径下(这种方式会对所有的程序都生效),我使用的是拷贝到编译工程下:
VTK教程3--------打开vtk文件_第10张图片
再次运行,弹出了错误,这已经不是代码的问题了,是新版本的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));

可以进行如下修改:
VTK教程3--------打开vtk文件_第11张图片
修改成“使用多字节字符集”。
再次运行,you got it!
VTK教程3--------打开vtk文件_第12张图片
怎么和说好的不一样,那是还没有打开文件,限于篇幅太长,讲在下一讲打开文件和分析代码。
更多VTK教程,请VX搜索CodeKit。

你可能感兴趣的:(VTK教程)