VTK+Qt+Cmake+VS的环境搭建

news2024/11/10 18:42:42

VTK+Qt+Cmake+VS的环境搭建

  • 一、准备工作
  • 二、VTK源码安装过程
  • 三、错误排查
  • 四、Cmake中引用VTK
  • 五、代码示例

本文的主要内容:简单介绍如何使用Cmake编译安装VTK源代码;如何配置VTK在Qt中的使用环境;如何以VS作为IDE在C++下使用Qt+VTK。
哪些人适合阅读本文:有一定Cmake、Qt和VS的基础,但是初次使用VTK的人。

一、准备工作

  1. 安装VS 2022
  2. 安装Cmake 3.28.3
  3. 安装Qt 5.15.2
  4. VTK 9.3.0 源代码,去官网下载

二、VTK源码安装过程

  1. 如果需要用Qt作为GUI,建议先把Qt装好,在Cmake Config的时候会自动识别出Qt的安装情况。
    在这里插入图片描述
  2. 解压VTK源代码,在同级目录下新建两个文件夹,其中vtk-build用于存放编译文件,安装完之后可以删除,避免占用空间。vtk-install文件夹用于存放安装之后的库文件。
    在这里插入图片描述
  3. 打开cmake-gui,源文件夹选择VTK-9.3.0,Build文件夹选择vtk-build,然后点Configure,选择对应的VS和X64。
  4. 在接下来出现的配置窗口里,有几个需要注意的地方,可以通过Search搜索栏直接找到需要修改的配置条目。
  • BUILD_SHARED_LIBS – 默认是勾选的,表示是动态编译。如果把勾选去掉表示VTK是静态编译。如果是动态编译,vtk-install/bin文件夹下会生成dll动态库,需要把这个文件夹添加到环境变量,应用程序运行时会自动从环境变量找到这个库;或者在写应用程序时复制需要用到的dll文件到exe文件同目录,否则运行会报错。静态库则不用。
    在这里插入图片描述
  • “静态编译”与“动态编译”的区别:静态编译就是在编译的时候把所有的模块都编译进可执行文件(exe)里去,当启动这个可执行文件时所有的模块都已加载进来。动态编译则是编译的时候需要的模块都没有编译进去,一般情况下可以把这些模块都编译成动态链接库DLL,启动程序(初始化)的时候这些模块不会被加载,运行的时候用到那个模块就调用哪个DLL文件。静态链接库编译相当于你带着一个工具包到处跑,遇到有需要的地方不需要周围的环境提供相应的工具,自己用自己工具包的工具就行了,所以当环境发生变化可以尽可能的无视;动态链接库编译相当于不带任何东西,走到哪是哪。这两者的区别显然就是前者重量增加了,即程序的体积会比后者的大。所以,究竟是用“静态编译”还是“动态编译”,关键看自己的需要。对于VTK初学者而言,所涉及到的工程可能都比较小,建议用“静态编译”,也方便把VTK程序移植到其他没有安装VTK的计算机上运行。本书的VTK类库是采用静态编译。-- 引用自CSDN博客
  • CMAKE_INSTALL_PREFIX – 这个选项表示VTK的安装路径,默认的路径是:C:/Program Files/VTK。将这个路径改成刚刚新建的vtk-install路径,安装完之后会在这个路径生成库文件。
    在这里插入图片描述
  1. 改完上述配置之后,再点一下Configure,然后Generate,然后OpenProject将在VS中打开工程。
  2. 将Debug改为Release,在ALL BUILD右键->生成,等待编译完成。
  3. 完成之后在INSTALL右键->生成,完成之后会把需要的库文件复制到vtk-install文件夹。
    在这里插入图片描述
    如果配置的是动态库,则bin文件夹下会有dll文件,如果是静态库则没有。
    至此,安装完成。如果想节约硬盘空间,可以将VTK9.3.0和vtk-build删除,只保留安装后的库文件vtk-install就可以了。

三、错误排查

  1. 使用VTK-9.3.0在VS2019里面编译会报错:
    vtkCommonCore-9.3d.lib(vtkSMPToolsAPI.obj) : error LNK2019: unresolved external symbol “public: bool __cdecl vtk::detail::smp::vtkSMPToolsImpl<1>::IsParallelScope(void)” (?IsParallelScope@?$vtkSMPToolsImpl@$00@smp@detail@vtk@@QEAA_NXZ) referenced in function “public: bool __cdecl vtk::detail::smp::vtkSMPToolsAPI::IsParallelScope(void)” (?IsParallelScope@vtkSMPToolsAPI@smp@detail@vtk@@QEAA_NXZ)

