【FastCAE源码阅读9】鼠标框选网格、节点的实现
一、VTK的框选支持类vtkInteractorStyleRubberBandPick
FastCAE的鼠标事件交互类是PropPickerInteractionStyle,它扩展自vtkInteractorStyleRubberBandPick。vtkInteractorStyleRubberBandPick类可以实现鼠标框选物体,默认情况下按下键盘r键开启框选模式,这时拖动鼠标可拾取物体。VTK官网有其例子:HighlightSelection。
二、FastCAE框选产品设计
我们看FastCAE的鼠标拾取产品设计。其只支持框选网格点与网格单元,几何点、线、面都不支持。框选网格单元效果如下:
在VTK的给的案例中,按r键是为了打开vtkInteractorStyleRubberBandPick类的框选开关,设置vtkInteractorStyleRubberBandPick字段CurrentMode=1(VTKISRBP_SELECT),表示开启框选模式。VTK中vtkInteractorStyleRubberBandPick.cxx源码如下:
void vtkInteractorStyleRubberBandPick::OnChar()
{switch (this->Interactor->GetKeyCode()){case 'r':case 'R':// r toggles the rubber band selection mode for mouse button 1if (this->CurrentMode == VTKISRBP_ORIENT){this->CurrentMode = VTKISRBP_SELECT;}else{this->CurrentMode = VTKISRBP_ORIENT;}break;case 'p':case 'P':{vtkRenderWindowInteractor* rwi = this->Interactor;int* eventPos = rwi->GetEventPosition();this->FindPokedRenderer(eventPos[0], eventPos[1]);this->StartPosition[0] = eventPos[0];this->StartPosition[1] = eventPos[1];this->EndPosition[0] = eventPos[0];this->EndPosition[1] = eventPos[1];this->Pick();break;}default:this->Superclass::OnChar();}
}
而在FastCAE框选时,不需要按下r键,其原因在用切换拾取模式时,直接改掉了CurrentMode的值,源码如下(注意看这个函数最后一行):
void PropPickerInteractionStyle::setSelectModel(int m)
{_selectModel = (SelectModel)m;this->CurrentMode = 0;if (_actor != nullptr)_actor->GetProperty()->DeepCopy(_property);_actor = nullptr;_preGeoSeltctActor = nullptr;_selectItems.clear();emit grabKeyBoard(false);switch (_selectModel){case ModuleBase::MeshNode:case ModuleBase::MeshCell:case ModuleBase::GeometryWinPoint:case ModuleBase::GeometryWinCurve:case ModuleBase::GeometryWinSurface:case ModuleBase::GeometryWinBody:emit grabKeyBoard(true);break;case ModuleBase::GeometryPoint:case ModuleBase::GeometryCurve:case ModuleBase::GeometrySurface:case ModuleBase::GeometryBody:break;case ModuleBase::BoxMeshNode: // 当选择方式是框选时,直接设置开始框选case ModuleBase::BoxMeshCell:case ModuleBase::DrawSketch:this->CurrentMode = 1;break;}
}
这种设计的好处是不用按键盘进行交互,但造成激活框选按钮之后,视图的角度无法更改。本来按住左键拖拽可以旋转视图的,打开框选之后就失效了。
其框选还有一个比较严重的问题:框选会同时拾取物体的表面与背面单元,效果如下:
这种效果惊不惊喜,意不意外!?很多场景下,这种拾取是不满足要求的。进一步分析其框选逻辑就很好理解这种现象了。
三、框选计算逻辑
PropPickerInteractionStyle::OnLeftButtonUp()处理鼠标抬起事件,框选计算哪些物体要被选中的逻辑也在这里被触发。
void PropPickerInteractionStyle::OnLeftButtonUp()
{vtkInteractorStyleRubberBandPick::OnLeftButtonUp();if (_selectModel == None && !_mouseMoved)emit this->clearAllHighLight();if ((_selectModel != BoxMeshCell) && (_selectModel != BoxMeshNode) && (_selectModel != DrawSketch))return;if (this->CurrentMode == 0)return;// _selectItemIDs->SetNumberOfValues(0);_selectItems.clear();int *endPos = this->GetInteractor()->GetEventPosition();_endPos[0] = endPos[0];_endPos[1] = endPos[1];// qDebug() << "end " << _endPos[0] << " " << _endPos[1];if (_selectModel != DrawSketch){vtkActor *ac = nullptr;vtkAreaPicker *areaPicker = dynamic_cast<vtkAreaPicker *>(this->GetInteractor()->GetPicker());ac = areaPicker->GetActor();if (ac == nullptr)return;}switch (_selectModel){case ModuleBase::BoxMeshNode: // 计算哪些节点被选中boxSelectMeshNode();break;case ModuleBase::BoxMeshCell: // 计算哪些单元要被选中boxSelectMeshCell();break;case ModuleBase::DrawSketch:_coordinate->SetCoordinateSystemToDisplay();_coordinate->SetValue(endPos[0], endPos[1], 0);double *d = _coordinate->GetComputedWorldValue(_renderer);emit mouseReleasePoint(d);break;}_mouseMoved = false;_leftButtonDown = false;
}
boxSelectMeshNode()、boxSelectMeshCell()函数分别哪些节点、单元要被拾取。
void PropPickerInteractionStyle::boxSelectMeshNode()
{emit clearAllHighLight(); // 清除掉当前高亮_selectItems.clear(); // 清理当前选择项// Forward eventsint range[4];this->getBoxRange(range); // 获取框选矩形的坐标vtkActorCollection *actors = _renderer->GetActors(); // 获取当前的场景中所有actoractors->InitTraversal();const int nac = actors->GetNumberOfItems();for (int i = 0; i < nac; ++i) // 对Actor进行遍历{vtkActor *actor = actors->GetNextActor();if (actor == nullptr)if (!actor->GetVisibility())continue;if (!actor->GetPickable())continue;vtkMapper *mapper = actor->GetMapper();if (mapper == nullptr)continue;vtkDataSet *dataset = mapper->GetInputAsDataSet();if (dataset == nullptr)continue;vtkDataArray *IDS = dataset->GetPointData()->GetArray("IDS"); // 提取Actor的点数据if (IDS == nullptr)continue;this->selectMesh(dataset, range);}emit highLight(&_selectItems);
}void PropPickerInteractionStyle::selectMesh(vtkDataSet *dataSet, int *range)
{vtkRenderer *render = this->GetInteractor()->GetRenderWindow()->GetRenderers()->GetFirstRenderer();vtkSmartPointer<vtkCoordinate> coordinate = vtkSmartPointer<vtkCoordinate>::New();coordinate->SetCoordinateSystemToWorld();coordinate->GetComputedDisplayValue(render);if (_selectModel == BoxMeshNode){vtkDataArray *ids = dataSet->GetPointData()->GetArray("IDS"); // 获取点集const int npoint = dataSet->GetNumberOfPoints();for (int i = 0; i < npoint; ++i){double coor[3];dataSet->GetPoint(i, coor); // 获取点的坐标coordinate->SetValue(coor); // 将点的坐标设置给coordinateint *va = coordinate->GetComputedDisplayValue(render); // 计算屏幕坐标if (isPointInRange(va, range)) // 是否在鼠标框内部{double *k_id = ids->GetTuple2(i); // 看不懂?_selectItems.insert(k_id[0], k_id[1]);}}}else if (_selectModel == BoxMeshCell){vtkDataArray *ids = dataSet->GetCellData()->GetArray("IDS"); // 获取cell数据const int ncell = dataSet->GetNumberOfCells();for (int i = 0; i < ncell; ++i) // 遍历cell{vtkCell *cell = dataSet->GetCell(i); // 当前的celldouble pcenter[3] = {0};cell->GetParametricCenter(pcenter); // 获取当前cell的中心点参数坐标int subid;double coor[3];double w[100];cell->EvaluateLocation(subid, pcenter, coor, w); // 根据参数坐标获取中心点世界空间坐标coordinate->SetValue(coor);int *va = coordinate->GetComputedDisplayValue(render); // 计算屏幕坐标if (isPointInRange(va, range)) // 屏幕坐标是否在选择框内{double *k_id = ids->GetTuple2(i);_selectItems.insert(k_id[0], k_id[1]);}}}
}
根据以上代码,框选点时,直接根据点坐标计算其投影到屏幕上的坐标,判断是否在选择框内。单元是判断中心点是否在选择框内部。因为投影之后,丢弃了深度方向的信息,没有考虑物体的遮挡信息,所以框选时表面、背面均可选择。而且其计算框选时遍历所有网格,没有借助一些加速结构,如BVH树等,造成框选效率较低,当网格数量较多时,这种方式很慢。
总结:
FastCAE的框选逻辑过于简单,只是demo阶段,实际的CAE软件的拾取逻辑要远比这复杂。
相关文章:

【FastCAE源码阅读9】鼠标框选网格、节点的实现
一、VTK的框选支持类vtkInteractorStyleRubberBandPick FastCAE的鼠标事件交互类是PropPickerInteractionStyle,它扩展自vtkInteractorStyleRubberBandPick。vtkInteractorStyleRubberBandPick类可以实现鼠标框选物体,默认情况下按下键盘r键开启框选模式…...

【ArcGIS处理】行政区划与流域区划间转化
【ArcGIS处理】行政区划与流域区划间转化 引言数据准备1、行政区划数据2、流域区划数据 ArcGIS详细处理步骤Step1:统计行政区划下子流域面积1、创建批量处理模型2、添加批量裁剪处理3、添加计算面积 Step2:根据子流域面积占比均化得到各行政区固定值 参考…...

Session、Token、Jwt三种登录方案介绍
新开发一个应用首先要考虑的就是登录怎么去做,登录本身就是判断一下输入的用户名和密码与系统存储的是否一致,但因为Http是无状态协议,用户请求其它接口时是怎么判断该用户已经登录了呢?下面聊一个三种实现方案。 一、传统sessio…...

Linux操作系统使用及C高级编程-D5Linux shell命令(进程管理、用户管理)
进程管理 查看进程ps 其中ps -eif可显示父进程 实时查看进程top 按q退出 树状图显示进程pstree 以父进程,子进程以树状形式展示 发送信号kill kill -l:查看都有哪些信号 9:进程终止 kill不指定信号,默认发送的是15信号SIGT…...

【TDSQL-PG数据库简单介绍】
TDSQL-PG数据库简单介绍 TDSQL-PGTDSQL-PG 设计目标 TDSQL-PG 腾讯 TDSQL-PG 分布式关系型数据库是一款面向海量在线实时分布式事务交易和 MPP 实时数据分析 通用型高性能数据库系统。 面对应用业务产生的不定性数据爆炸需求,不管是高并发的交易还是海量的实时数据…...

【文件包含】metinfo 5.0.4 文件包含漏洞复现
1.1漏洞描述 漏洞编号————漏洞类型文件包含漏洞等级⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐漏洞环境windows攻击方式 MetInfo 是一套使用PHP 和MySQL 开发的内容管理系统。MetInfo 5.0.4 版本中的 /metinfo_5.0.4/about/index.php?fmodule文件存在任意文件包含漏洞。攻击者可利用漏洞读取网…...

差分信号的末端并联电容到底有什么作用?
差分信号的末端并联电容到底有什么作用? 在现代电子系统中,差分信号是一种常见的信号形式,它们通过两根互补的信号线传输信号,具有较低的噪声和更高的抗干扰能力。然而,当差分信号线长度较长或者遇到复杂的电路环境时&…...

pandas教程:GroupBy Mechanics 分组机制
文章目录 Chapter 10 Data Aggregation and Group Operations(数据汇总和组操作)10.1 GroupBy Mechanics(分组机制)1 Iterating Over Groups(对组进行迭代)2 Selecting a Column or Subset of Columns (选中…...

通过右键用WebStorm、Idea打开某个文件夹或者在某一文件夹下右键打开当前文件夹用上述两个应用
通过右键用WebStorm、Idea打开某个文件夹或者在某一文件夹下右键打开当前文件夹用上述两个应用 通过右键点击某个文件夹用Idea打开 首先打开注册表 win R 输入 regedit 然后找到HKEY_CLASSES_ROOT\Directory\shell 然后右键shell 新建一个项名字就叫 Idea 第一步…...

Android 10.0 framework层设置后台运行app进程最大数功能实现
1. 前言 在10.0的定制开发中,在系统中,对于后台运行的app过多的时候,会比较耗内存,导致系统运行有可能会卡顿,所以在系统优化的 过程中,会限制后台app进程运行的数量,来保证系统流畅不影响体验,所以需要分析下系统中关于限制app进程的相关源码来实现 功能 2.framewo…...

如何快速找到华为手机中下载的文档
手机的目录设置比较繁杂,尤其是查找刚刚下载的文件,有时候需要捣鼓半天,如何快速找到这些文件呢?以下提供了几种方法: 方法一: 文件管理-》搜索文档 方法二: 文件管理-》最近 方法三…...

iceoryx(冰羚)-Architecture
Architecture 本文概述了Eclipseiceoryx体系结构,并解释了它的基本原理。 Software layers Eclipse iceoryx所包含的主要包如下所示。 接下来的部分将逐一简要介绍组件及其库。 Components and libraries 下面描述了不同的库及其名称空间。 ### iceoryx hoofs …...

LeetCode2-两数相加
大佬解法 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val x; }* }*/ class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {ListNode pre new ListNode(0);ListNo…...

css 灰质彩色的边框
border: 4px solid transparent; background-color:#fff; background-clip: padding-box,border-box; background-origin:padding-box, border-box; background-image: linear-gradient(90deg,#F5F6FA,#F5F6FA 42%,#F5F6FA),linear-gradient(151deg,#33e9bf,#c7e58a,#b1e8cc);...

OpenCV实现手势音量控制
前言: Hello大家好,我是Dream。 今天来学习一下如何使用OpenCV实现手势音量控制,欢迎大家一起前来探讨学习~ 一、需要的库及功能介绍 本次实验需要使用OpenCV和mediapipe库进行手势识别,并利用手势距离控制电脑音量。 导入库&am…...

pytorch 深度学习之余弦相似度
文章目录 用处定理代码F.normalize() 和 F.norm() 的区别 用处 此方法特别重要,经常可以用来修改论文,提出创新点. 定理 余弦相似度是通过计算两个向量之间的夹角余弦值来衡量它们的相似性。给定两个非零向量 x 和 y,它们之间的余弦相似度…...

Postman的常规断言/动态参数断言/全局断言
近期在复习Postman的基础知识,在小破站上跟着百里老师系统复习了一遍,也做了一些笔记,希望可以给大家一点点启发。 断言,包括状态码断言和业务断言,状态码断言有一个,业务断言有多个。 一)常规的…...

ruoyi若依前端请求接口超时,增加响应时长
问题: 前端查询请求超时 解决: 找到request.js的timeout属性由10秒改成了20秒,因为默认是10秒,请求肯定是超出了10秒 祝您万事顺心,没事点个赞呗,关注一下也行啊,有啥要求您评论哈...

贪吃蛇小游戏
一. 准备工作 首先获取贪吃蛇小游戏所需要的头部、身体、食物以及贪吃蛇标题等图片。、 然后,创建贪吃蛇游戏的Java项目命名为snake_game,并在这个项目里创建一个文件夹命名为images,将图片素材导入文件夹。 再在src文件下创建两个包&#…...

cocos----1
1 前言 刚体(Rigidbody)是运动学(Kinematic)中的一个概念,指在运动中和受力作用后,形状和大小不变,而且内部各点的相对位置不变的物体。在 Unity3D 中,刚体组件赋予了游戏对…...

第十九章绘图
Java绘图类 Graphics 类 Grapics 类是所有图形上下文的抽象基类,它允许应用程序在组件以及闭屏图像上进行绘制。Graphics 类封装了Java 支持的基本绘图操作所需的状态信息,主要包括颜色、字体、画笔、文本、图像等。 Graphics 类提供了绘图常用的…...

rpmbuild 包名 version 操作系统信息部分来源 /etc/rpm/macros.dist
/etc/rpm/macros.dist openeuler bclinux src.rpm openssl-1.1.1f-13.oe1.src.rpm 打包名称结果 openeuler openssl-1.1.1f-13.aarch64.rpm bclinux openssl-1.1.1f-13.oe1.bclinux.aarch64.rpm 验证 修改openeuler配置文件macros.dist 重新在openeuler上执行rpmbuild…...

【Linux专题】SFTP 用户配置 ChrootDirectory
【赠送】IT技术视频教程,白拿不谢!思科、华为、红帽、数据库、云计算等等https://xmws-it.blog.csdn.net/article/details/117297837?spm1001.2014.3001.5502 红帽认证 认证课程介绍:红帽RHCE9.0学什么内容,新版有什么变化-CSDN…...

openssl+ DES开发实例(Linux)
文章目录 一、DES介绍二、DES原理三、DES C实现源码 一、DES介绍 DES(Data Encryption Standard)是一种对称密钥加密算法,最初由 IBM 设计,于1977年成为美国国家标准,用于加密非机密但敏感的政府数据。DES 使用相同的…...

结构体几种实用的用法
结构体的初始化 结构体的初始化是指在声明结构体变量时,为其成员变量赋初值。结构体的初始化可以通过以下几种方式实现: 1. 在声明结构体变量的同时进行初始化: struct Student { char name[20]; int age; float score; } student {…...

React Native 源码分析(四)—— TurboModules JSI通信机制
本文会详细分析React Native 基于JSI的通信方式,除不会涉及Hemers引擎部分,其余代码都会详细分析,但比较简单的,不会很啰嗦,可以说是网上最完整详细的分析文章,代码通过断点截图,可以更方便查看运行的过程 1、React Native 源码分析(一)—— 启动流程 2、React Nativ…...

【C#学习】ToString() 格式化数值
格式字符串采用以下形式:Axx,其中 A 为格式说明符,指定格式化类型,xx 为精度说明符,控制格式化输出的有效位数或小数位数。 格式说明符 说明 示例 输出 C 货币 2.5.ToString(“C”) ¥2.50 D 十进制数 25.…...

install YAPI MongoDB
docker 运行 mongodb sudo docker run -d \ --name mongodb \ --restart always \ --netdocker \ -p 27017:27017 \ -v ./db:/data/db \ -e MONGO_INITDB_DATABASEyapi \ -e MONGO_INITDB_ROOT_USERNAMEroot \ -e MONGO_INITDB_ROOT_PASSWORD123456 \ mongo…...

大数据Doris(二十三):取消导入与其他导入案例参考
文章目录 取消导入与其他导入案例参考 一、取消导入...

SQL-LABS
less8 and 11-- 12 发现存在注入点 接下来我们会接着用联合查询 和以往的题目不一样没显错位,也就是没有报错的内容,尝试用盲注 布尔型 length()返回长度 substr()截取字符串(语法substr&a…...