【VTK】基于读取出来的 STL 模型,当用户点击鼠标左键时,程序将获取点击位置的点,显示其坐标,并设置它为模型的旋转原点

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

文章目录

  • `class PointPickedSignal : public QObject`
  • `class MouseInteractorCommand : public vtkCommand`
  • `void A::on_pushButtonSelected_clicked()`
  • `void A::onPointPicked(double* pos)`
  • `A.h`
  • `A.cpp`
  • Ref.

基于读取出来的 STL 模型,实现当用户点击鼠标左键时,程序将获取点击位置的点,显示其坐标,并设置它为模型的旋转原点。

详细流程为:点击 Select 按钮,鼠标具备选择的功能。当按下 Select Done 鼠标删除掉此功能。

在这里插入图片描述


主要是通过两个类和一个函数来实现的:

  • class PointPickedSignal : public QObject
  • class MouseInteractorCommand : public vtkCommand
  • void A::on_pushButtonSelected_clicked()
  • void A::onPointPicked(double* pos)

下边依次分析。

class PointPickedSignal : public QObject

class PointPickedSignal : public QObject
{Q_OBJECT
public:PointPickedSignal(QObject* parent = nullptr) : QObject(parent) {}signals:void pointPicked(double* pos);
};

这个类继承自 QObject 类,用于实现一个名为 pointPicked 的 Qt 信号,当一个点被选中时发出该信号。这个信号将被用于通知其他对象选中的点的坐标。

class MouseInteractorCommand : public vtkCommand

class MouseInteractorCommand : public vtkCommand
{
public:vtkTypeMacro(MouseInteractorCommand, vtkCommand);static MouseInteractorCommand* New(){return new MouseInteractorCommand;}virtual void Execute(vtkObject* caller, unsigned long eventId, void* vtkNotUsed(callData)){vtkRenderWindowInteractor* interactor = vtkRenderWindowInteractor::SafeDownCast(caller);int* clickPos = interactor->GetEventPosition();vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();picker->SetTolerance(0.0005);if (picker->Pick(clickPos[0], clickPos[1], 0, interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer())){double* pos = picker->GetPickPosition();memcpy(pickedPoint, pos, sizeof(double) * 3);emit signal->pointPicked(pickedPoint);}}double pickedPoint[3];PointPickedSignal* signal; // this will emit the pointPicked signal when a point is picked
};

这个类继承自 vtkCommand 类,其功能是监听鼠标左键的点击事件。当用户点击鼠标左键时,会触发 Execute 方法。在这个方法中,代码首先从事件的发起者中获取交互器,并从交互器中获取点击的位置。然后,它创建一个 vtkCellPicker 对象并尝试拾取点击位置的点。如果成功拾取了一个点,它将获取该点的坐标,并使用 memcpy 将这些坐标复制到 pickedPoint 数组中。最后,它发出 pointPicked 信号,将选中的点的坐标作为参数。

void A::on_pushButtonSelected_clicked()

void A::on_pushButtonSelected_clicked() {ui.textBrowser->insertPlainText("Button Clicked");PointPickedSignal* signal = new PointPickedSignal(this);vtkSmartPointer<MouseInteractorCommand> command = vtkSmartPointer<MouseInteractorCommand>::New();command->signal = signal;ui.qvtkWidget->interactor()->AddObserver(vtkCommand::LeftButtonPressEvent, command);QEventLoop loop;connect(signal, &PointPickedSignal::pointPicked, this, &A::onPointPicked);connect(signal, &PointPickedSignal::pointPicked, &loop, &QEventLoop::quit);loop.exec();onPointPicked(command->pickedPoint);
}

这个方法首先创建一个 PointPickedSignal 对象和一个 MouseInteractorCommand 对象。然后,它将 PointPickedSignal 对象赋值给 MouseInteractorCommand 对象的 signal 成员,然后将这个 MouseInteractorCommand 对象添加为 QVTKWidget 对象的交互器的观察者,这样当交互器收到左键按下事件时,就会执行 MouseInteractorCommand 对象的 Execute 方法。

然后,这个方法创建一个 QEventLoop 对象并开始执行事件循环。在事件循环中,当 pointPicked 信号被发出时,它将调用 A::onPointPicked() 方法,并结束事件循环。