这个时候将下面这个选项勾选去掉重新编译安装一遍就可以了:
在这里插入图片描述

  1. 在结合Qt使用时会出现QVTKOpenGLNativeWidget.h找不到
    这两个选项要改成yes:
    在这里插入图片描述

四、Cmake中引用VTK

  1. 上面已经说了,如果是动态编译,则要把vtk-install/bin这个文件夹添加到环境变量。如果是静态编译则不用。
  2. 然后在应用程序的CmakeLists.txt里面加入:
set(VTK_DIR "D:/Software/VTK-install/lib/cmake/vtk-9.3")
FIND_PACKAGE(VTK REQUIRED)
target_link_libraries(${PROJECT_NAME} ${VTK_LIBRARIES})
# vtk_module_autoinit is needed
vtk_module_autoinit(TARGETS ${PROJECT_NAME} MODULES ${VTK_LIBRARIES})
  1. 如果在CmakeLists.txt里面没有设置VTK_DIR,在通过Cmake配置应用程序时就会出现VTK_DIR NOT FOUND,将vtk-install/lib/cmake/vtk-9.3目录添加进去就可以了。
    在这里插入图片描述

五、代码示例

接下来写一个最简单的VTK+Qt+Cmake+VS的工程示例。
工程的目录如下,build里面是编译输出的文件。
在这里插入图片描述
src文件夹里只有三个文件:
在这里插入图片描述
CMakeLists.txt

# 设置cmake版本号
cmake_minimum_required(VERSION 3.10)

# 设置moc rcc uic
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

# 设置工程名称
project(VTKTest)

# 使用VTK
set(VTK_DIR "D:/Software/VTK/vtk-install/lib/cmake/vtk-9.3")
FIND_PACKAGE(VTK REQUIRED)

# 使用QT
set(Qt5_DIR D:/Software/Qt/Qt5.12.10/5.12.10/msvc2017_64/lib/cmake/Qt5/)
find_package(Qt5 COMPONENTS Widgets Core Gui Network OpenGL REQUIRED) # 查找Qt库文件

# 查找源码
include_directories("src/")
FILE(GLOB SRC_FILES "src/*.cpp")
FILE(GLOB HEAD_FILES "src/*.h")
source_group("src" FILES ${SRC_FILES} ${HEAD_FILES})

# 添加可执行文件
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES} )
	
# 设置工程包含当前目录
set(CMAKE_INCLUDE_CURRENT_DIR ON)

# 添加依赖项
target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::Core Qt5::Gui Qt5::Network Qt5::OpenGL ${VTK_LIBRARIES})

# vtk_module_autoinit is needed
vtk_module_autoinit(
TARGETS ${PROJECT_NAME}
MODULES ${VTK_LIBRARIES}
)

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

Widget.cpp

#include "widget.h"
#include <QHBoxLayout>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkCubeSource.h>
#include <vtkProperty.h>
#include <vtkNamedColors.h>

Widget::Widget(QWidget *parent) :
    QWidget(parent)
{
    this->setGeometry(640, 360, 640, 360);
    QHBoxLayout* layout = new QHBoxLayout(this);
    qVTKWidget = new QVTKOpenGLStereoWidget(this);
    layout->addWidget(qVTKWidget);

    vtkShow();
}

Widget::~Widget()
{
    
}

