当前位置: 首页 > news >正文

VTK开发笔记(五):示例Cone2,熟悉观察者模式,在Qt窗口中详解复现对应的Demo

若该文为原创文章,转载请注明出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/151314851

长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

OSG、VTK、OSGEARTH三维开发专栏(点击传送门)

上一篇:《VTK开发笔记(四):示例Cone,创建圆锥体,在Qt窗口中详解复现对应的Demo》
下一篇:敬请期待…


前言

  Vtk的了解学习途径跟随代码中的示例,循序渐进。
  本篇详细解析Cone2.exe,在Cone.exe基础上新增了观察者的概念,在Qt中复现一样的观察者。


Demo

  在这里插入图片描述


观察者模式

概述

  观察者模式(Observer Pattern),允许一个对象(观察者)关注另一个对象(被观察者)的状态变化,并在事件发生时自动执行预定操作。观察者回调(Observer-Callback) 是一种事件驱动的编程机制,用于处理 VTK 对象状态变化或特定事件的响应。

核心概念

  事件(Event)VTK 对象在特定操作或状态变化时会触发事件,例如: 数据更新(如vtkCommand::ModifiedEvent) 渲染完成(如vtkCommand::EndEvent) 鼠标交互(如vtkCommand::LeftButtonPressEvent) 每个事件都有唯一的标识符(如枚举值或字符串)。
  观察者(Observer) 注册到 VTK 对象上,用于 “监听” 特定事件的对象。当被监听的事件触发时,观察者会执行关联的回调函数。 回调函数(Callback) 事件触发时实际执行的代码逻辑,通常是自定义函数或方法,用于响应事件(如更新 UI、处理数据、日志记录等)。

工作流程

  • 步骤一:定义回调函数:实现处理事件的逻辑(需符合 VTK 的回调接口规范)。
  • 步骤二:获取被观察者:确定需要监听的 VTK 对象(如vtkRenderer、vtkActor等)。
  • 步骤三:注册观察者:将回调函数与特定事件绑定到被观察者上。
  • 步骤四:事件触发与响应:当被观察者触发事件时,VTK 自动调用对应的回调函数。

简单示例

  在这里插入图片描述

  在这里插入图片描述


观察者实现vtkCommand

  vtkCommand是观察器/命令设计模式的实现。在这种设计模式中,可以“观察”vtkObject的任何实例,以了解它可能调用的任何事件。例如,vtkRenderer在开始渲染时调用StartEvent,在完成渲染时调用EndEvent。过滤器(vtkProcessObject的子类)在过滤器处理数据时调用StartEvent、ProgressEvent和EndEvent。事件的观察者是通过vtkObject中的AddObserver()方法添加的。AddObserver()除了需要一个事件id或名称外,还需要一个vtkCommand实例(或子类)。请注意,vtkCommand旨在被子类化,以便可以打包支持回调所需的信息。
  事件处理可以按优先级列表进行组织,因此可以通过设置AbortFlag变量截断特定事件的处理。优先级是通过以下方式设定的AddObserver()方法。默认情况下,优先级为0,具有相同优先级的事件将按第一个处理顺序中的最后一个处理。事件的排序/中止对于像3D小部件这样的东西很重要,如果选择了小部件,它们会处理事件(然后中止对该事件的进一步处理)。否则。事件被传递以供进一步处理。
  当vtkObject的实例调用事件时,它还会将可选的void指针传递给callData。这个callData在大多数时候都是空的。callData并不特定于某一类型的事件,而是特定于调用特定事件的vtkObject类型。例如,  vtkCommand::PickEvent由vtkProp使用空指针调用,但由vtkInteractiorStyleImage使用指向  vtkInteractitorStyleImage对象本身的指针调用。
  以下是可以使用非nullptr callData调用的事件列表:
  在这里插入图片描述
  在这里插入图片描述


复现Demo

  有一个很重要的点,这个示例代码是阻塞时的循环刷新,与Qt的基于消息的编程处理方式不一样,这是过程式的编程,我们复刻示例,保持一块Demo就一个函数,否则的话,可以使用Qt定时器来实现更新位置就可以了。

步骤一:创建圆锥体数据源

  在这里插入图片描述

步骤二:创建多边形映射器

  在这里插入图片描述

  在这里插入图片描述

步骤三:创建演员类(类似osg模型结点)

  在这里插入图片描述

  在这里插入图片描述

步骤四:创建渲染器

  在这里插入图片描述

  在这里插入图片描述

步骤五:设置渲染器到渲染窗口

  在这里插入图片描述