void A::onPointPicked(double* pos)

void A::onPointPicked(double* pos) {ui.textBrowser->insertPlainText(QString("Point picked: %1 %2 %3\n").arg(pos[0]).arg(pos[1]).arg(pos[2]));ui.textBrowser->moveCursor(QTextCursor::End);mandibleActor->SetOrigin(pos);
}

当这个方法被调用时,它将在文本浏览器中显示选中的点的坐标,并将这个点设置为模型的旋转原点。

通过这种方式,当用户点击鼠标左键时,程序将获取点击位置的点,显示其坐标,并设置它为模型的旋转原点。


完整版代码如下:

A.h

// A.h
#pragma once#include <QtWidgets/QMainWindow>
#include "ui_A.h"#include <vtkSmartPointer.h>
#include <vtkSTLReader.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkRenderWindowInteractor.h>#include <vtkCellPicker.h>
#include <vtkCommand.h>
#include <vtkObjectFactory.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkRendererCollection.h>
#include <vtkPropPicker.h>
#include <QObject>#include <qtimer.h>class A : public QMainWindow
{Q_OBJECTpublic:A(QWidget* parent = nullptr);~A();private slots:void on_pushButtonSelect_clicked();void on_pushButtonSelDone_clicked();void onPointPicked(double* pos);void rotate();private:Ui::AClass ui;void initVTK();vtkSmartPointer<vtkActor> actor;vtkSmartPointer<vtkRenderer> renderer;vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow;QTimer* timer;
};class PointPickedSignal : public QObject
{Q_OBJECT
public:PointPickedSignal(QObject* parent = nullptr) : QObject(parent) {}signals:void pointPicked(double* pos);
};class MouseInteractorCommand : public vtkCommand
{
public:vtkTypeMacro(MouseInteractorCommand, vtkCommand);static MouseInteractorCommand* New(){return new MouseInteractorCommand;}virtual void Execute(vtkObject* caller, unsigned long eventId, void* vtkNotUsed(callData)){vtkRenderWindowInteractor* interactor = vtkRenderWindowInteractor::SafeDownCast(caller);int* clickPos = interactor->GetEventPosition();vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();picker->SetTolerance(0.0005);if (picker->Pick(clickPos[0], clickPos[1], 0, interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer())){double* pos = picker->GetPickPosition();memcpy(pickedPoint, pos, sizeof(double) * 3);emit signal->pointPicked(pickedPoint);}}double pickedPoint[3];PointPickedSignal* signal; // this will emit the pointPicked signal when a point is picked
};

A.cpp

// A.cpp
#include "A.h"A::A(QWidget* parent): QMainWindow(parent)
{ui.setupUi(this);// 配置 VTK 的初始设置initVTK();// 定时器,50ms 更新触发一次 checkPositionChange()timer = new QTimer(this);connect(timer, SIGNAL(timeout()), this, SLOT(rotate()));timer->start(100);
}A::~A()
{
}void A::initVTK()
{// 读取 STL 文件vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();reader->SetFileName("skull_50.stl"); // 请替换为你的 STL 文件路径reader->Update();// 创建映射器和演员vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();mapper->SetInputConnection(reader->GetOutputPort());actor = vtkSmartPointer<vtkActor>::New();actor->SetMapper(mapper);// 创建渲染器renderer = vtkSmartPointer<vtkRenderer>::New();// 添加演员到渲染器renderer->AddActor(actor);// 创建渲染窗口和渲染窗口交互器renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();renderWindow->AddRenderer(renderer);// 添加到 qvtkWidget 控件中显示ui.qvtkWidget->setRenderWindow(renderWindow);}void A::on_pushButtonSelect_clicked() {ui.textBrowser->insertPlainText("Select button clicked!\n");PointPickedSignal* signal = new PointPickedSignal(this);vtkSmartPointer<MouseInteractorCommand> command = vtkSmartPointer<MouseInteractorCommand>::New();command->signal = signal;ui.qvtkWidget->interactor()->AddObserver(vtkCommand::LeftButtonPressEvent, command);QEventLoop loop;connect(signal, &PointPickedSignal::pointPicked, this, &A::onPointPicked);connect(signal, &PointPickedSignal::pointPicked, &loop, &QEventLoop::quit);loop.exec();onPointPicked(command->pickedPoint);
}void A::onPointPicked(double* pos) {ui.textBrowser->insertPlainText(QString("Point picked: %1 %2 %3\n").arg(pos[0]).arg(pos[1]).arg(pos[2]));ui.textBrowser->moveCursor(QTextCursor::End);actor->SetOrigin(pos);
}void A::on_pushButtonSelDone_clicked() {ui.textBrowser->insertPlainText("Selection done, restore the default interactor style.\n");// 移除左键按下事件的观察者ui.qvtkWidget->interactor()->RemoveObservers(vtkCommand::LeftButtonPressEvent);// 恢复默认的交互器样式。vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();ui.qvtkWidget->interactor()->SetInteractorStyle(style);
}void A::rotate()
{actor->RotateX(5);renderWindow->Render();
}