void Widget::vtkShow()
{
    // 创建一个球体源
    vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
    sphereSource->SetCenter(0, 0, 0);
    sphereSource->SetRadius(0.5);
    sphereSource->SetThetaResolution(20);
    sphereSource->SetPhiResolution(20);

    // 创建一个正方体源
    vtkSmartPointer<vtkCubeSource> cubeSource = vtkSmartPointer<vtkCubeSource>::New();
    cubeSource->SetCenter(1.5, 0, 0);
    cubeSource->SetXLength(1);
    cubeSource->SetYLength(1);
    cubeSource->SetZLength(1);

    // 创建一个多边形数据映射器
    vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    sphereMapper->SetInputConnection(sphereSource->GetOutputPort());

    vtkSmartPointer<vtkPolyDataMapper> cubeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    cubeMapper->SetInputConnection(cubeSource->GetOutputPort());

    vtkSmartPointer<vtkNamedColors> colors = vtkSmartPointer<vtkNamedColors>::New();
    // 创建一个演员
    vtkSmartPointer<vtkActor> sphereActor = vtkSmartPointer<vtkActor>::New();
    sphereActor->SetMapper(sphereMapper);
    sphereActor->GetProperty()->SetColor(colors->GetColor3d("red").GetData());

    vtkSmartPointer<vtkActor> cubeActor = vtkSmartPointer<vtkActor>::New();
    cubeActor->SetMapper(cubeMapper);
    cubeActor->GetProperty()->SetColor(colors->GetColor3d("green").GetData());

    // 创建一个渲染器
    vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(sphereActor);
    renderer->AddActor(cubeActor);
    renderer->ResetCamera();

    qVTKWidget->renderWindow()->AddRenderer(renderer);
    qVTKWidget->renderWindow()->Render();
}

Widget.h

#pragma once

#include <QWidget>
#include <QVTKOpenGLStereoWidget.h>

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    void vtkShow();

private:
    QVTKOpenGLStereoWidget* qVTKWidget;
};

运行之后输出的效果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2086824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

android studio .android和.gradle迁移到其他盘

操作 可以看到gradle和android占用不小 .android 将C盘的.android迁移到D盘 切换到.android下面的avd目录&#xff0c;修改ini文件 .gradle 将.gradle复制到D盘 在Android studio的文件夹下面新建一个文件夹&#xff0c;我这里命名androidcache。接着在Android studio的…

「bug」nvitop ERROR: Failed to initialize curses

nvitop 作为一个优秀个 Nvidia显卡查询库&#xff0c;简单易用且显示信息十分丰富&#xff0c;相比 Nvidia-smi 更方便&#xff0c;简直是每个 开发人员必备的库&#xff0c;安装也十分方便&#xff0c;直接采用 pip install nvitop 即可&#xff0c;调用的时候也是直接在 Term…

51单片机波特率的计算方法

通过51单片机的波特率&#xff0c;来计算定时器的初始值。 定时器的溢出率公式 &#xff1a; 1 / ov 1/f * 12 *&#xff08;256 - init) &#xff08;ov为溢出率&#xff0c;溢出频率&#xff1b; init 为初始值; f为时钟频率&#xff0c; 比如12M或者11.0592M等&#xff09…

自己开发完整项目一、登录注册功能-01

一、创建spingboot项目框架 1.首先创建一个空的项目作为父项目&#xff0c;之后的所有都在此基础上创建模块进行开发。 2.创建负责登录注册功能模块 二、启动项目 1.出现如下错误&#xff0c;代表着端口号被占用&#xff0c;这个时候&#xff0c;我们可以进行端口号的修改。 …

如何从笔记本电脑或台式电脑恢复丢失的照片和视频

意外删除或丢失笔记本电脑或 PC 上的照片和视频是一个常见问题。不用担心&#xff0c;在此博客中&#xff0c;我们解释了从笔记本电脑或 PC 恢复丢失的照片和视频的各种方法。专业的数据恢复软件&#xff0c;例如奇客 数据恢复工具&#xff0c;可以帮助用户找回丢失的文件。 提…

微信小程序uni :class不支持xxx语法

问题代码&#xff1a; <view class"cellTop"><view>{{list.payTime}}</view><view :class"payStatusClass${list.payStatus}">{{payStatusDe[list.payStatus]}}</view></view> .payStatusClass1{color: rgb(246, 122,…

传输层协议-UDP数据报

UDP协议的特点 面向数据报&#xff0c;无连接&#xff0c;不可靠&#xff0c;全双工 面向数据报&#xff1a;是指该协议在传输数据的时候使用的是数据报&#xff1b; 无连接&#xff1a;指的是发送数据不需要两个进程连接在一起&#xff0c;类似生活中我们发送短信&#xff0…

代码随想录跟练第九天——LeetCode 232.用栈实现队列、225. 用队列实现栈、20. 有效的括号、1047. 删除字符串中的所有相邻重复项

拔了智齿后&#xff0c;好久没有总结了&#xff0c;先补一点 232.用栈实现队列 力扣题目链接(opens new window) 使用栈实现队列的下列操作&#xff1a; push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- …

解锁App推广新姿势,Xinstall带你玩转投放查看

