【VTK】VTK 让小球动起来,在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK

知识不是单独的,一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏:Visual Studio。

文章目录

  • 版本环境
  • `A.ui`
  • `A.h`
  • `A.cpp`
  • Ref.

本文主要目的是在 Qt 界面中,显示出来使用 VTK 构建的小球,并让小球能够动起来。同时为了方便对比,又添加了一个静态的小球,用来作为参考,方便对比观察动态小球的运动。

先放出来最终效果,如下:

在这里插入图片描述

版本环境

  • Win 11
  • Visual Studio 2022
  • Qt 6.2.8_msvs2019_64
  • VTK 9.2.6
  • 工程名字:A

工程目标为:假定已经拥有了 x,y,z 坐标,实现当坐标值更改时,就更新 VTK 的小球位置。

工程的实现为:

设定了三个函数:

  1. void initVTK(); 用来初始化 VTK 小球对象
  2. void updateSpherePosition(double x, double y, double z); 更新小球位置
  3. void checkPositionChange(); 检测位置是否变化,位置变了就更新,否则不更新

void initVTK(); 函数中,主要包含:

  • // 创建一个球体源和对应的 mapper
  • // 创建一个 actor 来表示小球
  • // 创建一个 actor 来表示参照物
  • // 创建一个渲染器和窗口来显示小球和参照物
  • // 将小球和参照物添加到渲染器中
  • // 关联 vtkGenericOpenGLRenderWindow 和 QVTKOpenGLNativeWidget

void updateSpherePosition(double x, double y, double z); 函数中,主要包含:

  • // 使用 vtkActorSetPosition 方法更新位置
  • // 重新渲染

在 VTK 中,renderWindow->Render(); 是用来执行渲染过程的命令。每当场景的某个部分需要重新绘制时,例如因为数据或视图的变化,就需要调用这个方法。在本工程的情况中,每当小球的位置发生改变时,都需要重新渲染窗口来更新小球的显示位置。


void checkPositionChange(); 函数中,主要包含:

  • // 定义位置变量
  • // TODO: 从你的数据源获取新的 x, y, z 坐标值,并存储在 newX, newY, newZ 中
  • // 这里使用了一个 QElapsedTimer 类的 elapsedTimer 变量来记录程序运行时间
  • // 判断位置是否变化,如果变化就调用 updateSpherePosition(double x, double y, double z); 函数更新小球位置

最后,工程的关键,也就是触发的方式,采用的是计时器触发。计时器 timer 每过 50ms,就触发一次 checkPositionChange(); 函数,然后间接调用位置更新函数 updateSpherePosition(double x, double y, double z); 来实现小球位置的更新。


关于工程的配置和具体的代码如下:

A.ui

ui 界面配置如下,一个 Widget 配置成 QVTKOpenGLNativeWidget

不知道如和配置可以参考我的这个配置文章:【Visual Studio】在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK。

在这里插入图片描述

A.h

// A.h
#pragma once#include <QtWidgets/QMainWindow>
#include "ui_A.h"#include <vtkActor.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QVTKOpenGLNativeWidget.h>#include <qtimer.h>
#include <QElapsedTimer>class A : public QMainWindow
{Q_OBJECTpublic:A(QWidget* parent = nullptr);~A();// 将该函数添加为 public,以便在需要时更新小球位置void updateSpherePosition(double x, double y, double z);private slots:void checkPositionChange();  // 添加一个新的槽函数,用于检查坐标变化private:Ui::AClass ui;void initVTK();     // 将创建小球的过程抽象为一个单独的函数vtkSmartPointer<vtkActor> sphereActor;vtkSmartPointer<vtkActor> referenceActor;vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow;QTimer* timer;QElapsedTimer elapsedTimer;     // 定义一个变量来跟踪经过的时间,并使用这个时间来计算圆形路径上的点的坐标。double lastX, lastY, lastZ;
};

A.cpp

