【FastCAE源码阅读5】使用VTK实现鼠标拾取对象并高亮

news2024/11/29 11:38:56

一、拾取对象

拾取对象是在PropPickerInteractionStyle类实现的,该类是vtkInteractorStyleRubberBandPick的子类,重写原来的鼠标处理函数。当鼠标左键按下,会触发以下代码:

void PropPickerInteractionStyle::clickSelectGeometry(bool preSelect)
{
	int *clickPos = this->GetInteractor()->GetEventPosition(); // 获取鼠标点击位置
	int success = -1, index = -1;
	vtkActor *actor = nullptr;
	if (_selectModel == GeometryPoint || _selectModel == GeometryWinPoint) // 几何点
	{
		vtkSmartPointer<vtkPointPicker> picker = vtkSmartPointer<vtkPointPicker>::New();
		success = picker->Pick(clickPos[0], clickPos[1], 0, this->GetDefaultRenderer());
		if (0 != success)
		{
			index = picker->GetPointId(); // 点的id
			actor = picker->GetActor(); // 点对应的Actor
		}
	}
	else
	{
		vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New();
		if (_selectModel == GeometryCurve || _selectModel == GeometryWinCurve)
			picker->SetTolerance(0.0025);
		success = picker->Pick(clickPos[0], clickPos[1], 0, this->GetDefaultRenderer());
		if (0 != success)
		{
			index = picker->GetCellId(); // cell的id
			actor = picker->GetActor(); // 对应的actor
		}
	}
	emit selectGeometry(preSelect, actor, index);
}

这段代码就是鼠标拾取对象的核心逻辑。其实现是借助了VTK提供的vtkPointPicker、vtkCellPicker。其中当拾取模式是点的时候,使用vtkPointPicker,如果拾取成功返回点的id及对应的Actor(一个Actor可能包含多个点)。当拾取模式是线、面、体的时候,使用vtkCellPicker,成功则返回对应cell id及Actor(一个Actor可能包含多个cell)。注意当拾取线的时候,需要提高拾取Tolerance,不然线很难拾取到。

另外要注意的是,当拾取线的时候,面Actor是拾取不到的,同样当拾取面的时候,线Actor也是拾取不到。这是通过在用户切换选择模式的时候,设置面或边Actor是否可以拾取实现的。核心代码在GeometryViewProvider类中,如下:

void GeometryViewProvider::setGeoSelectMode(int m)
{
	_viewData->updateGraphOption();
	ModuleBase::SelectModel selectType = (ModuleBase::SelectModel)m;
	QList<GeoViewObj> viewObjs = _geoViewHash.values();
	vtkActor *actor = nullptr;
	for (GeoViewObj vobj : viewObjs)
	{
		actor = vobj._faceObj.first;
		if (actor != nullptr)
			actor->SetPickable(false);
		actor = vobj._edgeObj.first;
		if (actor != nullptr)
			actor->SetPickable(false);
		actor = vobj._pointObj.first;
		if (actor != nullptr)
			actor->SetPickable(false);
		switch (selectType)
		{
		case ModuleBase::GeometryBody:
		case ModuleBase::GeometrySurface:
		case ModuleBase::GeometryWinBody:
		case ModuleBase::GeometryWinSurface:
			actor = vobj._faceObj.first;
			if (actor != nullptr)
				actor->SetPickable(true);
			break;
		case ModuleBase::GeometryWinCurve:
		case ModuleBase::GeometryCurve:
			actor = vobj._edgeObj.first;
			if (actor != nullptr)
				actor->SetPickable(true);
			break;
		case ModuleBase::GeometryWinPoint:
		case ModuleBase::GeometryPoint:
			actor = vobj._pointObj.first;
			if (actor != nullptr)
				actor->SetPickable(true);
			break;
		default:
			break;
		}
	}
}

这个代码相对比较简单,不再分析。

二、从信号到槽函数

拾取对象之后,会发出emit selectGeometry信号,参数中带有Actor及cell或点的id。这个信号是QT框架提供的编程机制。其对应的槽函数在如下图中能找到:
在这里插入图片描述

三、高亮拾取对象

高亮拾取对象处理过程代码如下:

