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

news2024/12/26 20:51:02

知识不是单独的,一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏: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_OBJECT

public:
    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()
{
    // 创建一个球体源和对应的 mapper
    vtkSmartPointer<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 和 QVTKOpenGLNativeWidget
    ui.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 s
    newX = 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.coloradmin.cn/o/783113.html

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

相关文章

第2章 SparkSQL 核心编程

第2章 SparkSQL 核心编程 2.1 新的起点2.2 DataFrame2.2.1 创建 DataFrame2.2.2 SQL 语法2.2.3 DSL 语法2.2.4 RDD 转换为 DataFrame2.2.5 DataFrame 转换为 RDD 2.3 DataSet2.3.1 创建 DataSet2.3.2 RDD 转换为 DataSet2.3.3 DataSet 转换为 RDD 2.4 DataFrame 和 DataSet 转…

学习记录681@Gitlab升级实战

前言 我的Linux目前是centos8&#xff0c;目前使用的gitlab是从https://mirrors.tuna.tsinghua.edu.cn/ 下载下来的gitlab-ce-12.10.1-ce.0.el8.x86_64.rpm&#xff0c;然后安装的。 这里需要注意如果是centos8需要下载el8的gitlab&#xff0c;如果是centos7需要下载el7的git…

golang - 下载大文件,实时返回前端下载进度,实现下载进度条

示例&#xff1a; package mainimport ("fmt""io""net/http""os""path"//"github.com/kataras/iris""github.com/kataras/iris/v12""time" )func doSomething() {time.Sleep(time.Second * …

大数据学习04-Hbase分布式集群部署

系统环境&#xff1a;centos7 软件版本&#xff1a;jdk1.8、zookeeper3.4.8、hadoop2.8.5 一、下载 HBASE官网 cd /home/toolswget https://archive.apache.org/dist/hbase/2.2.4/hbase-2.2.4-bin.tar.gz二、解压 tar -zxvf hbase-2.2.4-bin.tar.gz -C /home/local/移动目…

【弹力设计篇】聊聊降级设计

我们知道在分布式系统中&#xff0c;故障是不可避免的&#xff0c;所以我们需要设计一个高可用的系统&#xff0c;对于接口层面除了幂等&重试机制&#xff0c;还需要保证接口高可用&#xff0c;因此 限流&排队&降级&熔断也需要考虑。本篇主要介绍下接口故障下降…

Qt 之 自定义json配置文件类,QJsonDocument应用

目录 一、前言 二、头文件代码 三、源文件代码 四、使用示例 五、使用效果 一、前言 Qt的配置类QSettings主要是键值结构的配置&#xff0c;若需要的配置项为树形结构&#xff0c;例如配置学校\学院\班级\学生这样&#xff0c;使用键值结构已经不满足我们的需求了&#xf…

【计算机视觉 | 图像分割】arxiv 计算机视觉关于图像分割的学术速递(7 月 21 日论文合集)

文章目录 一、分割|语义相关(14篇)1.1 CNOS: A Strong Baseline for CAD-based Novel Object Segmentation1.2 Spinal nerve segmentation method and dataset construction in endoscopic surgical scenarios1.3 WeakPolyp: You Only Look Bounding Box for Polyp Segmentatio…

【unity】模型裁剪shader(建筑生长动画)

【unity】模型裁剪shader&#xff08;建筑生长动画&#xff09; 思路 使用的核心方法是clip,当传入正值时渲染&#xff0c;传入负值时不渲染。定义一个裁剪向量&#xff0c;使用裁剪向量和模型点点乘&#xff0c;如果模型点和裁剪向量是同一个方向&#xff0c;点乘为正&#…

代码随想录算法训练营第58天|739 496

739 用stack来写 stack里面发index 不要放数值 重点在于 1.填写result数组不需要按顺序填写 根据index就可以 2.遍历的值比top小的话就放入stack 这样stack里面是一个递减数组 遍历的值只需和top比 如果比他大就pop 一直到把stack里面比新加入的值小的都pop完为止 这样stack里…

vue项目的vue.config.js在打包过程中,并不会处理api请求。

主要处理打包选项和静态资源文件 请求是axios处理的

nonebot2聊天机器人插件12:stable_diffusion_webui_api

nonebot2聊天机器人插件12&#xff1a;stable_diffusion_webui_api 1. 插件用途2. 代码实现3. 实际效果 该插件涉及知识点&#xff1a;定时器&#xff0c;调用bot的api发送消息 插件合集&#xff1a;nonebot2聊天机器人插件 该系列为用于QQ群聊天机器人的nonebot2相关插件&…

IPO向上,大模型向下:中国企服寻找新「出口」

2023年&#xff0c;资本市场给企服行业带来的动荡&#xff0c;无疑是一次洗牌机会。只有当SaaS企业深耕产业侧&#xff0c;才能找到实现标准化的解法&#xff0c;才能在一波又一波的浪潮下抓住机遇。 作者|思杭 编辑|皮爷 出品|产业家 2023上半年&#xff0c;企服行业在…

MySQL存储过程——系统变量

1.存储过程中的变量 1.1 查看系统变量 查看所有的系统变量 show variables;查看会话级别的系统变量 show session variables&#xff1b;查看会话和auto相关的变量 show session variables like auto%;查看全局的和auto相关变量 show global variables like auto%;查看某一…

js的几种排序

冒泡排序&#xff1a; function bubbleSort(arr) {var len arr.length;for (var i 0; i < len; i) {for (var j 0; j < len - 1 - i; j) {if (arr[j] > arr[j1]) { //相邻元素两两对比var temp arr[j1]; //元素交换arr[j1] arr[j];arr[j] temp;}}…

进程(process)与线程(thread)以及线程的三种实现方法

一、线程和进程区别 说起进程&#xff0c;就不得不说下程序。程序是指令和数据的集合&#xff0c;其本身没有任何运行的含义&#xff0c;是一个静态的概念。 而进程则是执行程序的一次执行过程&#xff0c;它是一个动态的概念。是系统资源分配的单位。 通常在一个进程中可以…

BGP对SR-MPLS的支持

目录 BGP的SID类型 BGP Prefix-SID BGP Anycast-SID BGP Peer-SID BGP SID的通告 通过Prefix-SID属性 通告Prefix-SID 通过BGP EPE 通告Peer-SID 为什么要使用BGP作为SR-MPLS的控制平面 IGP for SR-MPSL只可以在自治系统AS内分配SID&#xff0c;规划出AS域内的最优路径 …

第12章 STM32+BH1750光照传感器+OLED模块显示环境光照强度

今天给大家介绍一块嵌入式毕设中也经常用到的一款传感器——BH1750光照传感器&#xff0c;如下图。&#xff08;该传感器的购买链接和代码我已放在资料里&#xff0c;想要资料的同学&#xff0c;评论区留下邮箱即可&#xff09;相比光敏传感器&#xff0c;它可以直接输出环境光…

【Unity2D】设置一物体默认在其他物体之上不被遮挡

比如我想让机器人显示在箱子的前面。 点击箱子&#xff0c;将其层级设置在机器人的后面。 即修改箱子的Order in Layer 在机器人之后 物体默认的Order in Layer 都是0 &#xff0c;将箱子的Order in Layer修改为-1即可 这样将确保先绘制机器人&#xff0c;然后绘制箱子。这样…

ConstraintLayout(约束布局)替代LinearLayout权重,解决多View一行省略问题

1.看上面的设计图中圈红的地方&#xff1a;左边设计图是一张直播间消息流&#xff0c;其中标红的消息流意思是&#xff1a; 用户的等级标签&#xff08;一张图片&#xff09; 用户名字写死的文案send,要求这三个View写一行&#xff0c;但是当用户名字过长时会让用户名出现.....…

数据结构双向循环链表,增删改查基本操作

一、双向循环链表的描述 和单链表的循环类似&#xff0c;双向链表也可以有循环表&#xff0c;循环表的引进是为了弥补双向链表不能向前遍历的弊端。 在双向循环链表中&#xff0c;头结点的直接前驱为尾结点&#xff0c;而尾结点的直接后继为头结点。 二、双向循环链表的存储结…