// A.cpp
#include "A.h"#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderer.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkRenderWindowInteractor.h>A::A(QWidget* parent): QMainWindow(parent),lastX(0), lastY(0), lastZ(0)
{ui.setupUi(this);// 配置 VTK 的初始设置initVTK();// 定时器,50ms 更新触发一次 checkPositionChange()timer = new QTimer(this);connect(timer, SIGNAL(timeout()), this, SLOT(checkPositionChange()));timer->start(50);// 开始记录经过的时间,并使用这个时间来计算圆形路径上的点的坐标elapsedTimer.start();
}A::~A()
{
}void A::initVTK()
{// 创建一个球体源和对应的 mappervtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();sphereMapper->SetInputConnection(sphereSource->GetOutputPort());// 创建一个 actor 来表示小球sphereActor = vtkSmartPointer<vtkActor>::New();sphereActor->SetMapper(sphereMapper);// 创建一个 actor 来表示参照物referenceActor = vtkSmartPointer<vtkActor>::New();referenceActor->SetMapper(sphereMapper);referenceActor->SetPosition(0, 0, 0);  // 参照物的位置固定在 (0, 0, 0)// 创建一个渲染器和窗口来显示小球和参照物vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();renderWindow->AddRenderer(renderer);// 将小球和参照物添加到渲染器中renderer->AddActor(sphereActor);renderer->AddActor(referenceActor);renderer->ResetCamera();// 关联 vtkGenericOpenGLRenderWindow 和 QVTKOpenGLNativeWidgetui.qvtkWidget->setRenderWindow(renderWindow);
}void A::updateSpherePosition(double x, double y, double z) {sphereActor->SetPosition(x, y, z);renderWindow->Render();
}void A::checkPositionChange() {double newX, newY, newZ;// TODO: 从你的数据源获取新的 x, y, z 坐标值,并存储在 newX, newY, newZ 中double t = elapsedTimer.elapsed() / 1000.0;  // convert ms to snewX = 1 * cos(t);newY = 1 * sin(t);newZ = 0;if (newX != lastX || newY != lastY || newZ != lastZ) {updateSpherePosition(newX, newY, newZ);}lastX = newX;lastY = newY;lastZ = newZ;
}

如果出现这个错误:有未经处理的异常:请求了严重的程序退出。
在这里插入图片描述

有可能是 VTK 配置的问题,回想下自己配置 VTK 时选择的时 Release 还是 Debug。如果还不知道,可以参考我的这个配置文章:【Visual Studio】在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK。

在这里插入图片描述


Ref.

  1. VTK实时变化刷新,动态点显示
  2. 【VTK】VTK+QT打开dicom图像并实时显示鼠标座标位置和像素值

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

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

相关文章

快手营销活动面试

衡量平台业务结果 请求&#xff0c;下发&#xff0c;曝光&#xff0c;点击&#xff0c;点击率&#xff0c;消耗系统QPS&#xff1f; 集群&#xff1a;高峰期8万&#xff0c;平峰期5万单机最大多少&#xff1f;性能瓶颈&#xff1f; 平峰期&#xff1a;300高峰期&#xff1a;500…

【C应用】测试CPU架构是大端还是小端模式

【C应用】测试CPU架构是大端还是小端模式 1、背景2、检测大小端1、背景 大端模式、小端模式是字节序里面的概念,即大端字节序,小端字节序。 关于字节序的理解,请参考文章: 【应用开发】关于字节序的理解 https://jn10010537.blog.csdn.net/article/details/131860480 所谓…

探秘ArrayList源码:Java动态数组的背后实现

探秘ArrayList源码&#xff1a;Java动态数组的背后实现 一、成员变量二、构造器1、默认构造器2、带初始容量参数构造器3、指定collection元素参数构造器 三、add()方法扩容机制四、场景分析1、对于ensureExplicitCapacity&#xff08;&#xff09;方法1.1 add 进第 1 个元素到 …

Inno Setup打包winform、wpf程序可判断VC++和.net环境

Inno Setup打包winform、wpf程序可判断VC和.net环境 1、下载Inno Setup2、新建打包文件、开始打包1、新建打包文件2、填写 应用名称、版本号、公司名称、公司官网3、选择安装路径 Custom是指定默认路径、Program Files folder是默认C盘根目录4、选择程序启动exe文件 以及Addfol…

【Python】基于Python和Qt的海康威视相机开发

文章目录 0 前期教程1 前言2 例程解析3 图像获取4 其他问题与解决办法5 使用到的python包 0 前期教程 【项目实践】海康威视工业相机SDK开发小白版入门教程&#xff08;VS2015OpenCV4.5.1&#xff09; 1 前言 此前写了一篇基于C开发海康威视相机的博客&#xff0c;貌似看的人…

防抖与节流

一、防抖&#xff08;Debounce&#xff09; 一种用于优化性能和减少不必要请求的技术。 防抖函数会延迟触发某个事件处理函数&#xff0c;并在一段时间内只执行一次。如果在延迟时间内多次触发了同一个事件&#xff0c;防抖函数会取消之前的延迟执行&#xff0c;并重新开始计…

springboot实现qq邮箱发送邮件或者验证码

首先我先去qq邮箱或者网易邮箱开通POP3/IMAP/SMTP/Exchange/CardDAV 服务 它在左上角的设置——账户——往下滑就可以找到——然后点击开通 开通后就会得到一串授权码。如下图 接下来直接编写代码 首先我没导入依赖 <!-- 这个是邮箱验证--> <dependency> <group…

