前言

  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 0
vtkSmartPointer<vtkPolyDataMapper> pPolyDataMapper =
VTKManager::createPolyDataMapper(pConeSource);
#else
vtkSmartPointer<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开发笔记(五):示例Cone2,熟悉观察者模式,在Qt窗口中详解复现对应的Demo的更多相关文章

  1. FFmpeg开发笔记(四):ffmpeg解码的基本流程详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  2. Django开发笔记五

    Django开发笔记一 Django开发笔记二 Django开发笔记三 Django开发笔记四 Django开发笔记五 Django开发笔记六 1.页面继承 定义base.html: <!DOC ...

  3. 【HANA系列】【第五篇】SAP HANA XS的JavaScript API详解

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第五篇]SAP HANA XS ...

  4. Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

    Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...

  5. web标准 浏览器介绍 开发工具介绍 HTML介绍 HTML颜色介绍 规范 HTML结构详解 {前端之前端初识}

    前端之前端初识   前端初识 本节目录 一 web标准 二 浏览器介绍 三 开发工具介绍 四 HTML介绍 五 HTML颜色介绍 六 规范 七 HTML结构详解 一 web标准 web准备介绍: 1. ...

  6. Flutter学习笔记(15)--MaterialApp应用组件及routes路由详解

    如需转载,请注明出处:Flutter学习笔记(15)--MaterialApp应用组件及routes路由详解 最近一段时间生病了,整天往医院跑,也没状态学东西了,现在是好了不少了,也该继续学习啦!!! ...

  7. Spark Streaming揭秘 Day28 在集成开发环境中详解Spark Streaming的运行日志内幕

    Spark Streaming揭秘 Day28 在集成开发环境中详解Spark Streaming的运行日志内幕 今天会逐行解析一下SparkStreaming运行的日志,运行的是WordCountO ...

  8. 《Android群英传》读书笔记 (2) 第三章 控件架构与自定义控件详解 + 第四章 ListView使用技巧 + 第五章 Scroll分析

    第三章 Android控件架构与自定义控件详解 1.Android控件架构下图是UI界面架构图,每个Activity都有一个Window对象,通常是由PhoneWindow类来实现的.PhoneWin ...

  9. Matlab+Qt开发笔记(一):matlab搭建Qt开发matlib环境以及Demo测试

    前言   做一些数据处理软件,使用matlab文件,.mat文件.   准备条件   安装matlab2016,发现是vs 12(是vs2011版本),Qt5.9.3是支持vs 14(是vs2015版 ...

  10. IONIC 开发的Android应用程序签名(或重新签名)详解

    完全通过DOS命令来完成apk签名 给apk签名一共要用到3个工具,或者说3个命令,分别是:keytool.jarsigner和zipalign,下面是对这3个工具的简单介绍:            ...

随机推荐

  1. SciTech-Theory-Phenomeon(Problem: Conditions+Process+Outcomes with Probability)->Experience->Concept(Natural+Common part of experiences)-> Principle(invest+research) -> Definition -> Theory -> Axiom

    SciTech Layers: Objective: Problem/Phenomeon: a objective Process and its Outcomes, and Conditions. ...

  2. ActiveMQ是什么?-九五小庞

    MQ是消息中间件,是一种在分布式系统中应用程序借以传递消息的媒介,常用的有ActiveMQ,RabbitMQ,kafka.ActiveMQ是Apache下的开源项目,完全支持JMS1.1和J2EE1. ...

  3. CF1365G Secure Password

    \(\mathbf{Part. -1}\) 这是一个交互题. Ayush 又想出了一个设置密码的新方法.他的锁有 \(n\) 个槽位,每个槽位可以放置任意非负整数.密码 \(P\) 是一个长度为 \( ...

  4. Oracle调优之no_unnest和unnest用法简介

    Oracle调优之no_unnest和unnest用法简介 本博客介绍Oracle SQL调优的一种常用也是很实用的方法,也即/*+no_unnest */和/*+ unnest*/ ,介绍Oracl ...

  5. 训练表(NOIP 2024 前)

    记号 sb 题 / 模板题前加:\(\circ\) 有一定难度的题前加:\(\Re\) 不可做的,积累经验的题前加:\(\Im\) 完全是自己做的题前加:\(\bigstar\) 看了题解或讨论的题前 ...

  6. 编辑大量文本的情况vscode比notepad++性能更好

    尝试操作几十万行的文本的时候Notepad++直接卡死了 二十多万行的文本选中需要卡几秒,剪切粘贴文本需要卡几秒 文本替换需要跑几十秒,再多一些的话容易卡崩 使用vscode进行剪切粘贴 批量替换 之 ...

  7. Cerely框架-异步执行与定时任务

    celery-处理大量的分布式系统,专注于实时处理的异步队列,也支持任务调度 celery的架构由三部分组成,消息中间件,任务执行单元和任务结果存储. 用户发起请求--->django(处理业务 ...

  8. Java集合——12.使用Deque

    目录 Java的双端队列Deque Deque的特性 Deque与Queue的方法对比 方法行为差异 Deque示例 Deque的实现类 总结 Java的双端队列Deque Deque的特性 Dequ ...

  9. [题解]P1083 [NOIP2012 提高组] 借教室

    [题解]P1083 [NOIP2012 提高组] 借教室 解法\(1\):线段树 - \(O((n+m)\log n)\) 比较直观的一种做法,但是可能需要卡一下输入(这里没卡也过了,但要注意输入是\ ...

  10. Semantic Kernel 入门教程

    https://www.bilibili.com/video/BV1sr4y1f7zb/?spm_id_from=333.337.search-card.all.click&vd_source ...