在移动互联网时代&#xff0c;App推广和运营成为了各大企业和开发者关注的焦点。然而&#xff0c;在这个过程中&#xff0c;推广者常常面临一些痛点&#xff0c;比如无法实时查看投放效果、数据不透明、难以精准定位目标用户等。这些问题不仅影响了推广效果&#xff0c;还可能导…

这些网络设备知名厂商你都不知道?白干这行了

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 你们好啊&#xff0c;我的网工朋友。 信息技术的快速发展&#xff0c;网络行业已经成为推动全球经济和社会进步的重要力量之一。无论是企业还是个…

CI/CD实践(五)Jenkins Docker 自动化构建部署Node服务

微服务CI/CD实践系列&#xff1a; 微服务CI/CD实践&#xff08;一&#xff09;环境准备及虚拟机创建 微服务CI/CD实践&#xff08;二&#xff09;服务器先决准备 微服务CI/CD实践&#xff08;三&#xff09;gitlab部署及nexus3部署 微服务CI/CD实践&#xff08;四&#xff09…

Linux驱动学习之input子系统

简介 input 子系统就是管理输入的子系统&#xff0c;和pinctrl、gpio 子系统一样&#xff0c;都是 Linux 内核针对某一类设备而创建的框架。按键、鼠标、键盘、触摸屏等都属于输入设备&#xff0c;linux内核为此专门做了一个叫做input子系统的框架来处理输入事件。输入设备本…

day44——面向对象特征

一、封装 1.1 面向对象的三大特质 封装、继承、多态&#xff0c;如果问有四大特征&#xff0c;可以外加一个抽象 封装&#xff1a;将实现同一事物的所有的属性&#xff08;成员变量&#xff09;和行为&#xff08;成员函数&#xff09;封装到一个整体&#xff0c;我们称之为…

【Datawhale AI夏令营】从零上手CV竞赛Task2

文章目录 前言一、YOLO是什么&#xff1f;二、YOLO的历史三、性能指标四、 性能指标计算公式五、性能优化总结 前言 本文的Task2是对Task1的baseline代码进行优化的过程。 一、YOLO是什么&#xff1f; 首先简单介绍一下YOLO模型&#xff1a; 物体检测算法主要分为两类&#…

MSTP多实例生成树的配置

SW1配置&#xff1a; vlan batch 1 to 100 interface GigabitEthernet0/0/1 port link-type trunk port trunk allow-pass vlan 2 to 4094 interface GigabitEthernet0/0/2 port link-type trunk port trunk allow-pass vlan 2 to 4094 stp mode mstp //修改生成树的模式为…

【多线程】创建线程到底是多少种方法?

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 创建线程的两种方式总结(最官方)1.1 继承 Thread 类1.2 实现 Runnable 接口1.3 优先考虑使用第二种 —— …

三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附+源代码流程)

三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附源代码流程) 文章目录 三. Spring Boot 当中的“容器功能” 和 “配置绑定” 的详细剖析(附源代码流程)1. Spring Boot 是继续支持了 Spring 当中的注解的1.2 Spring 当中的 Component&#xff0c;Controller…

通过visual studio进行dump文件调试和分析

0、前言 很多时候程序crash之后需要分析原因。对于C/C程序&#xff0c;一般最常见的场景和方法就是根据dump文件进行分析。 1、分析的前提条件 进行dump文件分析&#xff0c;需要以下文件&#xff1a; 进程crash时产生的dump文件程序源码进程对应的程序exe文件编译exe文件时产…

QT Quick QML 添加海康威视SDK云台控制模块

文章目录 1. 配置海康威视 SDK 下载SDK文件移植工程文件添加 2. 函数调用流程接口参考代码 3. 代码后端核心代码前端核心代码 GitHub 源码: QmlLearningPro &#xff0c;选择子工程 HkwsDemo.pro &#xff08;暂未上传&#xff09; QML 其它文章请点击这里: QT QUICK …

Monibuca实战:如何用Go语言打造高效的直播后端

简介 Monibuca&#xff08;简称&#xff1a;m7s&#xff09; 是一个开源的实时流媒体服务器开发框架&#xff0c;使用 Go 语言编写。 它的设计目标是提供一个高性能、可扩展、易于定制的实时流媒体服务器解决方案。 Monibuca 的核心理念是模块化&#xff0c;允许开发者根据需…