void GeometryViewProvider::selectGeometry(bool pre, vtkActor *ac, int index)
{
	if (ac == nullptr || index < 0) // 无效拾取
	{
		_viewData->preHighLight(nullptr);
		_preWindow->reRender();
		return;
	}
	ModuleBase::SelectModel selectMod = _preWindow->getSelectModel(); // 选择模式
	vtkDataSet *dataSet = ac->GetMapper()->GetInputAsDataSet(); // 获取Actor的多边形数据集vtkPolyData
	vtkPolyData *poly = vtkPolyData::SafeDownCast(dataSet);
	if (poly == nullptr)
		return;
	GeometryViewObject *vobj = nullptr;
	switch (selectMod)
	{
	case ModuleBase::GeometryWinBody:
	case ModuleBase::GeometryBody:
		vobj = _viewData->getSolidViewObj(poly, index);
		break;
	case ModuleBase::GeometryWinSurface:
	case ModuleBase::GeometrySurface:
		vobj = _viewData->getFaceViewObj(poly, index); // 输入多边形数据+cell id
		break;
	case ModuleBase::GeometryWinCurve:
	case ModuleBase::GeometryCurve:
		vobj = _viewData->getEdgeViewObj(poly, index);
		break;
	case ModuleBase::GeometryWinPoint:
	case ModuleBase::GeometryPoint:
		vobj = _viewData->getPointViewObj(poly, index);
		break;
	default:
		break;
	}
	if (vobj == nullptr)
		return;
	if (pre)
		_viewData->preHighLight(vobj); // 设置预高亮
	else
	{
		vobj->highLight(); // 高亮对象
		_viewData->preHighLight(nullptr);
		emit geoShapeSelected(vobj->getGeometySet(), vobj->getIndex());
	}
	_preWindow->reRender();
}

同样,这里也只分析面的高亮,其他的高亮逻辑类似。高亮处理的时候,直接先根据Actor获取了其vtkPolyData数据集,找到哪个面需要高亮,最后更改其颜色。如何根据cell id找到这个面,需要理解其数据结构才能看懂其逻辑。对于面的数据结构,这篇文章【FastCAE源码阅读3】几何模型显示:从OCC对象到VTK对象有详细描述。其核心原理是查找cell id落在哪个面包含的cell区间上,确定高亮哪个面。最后调用_preWindow->reRender()重新绘制整个场景。

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

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

相关文章

51单片机中断函数讲解及外部中断举例

文章目录 前言一、中断是什么&#xff1f;1.只有一个中断2. 什么东西可以中断&#xff1f;3. 有两个中断&#xff1f;中断嵌套4. 是否支持更多中断嵌套&#xff1f;5. 中断响应过程&#xff1f;6. 中断服务函数7.寄存器 二、外部中断实现1.中断配置2.参考程序3. 实验14.实验2 总…

性能工作站,双十一大促,超值推荐:蝰蛇峡谷 NUC12SNKi7迷你主机,优惠抢购!

近年来&#xff0c;ITX主机和小型化系统变得越来越受欢迎。英特尔的NUC受到许多玩家们的关注。作为mini主机的代表NUC小巧设计和灵活性使它成为很多玩家和科技爱好者的选择。它的高性能和可玩性使得它在迷你型准系统市场上备受推崇。双11来临之际&#xff0c;我们分析下哪款高性…

黑盒测试用例设计方法之等价类划分法

等价类划分法是一种典型的黑盒测试用例设计方法。采用等价类划分法时&#xff0c;完全不用考虑程序内部结构&#xff0c;设计测试用例的唯一依据是软件需求规格说明书。 等价类 所谓等价类&#xff0c;是输入条件的一个子集合&#xff0c;该输入集合中的数据对于揭示程序中的…

C++编程案例讲解-基于结构体的控制台通讯录管理系统

基于结构体的控制台通讯录管理系统 通讯录是一个可以记录亲人、好友信息的工具&#xff0c;系统中需要实现的功能如下&#xff1a; 添加联系人&#xff1a;向通讯录中添加新人&#xff0c;信息包括&#xff08;姓名、性别、年龄、联系电话、家庭住址&#xff09;最多记录1000人…

BuhoCleaner for Mac:彻底改变您的Mac清理体验

BuhoCleaner for Mac是一款专为Mac用户打造的清理工具&#xff0c;它可以帮助您清理无用的文件、缓存、日志和其他垃圾&#xff0c;从而释放磁盘空间并提高系统性能。这款工具具有简单易用的界面和强大的清理功能&#xff0c;是Mac用户必备的清理工具之一。 特点 简单易用的界…

3D RPG Course | Core 学习日记四:鼠标控制人物移动

前言 前边我们做好了Navgation智能导航地图烘焙&#xff0c;并且设置好了Player的NavMeshAgent&#xff0c;现在我们可以开始实现鼠标控制人物的移动了。除了控制人物移动以外&#xff0c;我们还需要实现鼠标指针的变换。 实现要点 要实现鼠标控制人物移动&#xff0c;点击…

VHDL基础知识笔记(1)

1.实体&#xff1a;其电路意义相当于器件&#xff0c;它相当于电路原理图上的元器件符号。它给出了器件的输入输出引脚。实体又被称为模块。 2.结构体&#xff1a;这个部分会给出实体&#xff08;或者说模块&#xff09;的具体实现&#xff0c;指定输入和输出的行为。结构体的…

十分钟搭建自己的在线书库随时随地看小说,Kindle不再盖泡面!

Kindle中国电子书店停运不要慌&#xff0c;十分钟搭建自己的在线书库随时随地看小说&#xff01; 文章目录 Kindle中国电子书店停运不要慌&#xff0c;十分钟搭建自己的在线书库随时随地看小说&#xff01;1.网络书库软件下载安装2.网络书库服务器设置3.内网穿透工具设置4.公网…

5K买的300集全套JAVA面试视频、10W+字文档成功上岸一线互联网大厂

