vtk9.0.1

  1. cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
  2. project(cone)
  3. find_package(VTK COMPONENTS
  4. CommonCore
  5. FiltersSources
  6. InteractionStyle
  7. RenderingOpenGL2 QUIET)
  8. if (NOT VTK_FOUND)
  9. #找VTK的路径
  10. message("fatal Skipping cone: ${VTK_NOT_FOUND_MESSAGE}")
  11. return ()
  12. endif()
  13. message (STATUS "VTK_VERSION: ${VTK_VERSION}")
  14. # 添加所有代码
  15. add_executable(cone Cone.cxx )
  16. # 链接第三方库
  17. target_link_libraries(cone PRIVATE ${VTK_LIBRARIES})
  18. # VTK_LIBRARIES变量由VTK的CMake文件提供
  19. # vtk_module_autoinit is needed
  20. vtk_module_autoinit(
  21. TARGETS cone
  22. MODULES ${VTK_LIBRARIES}
  23. )

vtk5.10.1

HelloVtk

  1. 编写源代码:D:\VTK\Examples\Chap01\1.3_TestVTKInstall.cpp
  2. 编写CMake文件:D:\VTK\Examples\Chap01\CMakeLists.txt ```

    CMake的版本要求

    CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

    项目名

    PROJECT( Chap01 )

找到对应模块

FIND_PACKAGE( VTK REQUIRED )

载入文件

INCLUDE( ${VTK_USE_FILE} )

添加.cpp文件

ADD_EXECUTABLE( 1.3_TestVTKInstall 1.3_TestVTKInstall.cpp)

加入依赖库的lib

TARGET_LINK_LIBRARIES( 1.3_TestVTKInstall vtkRendering vtkCommon )

  1. 3. 然后在cmake-gui中设置以下内容
  2. 1. `Where to build the binaries``D:\VTK\Examples\Chap01\bin`
  3. 1. 编译环境:VS17x64
  4. 点击Advanced视图,会显示出来以下几项
  5. 1. `CMAKE_INSTALL_PREFIX`:默认路径为`C:\Program Files\XXX`XXXCMakeLists里的project指定)
  6. 1. `VTK_DIR` VTK编译目录
  7. 1. 准确地说,是VTKConfig.cmake文件所在的完整路径
  8. 1. 一般情况下,编译完VTK以后,用CMake配置VTK的工程时,VTK_DIR选项的值都会自动填充。如果CMake找不到,或者找不到的不是想要的VTK版本,可以自己换别的路径
  9. 关于DLL文件,可以在VS项目里配置
  10. 1. 方法一:Properties > Configuration Properties > Debugging > Environment 输入VTKdll路径,即`PATH=%PATH%;D:\VTK-5.10-bin\bin\Debug`
  11. 1. 方法二:右键项目 > Properties > Configuration Properties > Debugging > Working Directory > `D:\VTK-5.10-bin\bin\Debug`
  12. <a name="G5L1O"></a>
  13. #### CMAKE_MINIMUM_REQUIRED
  14. 指定构建工程时所需的CMake版本要求

CMAKE_MINIMUM_REQUIRED( VERSION major[.minorp[.patch[.tweak]]] [FATAL_ERROR] )

  1. 1. 第一个参数`VERSION`是必选参数,且为大写(CMake命令名不区分大小写,为了统一描述,尽量都使用大写)
  2. 1. 第二个参数为指定CMAKE的版本号
  3. 1. 第三个参数为可选参数,且为CMake内置关键字`FATAL_ERROR`,如果构建工程所用CMake版本没有达到要求,配置过程就会出现以下错误提示,并终止工程构建过程
  4. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1465826/1619580627343-5f0bd123-51b2-441c-a298-f7c5fce7e1e6.png#crop=0&crop=0&crop=1&crop=1&height=124&id=hYTt0&margin=%5Bobject%20Object%5D&name=image.png&originHeight=197&originWidth=443&originalType=binary&ratio=1&size=60138&status=done&style=none&width=278)
  5. <a name="PQDsg"></a>
  6. #### 工程名PROJECT
  7. 用该命名指定工程名称,可指定工程支持的语言,支持语言的参数为可选。默认是C\C++

PROJECT(工程名 [CXX][C][Java])

  1. 该命令还隐含两个CMake内置变量:
  2. 1. `<projectName>_BINARY_DIR``PROJECT_BINARY_DIR`,在此示例中,值为`D:\VTK\Examples\Chap01\bin`
  3. 1. `<projectName>_SOURCE_DIR``PROJECT_SOURCE_DIR`,在此示例中,值为`D:\VTK\Examples\Chap01\Chap01`
  4. 为了统一起见,以后直接用CMake的内置变量`PROJECT_BINARY_DIR``PROJECT_SOURCE_DIR`,这样即使改了工程名称,这两个变量的值也会相应变化
  5. 该命令第一个参数也隐含了一个CMake内置变量`PROJECT_NAME`,可以通过`${PROJECT_NAME}`来取变量的值。在这个例子中,`${PROJECT_NAME}`即为`Chap01`
  6. <a name="byBdy"></a>
  7. #### 找到对应模块FIND_PACKAGE
  8. FIND_PACKAGE用于搜索并加载外部工程,其隐含的变量为`<package>_FOUND`,用于标示是否搜索到所需的工程。

FIND_PACKAGE( [version] [EXACT] [QUIET] [[REQUIRED|COMPONENTS][components…]] [NO_POLICY_SCOPE] )

  1. 1. 参数`[REQUIRED]`表示所要搜索到的外部工程对本工程来说是必须的,如果没有搜索到,CMake会终止整个工程构建过程。
  2. VTK为例,`FIND_PACKAGE`命令搜索的就是VTK的配置文件VTKConfig.cmake。<br />在VTK自带的示例目录里的CMakeLists.txt中有以下的CMake脚本语句(VTK-5.10\Examples\Tutorial\Step1\Cxx\CMakeLists.txt

FIND_PACKAGE(VTK REQUIRED) IF(NOT VTK_USE_RENDERING) MESSAGE(FATAL_ERROR “Example ${PROJECT_NAME} requires VTK_USE_RENDERING”) ENDIF(NOT VTK_USE_RENDERING)

  1. 以上四行的作用与`FIND_PACKAGE( VTK REQUIRED )`实现的功能是一样的。
  2. <a name="jpQkK"></a>
  3. #### 载入文件或模块INCLUDE
  4. 指定载入一个文件或者模块

INCLUDE( [OPTIONAL] [RESULT_VARIABLE] [NO_POLICY_SCOPE] )

  1. <a name="ZsATQ"></a>
  2. ##### 如果指定的是模块,那么将在`CMAKE_MODULE_PATH`中搜索这个模块并载入
  3. 1. 变量`CMAKE_MODULE_PATH`指的是搜索CMake模块的目录
  4. 1. 安装完CMake以后,在CMake的安装目录下(默认是`C:\Program Files(x84)\CMake 2.8`)可以找到CMake已定义的模块,路径为`C:\Program Files(x86)\CMake 2.8\share\cmake-2.8\Modules`
  5. <a name="uJ7mL"></a>
  6. ##### `INCLUDE( ${VTK_USE_FILE} )`的意义
  7. 本例中指定的是VTK模块,在`C:\Program Files(x86)\CMake 2.8\share\cmake-2.8\Modules`下存在`FindVTK.cmake`文件,其中定义了变量`VTK_USE_FILE`(在VTK编译目录`D:\VTK\VTK-5.10-bin\VTKConfig.cmake`文件中也可以看到)

The location of the UseVTK.cmake file.

SET(VTK_USE_FILE “D:/VTK/VTK-5.10-bin/UseVTK.cmake”)

  1. 所以,`INCLUDE( ${VTK_USE_FILE} )`即等于`INCLUDE(D:/VTK/VTK-5.10-bin/UseVTK.cmake)`
  2. <a name="BBGHe"></a>
  3. #### 生成可执行文件ADD_EXECUTABLE

ADD_EXECUTABLE( [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN )

  1. 定义这个工程会生成一个文件名为`<name>`的可执行文件,相关的源文件通过source1source2、...、sourceN列出
  2. 如果有多个源文件,有两种方式

方式一:多个源文件之间用空格隔开

ADD_EXECUTABLE(projectname source1.cpp source2.cpp source3.cpp)

方式二:用变量

SET(projectname_src source1.cpp source2.cpp source3.cpp) ADD_EXECUTABLE(projectname ${projectname_src})

  1. <a name="1ba71144"></a>
  2. #### 链接依赖库的lib TARGET_LINK_LIBRARIES
  3. 指定生成可执行文件时需要链接哪些文件
  4. 1. 参数<target>的名称必须与`ADD_EXECUTABLE`中指定的`<name>`一致
  5. 1. 在写这些链接的函数库时不需要带".lib"后缀

TARGET_LINE_LIBRARIES( [item1 [item2 […]]] [[debug|optimized|general] ] … )

  1. `TARGET_LINK_LIBRARIES( 1.3_TestVTKInstall vtkRendering vtkCommon )`
  2. <a name="O9h3u"></a>
  3. ##### 为什么本例中要链接vtkRendering.lib文件
  4. 1. .cpp中使用了`vtkRenderWindow``vtkSmartPointer`这两个类
  5. 1. 查找这两个类的头文件所在路径,分别是`VTK-5.10-src\Rendering``VTK-5.10-src\Common`
  6. 1. VTK编译的目录中又能找到`vtkRendering.lib``vtkCommon.lib`这两个文件
  7. 1. 所以是否可以断定类`vtkRenderWindow``vtkSmartPointer`的接口就分别定义在这两个文件中呢?
  8. <a name="BuI1W"></a>
  9. ##### 可以直接使用VTK_LIBRARIES自定义变量
  10. VTKConfig.cmake文件中定义了一个变量VTK_LIBRARIES

SET(VTK_LIBRARIES “vtkCommon;vtkFiltering;vtkImageing;vtkGraphics;vtkGenericFiltering;vtkIO;vtkRendering;vtkVolumeRendering;vtkHybrid;vtkWidgets;vtkInfos;vtkGeovis;vtkViews;vtkCharts” )

  1. 所以,可以不需要一一列出所要的链接的函数库,可以直接引用变量值:`${VTK_LIBRARIES}`来代替`vtkRendering vtkCommon`
  2. <a name="uk1BT"></a>
  3. ## 用CMake管理Qt与VTK工程

cmake版本

cmake_minimun_required(VERSION 2.8)

工程的名字

project(CombineQtAndVtk)

找Qt、vtk相关包,而且是必须找到

find_package(VTK REQUIRED) find_package(Qt4 REQUIRED)

加入使用VTK、Qt的相关文件

include(${VTK_USE_FILE}) include(${QT_USE_FILE})

程序所有源文件

set(PROJECT_SRCS main.cpp ProjectMainWindow.cpp )

Qt的UI文件

set(PROJECT_UIS ProjectMainWindow.ui )

包含所有含有Q_OBJECT的头文件

set(PROJECT_MOC_HDRS ProjectMainWindow.h )

qt4_wrap_ui通过Qt的uic.exe生成UI文件对应的ui_xxx.h文件,并将生成的ui_xxx.h文件列表存储于变量Project_UIS_H中

qt4_wrap_ui(PROJECT_UIS_H ${PROJECT_UIS} )

qt_wrap_cpp通过Qt的moc.exe将包含Q_OBJECT的头文件生成对应的moc_xxx.cxx文件,并存储在变量PROJECT_MOC_HDRS中

qt4_wrap_cpp(PROJECT_MOC_SRCS ${PROJECT_MOC_HDRS} )

引用文件夹

生成的moc_xxx.cxx和ui_xxx.h等文件是存放在CMake的”Where build the binaries”里指定的目录里,所以必须将这些路径包含进来

include_directories(${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${VTK_DIR} )

加入源代码与头文件,编译成CombineQtAndVTK.exe

add_executable(CombineQtAndVTK ${PROJECT_SRCS} ${PROJECT_UIS_H} ${PROJECT_MOC_SRCS} )

依赖库

target_line_libraries(CombineQtAndVTK ${VTK_LIBRARIES} QVTK )

  1. <a name="ySKaO"></a>
  2. #### 找不到dll
  3. 运行VTK应用程序之后,有时会遇到类似的问题:找不到*.dll<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1465826/1619596271525-a33a7793-c6f6-4bd6-8782-37651655b74f.png#crop=0&crop=0&crop=1&crop=1&height=85&id=e8yTd&margin=%5Bobject%20Object%5D&name=image.png&originHeight=169&originWidth=440&originalType=binary&ratio=1&size=44222&status=done&style=none&width=220)
  4. <a name="ev1WZ"></a>
  5. ##### 方法一:将dll拷贝到exe同级目录下
  6. 缺点:繁琐
  7. <a name="NB3d8"></a>
  8. ##### 方法二:将dll拷贝到Windows系统目录下
  9. Windows系统目录:`C:\Windows\system32`或者`C:\Windows\system`<br />缺点:多版本不好管理
  10. <a name="Hn6vN"></a>
  11. ##### 方法三:CMake里加命令,构建工程时把系统的Path环境变量加载进来,使得在工程启动之前加载这些环境变量
  12. 1. CMakeLists.txt:在CMakeLists.txt文件的最后添加代码

—————————————————————————————————————————————————————————————————-

Windows平台下,构建程序运行时所需的目录

SET(PROJECT_RUNTIME_PATH “${VTK_LIBRARY_DIRS}/@VS_BUILD_TYPE@;${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/@VS_BUILD_TYPE@” ) IF(QT4_FOUND) SET(PROJECT_RUNTIME_PATH “${PROJECT_RUNTIME_PATH};${QT_LIBRARY_DIR}/../bin”) ENDIF()

INCLUDE(CreateWindowsBatchScript.cmake)

Windows平台下使用VS时,创建两个正确设置环境变量的批处理文件

分别是StartVS_Debug.bat和StartVS_Release.bat文件

IF(WIN32) SET(VSSOLUTION_FILE “${PROJECT_BINARY_DIR}/${PROJECT_NAME}.sln”) FOREACH(VS_BUILD_TYPE debug release) CreateWindowsBatchScript(“${CMAKE_SOURCE_DIR}/StartVS.bat.in” ${PROJECT_BINARY_DIR}/StartVS${VS_BUILD_TYPE}.bat ${VS_BUILD_TYPE}) ENDFOREACH() ENDIF(WIN32)

  1. 2. CreateWindowsBatchScript.cmake

FUNCTION(CreateWindowsBatchScript in out build_type) IF(VTK_DIR) SET(VTK_BIN_DIR “${VTK_DIR}/bin/${build_type}”) ELSE() SET(VTK_BIN_DIR) ENDIF()

SET(VS_BUILD_TYPE ${build_type}) CONFIGURE_FILE(${in} ${out} @ONLY)

substitute again

CONFIGURE_FILE(${out} ${out} @ONLY) ENDFUNCTION()

  1. 3. StartVS.bat.in

@set CL=/D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE @set LINK=/LARGEADDRESSAWARE

PATH=@PROJECT_RUNTIME_PATH@;%PATH% “@VS_SOLUTION_FILE@”

  1. 工程通过CMakeconfiguregenerate以后,即可生成StartVS_Debug.batStartVS_release.bat两个脚本文件。
  2. 1. 如果需要编译、运行Debug版本的工程,可双击StartVS_debug.bat文件打开对应的工程
  3. 1. Release版本也类似,一旦这种方式打开相应的工程,就不用担心出现“无法加载xxx.dll文件”的错误
  4. <a name="TcOeY"></a>
  5. ## 用QVTKWidget整合Qt和VTK
  6. 可以使用VTK提供的QVTKWidget类实现QtVTK的整合,该类继承自QWidget,所以可以把它当作QtWidget来使用,甚至可以在Qt Designer里像Qt的其他标准控件一样具有拖拽功能
  7. 除了QVTKWidget类之外,VTK还提供大量与Qt相关的类。著名的ParaView软件就是基于VTKQt编写的。
  8. <a name="8yaWq"></a>
  9. ##### 在Qt Designer里集成QVTKWidget控件
  10. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1465826/1619604089173-f1800605-8041-43b3-9c69-d2c6c5fca22f.png#crop=0&crop=0&crop=1&crop=1&height=272&id=ORWYs&margin=%5Bobject%20Object%5D&name=image.png&originHeight=543&originWidth=744&originalType=binary&ratio=1&size=283711&status=done&style=none&width=372)
  11. <a name="gabwx"></a>
  12. ##### 一个简单的VTK/QT程序
  13. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1465826/1619604228025-4f0001e7-991c-4a4d-895d-e324e78ef305.png#crop=0&crop=0&crop=1&crop=1&height=175&id=pyqXl&margin=%5Bobject%20Object%5D&name=image.png&originHeight=349&originWidth=310&originalType=binary&ratio=1&size=83829&status=done&style=none&width=155)
  14. 1. ProjectMainWindow.h
  15. ```cpp
  16. #ifndef Project_MainWindow_H
  17. #define Project_MainWindow_H
  18. #include <QMainWindow>
  19. #include "ui_ProjectMainWindow.h"
  20. #include <vtkSmartPointer.h>
  21. class vtkImageViewer2;
  22. class vtkRenderer;
  23. class vtkEventQtSlotConnect;
  24. class vtkObject;
  25. class vtkCommand;
  26. class ProjectMainWindow : public QMainWindow, public Ui::ProjectMainWindow
  27. {
  28. Q_OBJECT
  29. public:
  30. ProjectMainWindow();
  31. ~ProjectMainWindow();
  32. private slots:
  33. //响应打开图像文件的槽函数
  34. void onOpenSlot();
  35. //响应鼠标移动的消息,实时输出鼠标的当前位置
  36. void updateCoords(vtkObject* obj);
  37. private:
  38. vtkSmartPointer< vtkImageViewer2 > m_pImageViewer;
  39. vtkSmartPointer< vtkRenderer > m_pRenderder;
  40. vtkEventQtSlotConnect* m_Connections;
  41. };
  42. #endif
  1. ProjectMainWindow.cpp ```cpp

    include “ProjectMainWindow.h”

    include

    include

    include

    include

    include

    include

    include

    include

    include

    include

ProjectMainWindow::ProjectMainWindow() { setupUi(this);

  1. m_pImageViewer = vtkSmartPointer< vtkImageViewer2 >::New();
  2. m_pRenderder = vtkSmartPointer< vtkRenderer >::New();
  3. // 设置m_QVTKWidget的渲染器
  4. m_QVTKWidget->GetRenderWindow()->AddRenderer(m_pRenderder);
  5. //连接打开的信号与相应的槽
  6. connect( m_OpenAction, SIGNAL( triggered() ), this, SLOT( onOpenSlot() ) );
  7. m_Connections = vtkEventQtSlotConnect::New();
  8. m_Connections->Connect(m_QVTKWidget->GetRenderWindow()->GetInteractor(),
  9. vtkCommand::MouseMoveEvent,
  10. this,
  11. SLOT(updateCoords(vtkObject*)));

}

ProjectMainWindow::~ProjectMainWindow() { }

void ProjectMainWindow::onOpenSlot() { QString filter; filter = “JPEG image file (.jpg .jpeg)”;

  1. QDir dir;
  2. QString fileName = QFileDialog::getOpenFileName( this, QString(tr("打开图像")), dir.absolutePath() , filter );
  3. if ( fileName.isEmpty() == true ) return;
  4. // 支持带中文路径的读取
  5. QByteArray ba = fileName.toLocal8Bit();
  6. const char *fileName_str = ba.data();
  7. // 用vtkJPEGReader读取JPG图像
  8. vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New();
  9. reader->SetFileName(fileName_str);
  10. // 将reader的输出作为m_pImageViewer的输入,并设置m_pImageViewer与渲染器m_pRenderer的关联
  11. m_pImageViewer->SetInput(reader->GetOutput());
  12. m_pImageViewer->UpdateDisplayExtent();
  13. m_pImageViewer->SetRenderWindow(m_QVTKWidget->GetRenderWindow());
  14. m_pImageViewer->SetRenderer(m_pRenderder);
  15. m_pImageViewer->SetupInteractor(m_QVTKWidget->GetRenderWindow()->GetInteractor());
  16. m_pImageViewer->SetSliceOrientationToXY(); //默认就是这个方向的
  17. m_pImageViewer->GetImageActor()->InterpolateOff();
  18. m_pRenderder->ResetCamera();
  19. m_pRenderder->DrawOn();
  20. m_QVTKWidget->GetRenderWindow()->Render();

}

void ProjectMainWindow::updateCoords(vtkObject obj) { // 获取交互器 vtkRenderWindowInteractor iren = vtkRenderWindowInteractor::SafeDownCast(obj);

  1. // 获取鼠标的当前位置
  2. int event_pos[2];
  3. iren->GetEventPosition(event_pos);
  4. QString str;
  5. str.sprintf("x=%d : y=%d", event_pos[0], event_pos[1]);
  6. m_StatusBar->showMessage(str);

} ```

用vtkEventQtSlotConnect实现VTK事件与Qt槽的连接

vtkEventQtSlotConnect类可以实现VTK事件与Qt的槽函数的连接
VTK事件主要在vtkCommand.h文件里定义,包括鼠标单击、双击、移动等。

比如,可以通过响应VTK的事件来实现一个简单的功能:当移动鼠标时,在窗口上显示当前鼠标的像素坐标值,代码如下:
image.png
image.png