步骤六:设置观察者回调函数

  这里回调类,放在函数里面定义,方便归类demo
  在这里插入图片描述

步骤七:用Qt的方式实现不阻塞又是过程化旋转

  为了看到更加清晰,我们设置过渡延迟一循环为1000ms:
  在这里插入图片描述

  在这里插入图片描述


运行效果

  在这里插入图片描述
  在这里插入图片描述


Demo源码

VTKWidget.cpp

void VTKWidget::test_demo4_createCone()
{// 步骤一:创建圆锥体数据源vtkSmartPointer<vtkConeSource> pConeSource =VTKManager::createConeSource(0, 0, 0, 10, 30, 10);// 步骤二:创建多边形映射器
#if 0vtkSmartPointer<vtkPolyDataMapper> pPolyDataMapper =VTKManager::createPolyDataMapper(pConeSource);
#elsevtkSmartPointer<vtkPolyDataMapper> pPolyDataMapper =VTKManager::createPolyDataMapper(pConeSource->GetOutputPort());
#endif// 步骤三:创建演员vtkSmartPointer<vtkActor> pActor =VTKManager::createActor(pPolyDataMapper);// 步骤四:创建渲染器vtkSmartPointer<vtkRenderer> pRenderer =VTKManager::createRenderer(pActor, 0.1, 0.2, 0.4);// 步骤五:渲染器添加到QVTKWidget渲染_pQVTKWidget->GetRenderWindow()->AddRenderer(pRenderer);// 步骤六:设置观察者,触发回调函数,交互回调class vtkMyCallback : public vtkCommand{public:static vtkMyCallback *New() {return new vtkMyCallback;}void Execute(vtkObject *caller, unsigned long, void*) override{// 注意:这个类在函数里面定义,其函数内部无法直接->或者.来得到成员函数vtkRenderer *pRenderer = reinterpret_cast<vtkRenderer*>(caller);LOG << pRenderer->GetActiveCamera()->GetPosition()[0]<< pRenderer->GetActiveCamera()->GetPosition()[1]<< pRenderer->GetActiveCamera()->GetPosition()[2];}};vtkMyCallback *pVtkMyCallback = vtkMyCallback::New();pRenderer->AddObserver(vtkCommand::StartEvent, pVtkMyCallback);pVtkMyCallback->Delete();// 步骤七:过程循环的方式实现旋转QElapsedTimer elapsedTimer;for(int index = 0; index < 360; index++){LOG << index;if(!isVisible()){continue;}// 渲染一次_pQVTKWidget->GetRenderWindow()->Render();elapsedTimer.start();while(elapsedTimer.elapsed() < 100){qApp->processEvents();}if(!isVisible()){continue;}// 渲染器相机绕焦点旋转VTKManager::rotateAzimuth(pRenderer, 1);}
}

VTKManager.cpp

vtkSmartPointer<vtkConeSource> VTKManager::createConeSource(double x, double y, double z, double r, int h, int n)
{// 步骤一:智能指针定义vtkSmartPointer<vtkConeSource> pConeSource;// 步骤二:智能指针实例化pConeSource = vtkSmartPointer<vtkConeSource>::New();// 步骤三:设置中心坐标pConeSource->SetCenter(x, y, z);// 步骤三:设置半径pConeSource->SetRadius(r);// 步骤四:设置圆锥的高度pConeSource->SetHeight(h);// 步骤五:设置圆锥球体的经度分辨率,即横向的切片数量(横向/水平精细度)pConeSource->SetResolution(n);return pConeSource;
}
vtkSmartPointer<vtkPolyDataMapper> VTKManager::createPolyDataMapper(vtkAlgorithmOutput *pAlgorithmOutput)
{// 步骤一:智能指针定义vtkSmartPointer<vtkPolyDataMapper> pPolyDataMapper;// 步骤二:智能指针实例化pPolyDataMapper = vtkSmartPointer<vtkPolyDataMapper>::New();// 步骤三:设置pPolyDataMapper->SetInputConnection(pAlgorithmOutput);return pPolyDataMapper;
}
vtkSmartPointer<vtkActor> VTKManager::createActor(vtkPolyDataMapper *pPolyDataMapper)
{// 步骤一:智能指针定义vtkSmartPointer<vtkActor> pActor;// 步骤二:智能指针实例化pActor = vtkSmartPointer<vtkActor>::New();// 步骤三:设置映射器pActor->SetMapper(pPolyDataMapper);return pActor;
}vtkSmartPointer<vtkRenderer> VTKManager::createRenderer(std::vector<vtkActor *> vectorPActor, double r, double g, double b)
{// 步骤一:智能指针定义vtkSmartPointer<vtkRenderer> pRenderer;// 步骤二:智能指针实例化pRenderer = vtkSmartPointer<vtkRenderer>::New();// 步骤三:设置映射器for(int index = 0; index < vectorPActor.size(); index++){pRenderer->AddActor(vectorPActor.at(index));}// 步骤四:设置背景色pRenderer->SetBackground(r, g, b);return pRenderer;
}