前言&#xff1a; 今年这情况&#xff0c;真心建议所有 Java 后端不要随便被“行情差洗脑”&#xff01; 目前职友集上搜到的 java 岗位仍有22万&#xff0c;招聘需求相比其他行业不算少&#xff01; 大家最应该关注的是&#xff1a;自身技术硬度如何&#xff1f; 毕竟不管在…

Redis学习(十)RedisTemplate 对各种数据类型的支持

目录 一、SpringDataRedis 简介1.1 什么是 Redis&#xff1f;1.2 什么是 Jedis&#xff1f;1.3 什么是 Spring Data Redis&#xff1f; 二、RedisTemplate 中 API 使用2.1 pom.xml 依赖2.2 配置文件2.3 RedisTemplate 的直接方法2.4 String 类型相关操作2.5 Hash 类型相关操作2…

台灯选用什么类型好?双十一值得入手的护眼台灯推荐

如何给孩子挑选一盏能够护眼的台灯一直是许多家长都为之头痛的一大难题&#xff0c;主要是如今市面上的台灯实在太多了&#xff0c;而且迭代速度非常快&#xff0c;再加上这些产品中还混杂了许多不专业品牌、网红产品和低价劣质产品等等&#xff0c;想要挑选到一款好的台灯确实…

MVC模式和三层架构:

MVC模式&#xff1a; M&#xff1a;Model&#xff0c;业务模型&#xff0c;处理业务 V&#xff1a;View&#xff0c;视图&#xff0c;界面展示 C&#xff1a;Controller&#xff0c;控制器&#xff0c;处理请求&#xff0c;调用模型和视图 MVC优点&#xff1a; 职责单一&am…

C++ Lambda表达式 在竞赛中提高你的代码连贯性

本文中的lambda表达式使用方式应该在目前的所有比赛中&#xff08;C11及以上&#xff09;都是可以使用的&#xff0c;因为比较落后的蓝桥杯都更新到了C14。 当题目做的越来越多&#xff0c;难度越来越大&#xff0c;相应的代码就会越来越长&#xff0c;通常在100行左右。 在行…

你的GPU能跑Llama 2等大模型吗?用这个开源项目上手测一测

你的 GPU 内存够用吗&#xff1f;这有一个项目&#xff0c;可以提前帮你查看。 在算力为王的时代&#xff0c;你的 GPU 可以顺畅的运行大模型&#xff08;LLM&#xff09;吗&#xff1f; 对于这一问题&#xff0c;很多人都难以给出确切的回答&#xff0c;不知该如何计算 GPU 内…

云栖大会72小时沉浸式精彩回顾

计算&#xff0c;为了无法计算的价值 2023 杭州云栖大会震撼落幕 自2015年&#xff0c;云计算支撑着移动互联网创新 AI时代&#xff0c;继续支撑所有开发者的创新与梦想 当大会主题再次回归 让我们也打开时空隧道 一起回顾72小时云栖之旅 打造一朵AI时代最开放的云 随着…

SpringBoot单元测试报错“Error creating bean with name ‘serverEndpointExporter‘ ”

问题场景 在SpringBoot中使用单元测试时&#xff0c;出现以下报错&#xff0c;意思是创建名为‘serverEndpointExporter’的bean时出错。 org.springframework.beans.factory.BeanCreationException: Error creating bean with name serverEndpointExporter defined in class…

折叠旗舰新战局:华为先行,OPPO接棒

乌云中的曙光&#xff0c;总能带给人希望。 全球智能手机出货量已经连续八个季度下滑&#xff0c;行业里的乌云挥之不散。不过&#xff0c;也能看到高端市场逆势上涨&#xff0c;散发光亮。个中逻辑在于&#xff0c;当前换机周期已经达到了34个月&#xff0c;只有创新产品才能…

使用R语言构建HTTP爬虫:IP管理与策略

目录 摘要 一、HTTP爬虫与IP管理概述 二、使用R语言进行IP管理 三、爬虫的伦理与合规性 四、注意事项 结论 摘要 本文深入探讨了使用R语言构建HTTP爬虫时如何有效管理IP地址。由于网络爬虫高频、大量的请求可能导致IP被封禁&#xff0c;因此合理的IP管理策略显得尤为重要…

简单的nvm语法

文章目录 导文常用的nvm语法 导文 nvm&#xff08;Node Version Manager&#xff09;是一个用于管理Node.js版本的工具&#xff0c;它提供了一些简单的命令来操作Node.js的安装、切换和管理。 常用的nvm语法 这些命令可以在终端中执行&#xff0c;以方便地进行Node.js版本的管…

汇编-DUP操作符

DUP操作符使用整数表达式作为计数器&#xff0c; 为多个数据项分配存储空间。 在为字符串或数组分配存储空间时&#xff0c;这个操作符尤其有用&#xff0c;并且可以使用初始化或非初始化数据&#xff1a; .data BYTE 20 DUP(0) ;20个字节&#xff0c;都等于0 BYTE 20 …