Python 模块 ddt 数据驱动测试

简介 ddt 提供了一种方便的方法来实现数据驱动测试&#xff08;Data-Driven Testing&#xff09;。数据驱动测试是一种测试方法&#xff0c;通过将测试数据与测试逻辑分开&#xff0c;可以使用不同的数据集来运行相同的测试用例。这样可以提高测试的灵活性和可维护性&#xff0…

【Deviation】50 Matplotlib Visualizations, Python实现,源码可复现

详情请参考博客: Top 50 matplotlib Visualizations 因编译更新问题&#xff0c;本文将稍作更改&#xff0c;以便能够顺利运行。 本文介绍一下5中图示&#xff1a; Diverging Bars Diverging Texts Diverging Dot Plot Diverging Lollipop Chart with Markers Area Chart 1 Di…

【Spring Cloud】git 仓库新的配置是如何刷新到各个微服务的原理步骤

文章目录 1. 第一次启动时2. 后续直接在 git 修改配置时3. 参考资料 本文描述了在 git 仓库修改了配置之后&#xff0c;新的配置是如何刷新到各个微服务的步骤 前言&#xff1a; 1、假设现有有 3 个微服务&#xff0c;1 个是 配置中心&#xff0c;另外 2 个是普通微服务&#x…

【C++】通过栈和队列学会使用适配器和优先队列学会仿函数的使用

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

MAL文档

MAL文档 语法读取器宏特殊形式 内置符号内置函数算数运算谓词字符串解释器读取求值打印 原子序列操作字典元数据时间异常FFI 标准库符号函数宏 语法 空白符 所有的空白符会被忽略, 逗号也会被忽略; 以分号起始的内容直到行尾都被视为注释符号 符号中不允许含有空白符及[]{}()&…

pytorch安装GPU版本 (Cuda12.1)教程: Windows、Mac和Linux系统下GPU版PyTorch(CUDA 12.1)快速安装

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

vscode设置java -Xmx最大堆内存

如果在vscode中直接运行java程序&#xff0c;想要改下每次运行的最大堆内存&#xff0c;按照如下修改 一、vscode安装java插件 当然前提是vscode在应用管理中已经安装了java语言的插件&#xff0c;Debugger for Java,如下图所示 二、CommandShiftP打开配置搜索框 三、搜索…

前端实现输入框实时搜索,【vue+el-input】

一般搜索都是调后端的接口&#xff0c;绑searchValue字段&#xff08;也有可能叫其他的字段名&#xff09;&#xff0c;通过后端的接口进行实时搜索 如果由前端自己实现搜索过滤的话也简单 1、input事件 <el-inputv-model"queryParams.searchValue"input"k…

dpdpdp

这里写目录标题 139. 单词拆分322. 零钱兑换300. 最长递增子序列120. 三角形最小路径和64. 最小路径和63. 不同路径 II5. 最长回文子串&#xff08;回文dp&#xff09;⭐97. 交错字符串⭐&#xff08;抽象成路径问题&#xff09;221. 最大正方形⭐ 139. 单词拆分 class Soluti…

代码随想录day8 | KMP 28.实现strStr() 459.重复的子字符串

文章目录 一、实现strStr()二、重复的子字符串 一、实现strStr() 先学学KMP算法&#xff0c;代码随想录 28.实现strStr() class Solution { public:void getNext(int* next, const string& s) {int j -1;next[0] j;for(int i 1; i < s.size(); i) { // 注意i从1开始…

微信小程序的微信一键登录与验证码登录

验证码登录 <template><view class"wx-login"><view class"login-Box"><text class"title">欢迎登录</text><text class"subTitle">再就业男团系统</text><view class"login-Form…

java原型模式

在Java中实现原型模式&#xff0c;可以通过使用对象克隆&#xff08;Cloneable&#xff09;接口和重写 clone() 方法来完成。原型模式用于通过复制现有对象来创建新对象&#xff0c;避免了使用构造函数创建对象的开销。 下面是一个简单的示例&#xff1a; 首先&#xff0c;我…

【算法基础:搜索与图论】3.3 拓扑排序

文章目录 拓扑排序介绍如何构造拓扑排序&#xff08;⭐重要&#xff01;&#xff09; 例题&#xff1a;848. 有向图的拓扑序列BFS 写法构造拓扑排序 相关题目练习207. 课程表&#xff08;判断是否存在拓扑序列&#xff09;bfs 写法dfs 写法 210. 课程表 II&#xff08;找到一个…