Ref.

  1. 骷髅3D打印3D模型

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

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

相关文章

vue3搭建(vite+create-vue)

目录 前提条件 输入命令 对于Add an End-to-End Testing Solution nightwatch和Cypress 和 Playwright 运行 前提条件 熟悉命令行已安装 16.0 或更高版本的 Node.js &#xff08;node -v查看版本&#xff09; 输入命令 npm init vuelatest 这一指令将会安装并执行 create-…

Meta AI研究团队新AI模型: Llama 2 大语言模型

Llama是Facebook Research团队开发的基础语言模型集&#xff0c;旨在提供广泛的语言理解能力。它基于转换器架构&#xff0c;参数范围从7B到65B。通过使用Llama模型&#xff0c;研究人员和开发人员可以构建更先进的自然语言处理系统。您可以在GitHub上找到相关的代码和资源&…

kotlin 编写一个简单的天气预报app(四)增加界面显示

编写界面来显示返回的数据 用户友好性&#xff1a;通过界面设计和用户体验优化&#xff0c;可以使天气信息更易读、易理解和易操作。有效的界面设计可以提高用户满意度并提供更好的交互体验。 增加城市名字的TextView <TextViewandroid:id"id/textViewCityName"…

CentOS 7虚拟机 虚拟机安装安装增强VBox_GAs_6.1.22失败:modprobe vboxguest failed

我安装的CentOS 在安装增强工具的时候报错: 查阅资料后 &#xff0c;解决方法&#xff1a; 1、更新kernel内核版本&#xff1a; yum update kernel -y //安装kernel-devel和gcc编译工具链yum install -y kernel-devel gcc//更新kernel和kernel-devel到最新版本yum -y upgrade …

就业并想要长期发展选数字后端还是ic验证?

“就业并想要长期发展选数字后端还是ic验证&#xff1f;” 这是知乎上的一个热点问题&#xff0c;浏览量达到了13,183。看来有不少同学对这个问题感到疑惑。之前更新了数字后端&数字验证的诸多文章&#xff0c;从学习到职业发展&#xff0c;都写过&#xff0c;唯一没有做过…

windows编译ncnn

官方代码https://github.com/Tencent/ncnn/wiki/how-to-build#build-for-windows-x64-using-visual-studio-community-2017 编译工具 visual studio 2017 一、编译protobuf 1、下载protobuf protobuf-3.11.2&#xff1a;https://github.com/google/protobuf/archive/v3.11…

指针初阶(超详解)

指针初阶 1.指针是什么2.指针和指针类型2.1 指针-整数2.2 指针的解引用 3.野指针3.1 野指针成因3.2如何避免野指针 4.指针运算4.1 指针-整数4.2 指针-指针4.3 指针的关系运算 5.指针和数组6.二级指针7.指针数组 1.指针是什么 指针是什么&#xff1f; 指针理解的2个要点&#xf…

maven下载按照及初次使用相关配置

maven下载按照及初次使用相关配置 一、下载 与安装 依赖Java&#xff0c;需要配置JAVA_HOME设置MAVEN自身的运行环境&#xff0c;需要配置MAVEN_HOME测试环境配置结果 MVN测试成功&#xff01;&#xff01;&#xff01; 二、本地仓库配置 Maven启动后&#xff0c;会自动保…