工程模板v1.3.0

  在这里插入图片描述


上一篇:《VTK开发笔记(四):示例Cone,创建圆锥体,在Qt窗口中详解复现对应的Demo》
下一篇:敬请期待…


本文章博客地址:https://hpzwl.blog.csdn.net/article/details/151314851


文章转载自:

http://AocwViVj.jzykw.cn
http://3yzNORjI.jzykw.cn
http://KR1IJbMV.jzykw.cn
http://Opk6Ngat.jzykw.cn
http://KWmfYqPc.jzykw.cn
http://QKpsSPDo.jzykw.cn
http://lTMl8Hli.jzykw.cn
http://KNLNvcy4.jzykw.cn
http://f10hBiBJ.jzykw.cn
http://QMpAiuqJ.jzykw.cn
http://3cPUIUzl.jzykw.cn
http://gxAZvOTu.jzykw.cn
http://LTRcEHs5.jzykw.cn
http://RSeoVgNo.jzykw.cn
http://VcbzWh5Y.jzykw.cn
http://rLc6gC1p.jzykw.cn
http://rmKnlKet.jzykw.cn
http://zBtFoZoT.jzykw.cn
http://ZwBxnBgh.jzykw.cn
http://X6t7hilR.jzykw.cn
http://qv1rdbsy.jzykw.cn
http://kHVRmbQ0.jzykw.cn
http://MjurreH6.jzykw.cn
http://AANTZNXO.jzykw.cn
http://GctPdITG.jzykw.cn
http://QEv9ewh9.jzykw.cn
http://GrNr6NR1.jzykw.cn
http://UCdiKzRU.jzykw.cn
http://FwkRs8iD.jzykw.cn
http://QnW53vGR.jzykw.cn
http://www.dtcms.com/a/373405.html

相关文章:

  • Excel 表格 - Excel 减少干扰、专注于内容的查看方式
  • Vue3 + Ant Design Vue 全局配置中文指南
  • CSS in JS 的演进:Styled Components, Emotion 等的深度对比与技术选型指引
  • 哈士奇vs网易高级数仓:数据仓库的灵魂是模型、数据质量还是计算速度?| 易错题
  • Windows 命令行:cd 命令2,切换到多级子目录
  • C++ 8
  • GD32入门到实战45--LVGL开发(Code::Blocks)之创建控件
  • 算法题(202):乌龟棋
  • 国产化服务注册与发现工具nacos安装
  • WordPress 性能优化:从插件到 CDN 的全方位缓存设置指南
  • 所有微服务部署都使用一个git地址,并且通过docker部署各个服务的情况下,如何编写mvn指令来处理各个服务。
  • 【AI】乡村振兴计划书:AI智能农业与设备研发销售一体化项目
  • 408 Request Timeout:请求超时,服务器等待客户端发送请求的时间过长。
  • 从车辆中心到用户中心:E/E架构的变革与挑战
  • 基于Mysql+SpringBoot+vue框架-校园商铺管理系统源码
  • SQL MERGE语句实战:高效增量数据处理
  • AI 云再进化,百度智能云新技术与产品全景解读
  • react 面试题 react 有什么特点?
  • PyTorch 模型保存与加载 (速查版)
  • MCU-在SOTA过程中基于TC397的AB-SWAP切换底层原理
  • Python+DRVT 从外部调用 Revit:批量创建带孔洞楼板
  • 如何解决Ubuntu22.04安装Docker后使用Timeshift进行备份非常慢的问题
  • 自适应支撑衣专利拆解:IMU 传感器与线轴引擎的支撑力动态调节机制
  • Linux系统shell脚本(五)
  • 秋招刷题|数据分析岗:Numpy30道核心考点解析
  • 实例分割网络-YOLACT使用
  • PyCharm SSH Autodl
  • 9月8日星期一今日早报简报微语报早读
  • Python2-工具安装使用-anaconda-jupyter-PyCharm-Matplotlib
  • GEO搜索优化服务全流程解析:从诊断到持续优化的完整服务体验