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

示例Cone2,熟悉观察者模式,在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 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;

}

http://www.jsqmd.com/news/119732/

相关文章:

  • 2025年伸缩悬臂货架哪家强?十大口碑厂家深度解析,伸缩悬臂货架/重型仓储货架/伸缩货架/抽拉式重型货架伸缩悬臂货架源头厂家有哪些 - 品牌推荐师
  • 当像素遇上混沌:MATLAB图像加密的奇幻漂流
  • 2025年度优质调节阀批发厂家综合排名揭晓,特种调节阀/精小型调节阀/调节阀/高性能调节阀/气动高温调节阀/美标调节阀调节阀生产商怎么选择 - 品牌推荐师
  • 《PHP POP 链构造(下):实战与利用》
  • CSS布局小技巧
  • day29打卡
  • 【权威对比】Open-AutoGLM与Parasoft SOAtest集成能力评测:数据背后的真相
  • 【权威对比】Open-AutoGLM与Parasoft SOAtest集成能力评测:数据背后的真相
  • cesium126,230911,Ce for Ue WMTS的编译流程:但 Cesium for Unreal 2.3.0已经实现了WMTS
  • 高可靠电子产品设计的IC选用和PCB设计
  • Word如何实现电子版手写签名?
  • 2025年行业内优质的制冷设备直销厂家排行,闭式冷却塔/玻璃钢冷却塔/冷却塔/制冷设备/工业冷却塔/冷却水塔制冷设备定制厂家怎么选 - 品牌推荐师
  • 真空包装袋选购指南:十大口碑厂家深度解析,市场优质的真空包装袋品牌关键技术和产品信息全方位测评 - 品牌推荐师
  • Thinkphp和Laravel党员素质能力提升管理系统vue
  • 《Docker Swarm实战:从入门到企业级生产部署》大纲【20251221】001篇
  • 【原创实践】Docker 镜像批量导出镜像与导入镜像
  • 监控指标与容量预警——延迟、命中率、慢查询与内存碎片的解读方法
  • 8个降AI率工具,MBA高效写作利器
  • 12.21
  • 移动端体验差?兰亭妙微用户体验设计公司教你 6 招解锁高效界面设计
  • - 标题: 基于matlab的热红外图像温度检测 - 关键词:matlab GUI界面 高斯噪...
  • 阿玛特拉斯
  • 第 481 场周赛Q1——100942. 整数的镜像距离
  • 2025年CNC数控机床定制服务商综合实力排行,自动化数控机床/医疗器械数控机床/牙科配件数控车床/级柱数控机床CNC数控机床品牌找哪家 - 品牌推荐师
  • Thinkphp和Laravel婚庆服务网站的设计与实现vue
  • Thinkphp和Laravel宠屋”宠物交易商城购物网站的设计与实现-vue
  • eDiary电子日记本(记录生活点滴)
  • Thinkphp和Laravel大学生兼职雇佣应聘系统_yk10d-vue
  • Open-AutoGLM与UFT Mobile功能对标(9项核心能力实测数据曝光)
  • AI算法实时“站岗” 及时发现商铺通道堵塞,避免安全隐患