基于Amoeba读写分离(三十六)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 今天要学的是基于Amoeba读写分离。Amoeba是一个开源的关系型数据库管理系统&#xf…

Spark性能调优之数据序列化

前言 在使用Spark进行数据开发的时候,避不开的一个问题就是性能调优。网上一搜一大堆所谓的调优策略很多作者自己都不知所云,导致读者看了后只会更加困惑。我们在研究一个技术的时候第一手资料永远都请参考官网,官网对性能优化不一定是最全甚至最优,但是可以解决大部分问题…

向 Maven 中央仓库上传一个修改过的基于jeecg的autoPOI的 jar包记录

1、注册https://issues.sonatype.org/账号 下面就代表注册好了&#xff0c;同时提交的工单也通过了 2、这里主要是goupId 需要进行认证&#xff0c;需要到域名注册商近一个txt的解析&#xff0c;以便确保这个是你的 通过下面来验证你的域名信息&#xff0c;这里主要是上面的工…

面试题:说一说深拷贝和浅拷贝?

JavaScript中存在两大数据类型&#xff1a; 基本类型 和 引用类型 基本类型数据保存在在栈内存中 引用类型数据保存在堆内存中&#xff0c;引用数据类型的变量是一个指向堆内存中实际对象的引用&#xff0c;存在栈中 深拷贝和浅拷贝都只针对于引用类型。 一、 浅拷贝&#xff1…

Cpp7 — 继承和多态

继承 -------- 面向对象的三大特性之一 面向对象的三大特性&#xff1a;封装、继承、多态 封装&#xff1a;把数据和方法都封装在一起&#xff0c;想给你访问的变成共有&#xff0c;不想给访问的&#xff0c;写成私有。 继承&#xff1a;继承是类设计层次的复用 多态&#…

【AGI】Copilot AI编程辅助工具安装教程

1. 基础激活教程 GitHub和OpenAI联合为程序员们送上了编程神器——GitHub Copilot。 但是&#xff0c;Copilot目前不提供公开使用&#xff0c;需要注册账号通过审核&#xff0c;我也提交了申请&#xff1a;这里第一期记录下&#xff0c;开启教程&#xff0c;欢迎大佬们来讨论…

通向架构师的道路之apache性能调优

一、总结前一天的学习 在前两天的学习中我们知道、了解并掌握了Web Server结合App Server实现单向Https的这样的一个架构。这个架构是一个非常基础的J2ee工程上线布署时的一种架构。在前两天的教程中&#xff0c;还讲述了Http服务 器、App Server的最基本安全配置&#xff08;…

java 数组的使用

数组 基本介绍 数组可以存放多个同一类型的数据&#xff0c;数组也是一种数据类型&#xff0c;是引用类型。 即&#xff1a;数组就是一组数据。 数组的使用 1、数组的定义 方法一 -> 单独声明 数据类型[] 数组名 new 数据类型[大小] 说明&#xff1a;int[] a new int…

C/C++算法——散列表

1、散列表介绍 散列表的英文叫Hash Table&#xff0c;我们平时也叫它哈希表或者Hash 表。散列表用的是数组支持按照下标随机访问数据的特性&#xff0c;所以散列表其实就是数组的一种扩展&#xff0c;由数组演化而来。可以说&#xff0c;如果没有数组&#xff0c;就没有散列表。…

iOS——锁与死锁问题

iOS中的锁 什么是锁锁的分类互斥锁1. synchronized2. NSLock3. pthread 递归锁1. NSRecursiveLock2. pthread 信号量Semaphore1. dispatch_semaphore_t2. pthread 条件锁1. NSCodition2. NSCoditionLock3. POSIX Conditions 分布式锁NSDistributedLock 读写锁1. dispatch_barri…

超全整理,Jmeter性能测试-常用Jmeter第三方插件详解(超细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Jmeter作为一个开…

React(4)

1.属性&#xff08;props&#xff09;初始 状态state都是组件内部写的&#xff0c;也就是A组件内的state就只能A组件里面用&#xff0c;其他组件复用不了。因此属性props就可以。 比如一个导航栏&#xff0c;首页有&#xff0c;购物车有&#xff0c;我的有&#xff0c;他们三个…