LineSegmentIntersectorUtils::IntersectFunctor::intersect源码分析

目录

1. 概述

2. 代码环境说明

3. intersect函数分析


1. 概述

      osgUtil::Intersector有几个子类,如下:

每个子类表示不同的求交器。所谓求交器就是判定和物体相交的类,通过这些类可以很方便的得出交点、实现拾取功能等。LineSegmentIntersector类是osgUtil::Intersector其中的一个子类,其表示线段求交器,即通过线段和三维场景中的某个物体相交,该类一般和osgUtil::IntersectionVisitor即求交访问器类一起使用,从而得出交点、实现拾取功能等。关于osgUtil::LineSegmentIntersector类的具体应用及源码分析,请参考如下博文:

  • LineSegmentIntersector::Intersections中ratio含义及LineSegmentIntersector相交点说明。
  •  osgUtil::LineSegmentIntersector类源码分析(一)。
  • osgUtil::LineSegmentIntersector类源码分析(二)。

2. 代码环境说明

环境说明如下:

  • OpenSceneGraph-3.6.2。
  • Windows 10。
  • Microsoft Visual Studio Community 2022 (64 位) - Current版本 17.5.5。

说明:本博文是基于OpenSceneGraph的3.6.2版本来讲解的,读者版本可能和本人的版本不同,

           故本人的源码或功能可能在细节上和读者的有所不同。

3. intersect函数分析

本节讲解的LineSegmentIntersectorUtils::IntersectFunctor::intersect函数源码如下: 

void intersect(const osg::Vec3& v0, const osg::Vec3& v1, const osg::Vec3& v2){if (_settings->_limitOneIntersection && _hit) return;// const StartEnd startend = _startEndStack.back();// const osg::Vec3& ls = startend.first;// const osg::Vec3& le = startend.second;Vec3 T = _start - v0;Vec3 E2 = v2 - v0;Vec3 E1 = v1 - v0;Vec3 P =  _d ^ E2;value_type det = P * E1;value_type r,r0,r1,r2;const value_type epsilon = 1e-10;if (det>epsilon){value_type u = (P*T);if (u<0.0 || u>det){return;}osg::Vec3 Q = T ^ E1;value_type v = (Q*_d);if (v<0.0 || v>det){return;}if ((u + v) > det){return;}value_type inv_det = 1.0/det;value_type t = (Q*E2)*inv_det;if (t<0.0 || t>_length) return;u *= inv_det;v *= inv_det;r0 = 1.0-u-v;r1 = u;r2 = v;r = t * _inverse_length;}else if (det<-epsilon){value_type u = (P*T);if (u>0.0 || u<det) return;Vec3 Q = T ^ E1;value_type v = (Q*_d);if (v>0.0 || v<det) return;if ((u+v) < det) return;value_type inv_det = 1.0/det;value_type t = (Q*E2)*inv_det;if (t<0.0 || t>_length) return;u *= inv_det;v *= inv_det;r0 = 1.0-u-v;r1 = u;r2 = v;r = t * _inverse_length;}else{return;}// Remap ratio into the range of LineSegmentconst osg::Vec3d& lsStart = _settings->_lineSegIntersector->getStart();const osg::Vec3d& lsEnd = _settings->_lineSegIntersector->getEnd();double remap_ratio =  ((_start - lsStart).length() + r*_length)/(lsEnd - lsStart).length();Vec3 in = lsStart*(1.0 - remap_ratio) + lsEnd*remap_ratio; // == v0*r0 + v1*r1 + v2*r2;Vec3 normal = E1^E2;normal.normalize();LineSegmentIntersector::Intersection hit;hit.ratio = remap_ratio;hit.matrix = _settings->_iv->getModelMatrix();hit.nodePath = _settings->_iv->getNodePath();hit.drawable = _settings->_drawable;hit.primitiveIndex = _primitiveIndex;hit.localIntersectionPoint = in;hit.localIntersectionNormal = normal;if (_settings->_vertices.valid()){const osg::Vec3* first = &(_settings->_vertices->front());hit.indexList.reserve(3);hit.ratioList.reserve(3);if (r0!=0.0f){hit.indexList.push_back(&v0-first);hit.ratioList.push_back(r0);}if (r1!=0.0f){hit.indexList.push_back(&v1-first);hit.ratioList.push_back(r1);}if (r2!=0.0f){hit.indexList.push_back(&v2-first);hit.ratioList.push_back(r2);}}_settings->_lineSegIntersector->insertIntersection(hit);_hit = true;}

代码段1

为了分析该函数,就得写一个例子,让该例子的调用能进入到这个函数,从而实现断点调试,这样分析才高效、明白。 如下为测试用的例子代码:

#include <osgViewer/Viewer>
#include <osgUtil/IntersectionVisitor>
#include<osg/ShapeDrawable>
#include<iostream>//创建盒子
osg::ref_ptr<osg::Geode> createBox()
{osg::ref_ptr<osg::Geode> geode1 = new osg::Geode;auto box1 = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 10.0, 8.0, 6.0));geode1->addDrawable(box1);return geode1;
}int main(int argc, char* argv[])
{osg::ref_ptr<osgViewer::Viewer> viewer1 = new osgViewer::Viewer;osg::ref_ptr<osg::Group> group1 = new osg::Group;osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegmentIntesector = new osgUtil::LineSegmentIntersector(osg::Vec3(0, 0, 15), osg::Vec3(0, 0, -15));osg::ref_ptr<osgUtil::IntersectionVisitor> intersectionVisitor1 = new osgUtil::IntersectionVisitor(lineSegmentIntesector);group1->addChild(createBox());group1->accept(*intersectionVisitor1.get());osgUtil::LineSegmentIntersector::Intersections intersections;//输出交点intersections = lineSegmentIntesector->getIntersections();osgUtil::LineSegmentIntersector::Intersections::iterator iter;for (iter = intersections.begin(); iter != intersections.end(); ++iter){std::cout << "ratio:" << "   " << iter->ratio << "    x:" << iter->getWorldIntersectPoint().x() << "    y:" << iter->getWorldIntersectPoint().y() << "    z:" << iter->getWorldIntersectPoint().z() << std::endl;}viewer1->setSceneData(group1.get());return viewer1->run();
}

代码段2

代码段2构建了一条线段,线段起始坐标如下:

osg::Vec3(0, 0,15)

终点坐标如下:

osg::Vec3(0, 0, -15)

同时构建了一个长方体,长方体中心位于原点,长、宽、高、分别为:5、4、3。效果如下(注意:为了便于观察,我使这个长方体绕X轴逆时针转动了一定角度):

上述代码的第21、22行构造了一个求交器和求交访问器对象。通过求交器和求交访问器对象相互协同,再通过调用第25行代码accept函数,就能求出线段和长方体的交点。在代码段1设置断点,当启动该例子时,就能进入到intersect函数并停下来。代码段1的功能是求出线段和图元的交点信息。关于该段代码判断线段和面的交点及如何求出交点的算法,请参考:

射线和三角形的相交检测(ray triangle intersection test)

需要说明的是:虽然长方体6个面是四边形,但OPenGl是通过绘制两个三角形来实现一个四边形的。以长方体上顶面、下底面的四边形绘制为例说明如下:

通过在for循环中循环2次绘制两个三角形从而形成四边形(四边形由两个三角形拼接而成,在底层硬件实现上,大部分多边形的绘制是分割为三角形进行绘制的,这样效率要高些)。第1次循环绘制v0v2v1(或v0v3v2)三角形,此时检测到线段和该三角形交于A点;第2次循环绘制v0v3v2(或v0v2v1)三角形,此时又检测到线段和该三角形交于A点。

           在代码段1中_start表示线段起点被裁剪到最小外接包围盒的起点坐标,本例为osg::Vec3(0, 0,3)而 

_settings->_lineSegIntersector->getStart() 

则是线段原始起点坐标,本例为osg::Vec3(0, 0,15)。关于线段起点是如何转化为裁剪起始点的,请参考:osgUtil::LineSegmentIntersector类源码分析(二) 。对于知道线段的起点S和终点E,显然方向向量为D=E−S。这时,根据线段的向量方程,线段上某一点P为:

P = S + t*D

其中t的范围为[0, 1]。当t=0时是起点S;当t=1时是终点E;当t为(0,1)时是SE之间的一点。代码段1中t值的含义和这里的t意义相同,即表示位于_length之间的某点,而_length则表示线段裁剪起点到线段裁剪终点的长。

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

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

相关文章

Unity动画系统(3)---融合树

6.1 动画系统基础2-6_哔哩哔哩_bilibili Animator类 using System.Collections; using System.Collections.Generic; using UnityEngine; public class EthanController : MonoBehaviour { private Animator ani; private void Awake() { ani GetComponen…

跟李沐学AI:模型选择、过拟合和欠拟合

目录 训练误差和泛化误差 验证数据集和测试数据集 K-则交叉验证 模型总结 过拟合和欠拟合 模型容量 模型容量的影响 估计模型容量 数据复杂度 拟合总结 训练误差和泛化误差 训练误差&#xff1a;模型在训练数据上的误差 泛化误差&#xff1a;模型在新数据上的误差 …

我无法给博客园出钱,那我就出点建议吧

相信这张图大家都已经看见过了&#xff0c;从去年就传出博客园经营困难的情况&#xff0c;其实很多平台&#xff0c;不止是博客园&#xff0c;包括现在国内的很多公司都一样&#xff0c;经营是一件大难题&#xff0c;但很多公司我们不知道&#xff0c;悄无声息的倒下了。而博客…

泛微e-cology WorkflowServiceXml SQL注入漏洞(POC)

漏洞描述&#xff1a; 泛微 e-cology 是泛微公司开发的协同管理应用平台。泛微 e-cology v10.64.1的/services/接口默认对内网暴露&#xff0c;用于服务调用&#xff0c;未经身份认证的攻击者可向 /services/WorkflowServiceXml 接口发送恶意的SOAP请求进行SQL注入&#xff0c;…

Nginx优化与防盗链(企业网站架构部署与优化)

Nginx网页优化与防盗链 本章结构 隐藏版本号&#xff1a; 首先进入nginx的配置文件&#xff1a; vim /usr/local/nginx/conf/nginx.conf 添加这个语句&#xff0c;重启服务后生效。 重启服务后生效&#xff1b; 如果想把nginx名称都给改了&#xff0c;需要修改nginx的源代码…

STM32使用Wifi连接阿里云

目录 1 实现功能 2 器件 3 AT指令 4 阿里云配置 4.1 打开阿里云 4.2 创建产品 4.3 添加设备 5 STM32配置 5.1 基础参数 5.2 功能定义 6 STM32代码 本文主要是记述一下&#xff0c;如何使用阿里云物联网平台&#xff0c;创建一个简单的远程控制小灯示例。 完整工程&a…

Flink底层原理解析:案例解析(第37天)

系列文章目录 一、flink架构 二、Flink底层原理解析 三、Flink应用场景解析 四、fink入门案例解析 文章目录 系列文章目录前言一、flink架构1. 作业管理器&#xff08;JobManager&#xff09;2. 资源管理器&#xff08;ResourceManager&#xff09;3. 任务管理器&#xff08;Ta…

【数学建模】高温作业专用服装设计(2018A)隐式差分推导

为方便计算&#xff0c;对区域进行离散化处理&#xff0c;采用隐式差分格式进行离散计算。隐式差分格式如图&#xff1a; 每层材料内部 对第 j j j层材料: 其中&#xff0c; λ j \lambda_j λj​表示第 j j j层的热扩散率&#xff0c; c j c_j cj​表示第 j j j层的比热容…

RFID(NFC) CLRC663非接触读取芯片GD32/STM32 SPI读取

文章目录 基本介绍硬件配置连接硬件连接详解程序代码代码解释 基本介绍 CLRC663 是高度集成的收发器芯片&#xff0c;用于 13.56 兆赫兹的非接触式通讯。CLRC663 收发器芯片支 持下列操作模式 • 读写模式支持 ISO/IEC 14443A/MIFARE • 读写模式支持 SO/IEC 14443IB • JIS X…

全网超详细Redis主从部署(附出现bug原因)

主从部署 整体架构图 需要再建两个CentOs7,过程重复单机部署 http://t.csdnimg.cn/zkpBE http://t.csdnimg.cn/lUU5gLinux环境下配置redis 查看自己ip地址命令 ifconfig 192.168.187.137 进入redis所在目录 cd /opt/software/redis cd redis-stable 进入配置文件 vim redi…

【JavaEE精炼宝库】 初识网络原理——网络通信基础 | 协议

文章目录 一、网络发展史1.1 独立模式&#xff1a;1.2 网络互连&#xff1a;1.3 局域网&#xff08;LAN&#xff09;&#xff1a;1.4 广域网&#xff08;WAN&#xff09;&#xff1a; 二、网络通信基础2.1 IP地址&#xff1a;2.2 端口号&#xff1a; 三、协议3.1 协议的概念&am…

Python基础语法篇(上)

Python基础语法&#xff08;上&#xff09; 一、基知二、基本数据类型&#xff08;一&#xff09;标准数据类型&#xff08;二&#xff09;数据类型转换 三、字符串基本操作&#xff08;一&#xff09;字符串的索引和切片&#xff08;二&#xff09;字符串的拼接 三、运算符四、…

在golang中Sprintf和Printf 的区别

最近一直在学习golang这个编程语言&#xff0c;我们这里做一个笔记就是 Sprintf和Printf 的区别 fmt.Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。 fmt.Printf 根据格式化参数生成格式化的字符串并写入标准输出。由上面就可以知道&#xff0c;fmt.Sprintf返回的…

AI第二课堂第一次笔记

conda的使用 在输入cmd进入终端后&#xff0c;使用命令 conda create -n env_name python3.10 创建环境 命令 conda activate env_name 打开环境&#xff0c;如&#xff1a;使用 conda deactivate退出指令 2.python一些常见操作 python中的文件打开与关闭 调开源的库 p…

C++--lambda表达式

介绍 一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。和函数类型,lambda有一个返回值,一个参数列表和一个函数体,但比函数多一个捕获列表。具体形式如下: [捕获列表](参数列表) ->返回值类型 {函数体}其中:捕获列表:可以捕获定义lam…

NineData全面支持PostgreSQL可视化表结构设计

“PostgreSQL 是最像 Oracle 的开源关系型数据库“&#xff0c;也正因为如此&#xff0c;很多企业都青睐 PostgreSQL&#xff0c;拿它当成 Oracle 的替代品。所以毫无疑问&#xff0c;目前 PostgreSQL 在企业中非常常见。 对于直接接触 PostgreSQL 的开发人员而言&#xff0c;…

60K起?“软件安全岗”比“网络安全岗”薪资高在哪里?

在网络世界的江湖中&#xff0c;“软件安全”与“网络安全”这两大“武林高手”都肩负着守护数字领域和平的重任。不过&#xff0c;眼尖的小伙伴们可能发现了&#xff0c;软件安全岗位的薪资待遇往往比网络安全岗位要丰厚那么一些&#xff0c;这到底是为啥呢&#xff1f;今天&a…

使用ETLCloud实现MySQL数据库与StarRocks数据库同步

在现代数据架构中&#xff0c;数据同步是保证数据一致性和分析准确性的关键步骤之一。本文将介绍如何利用ETLCloud技术实现MySQL数据库与StarRocks数仓数据库的高效数据同步&#xff0c;以及其在数据管理和分析中的重要性。 数据同步的重要性 在数据驱动的时代&#xff0c;企…

【紫光同创盘古PGX-Nano教程】——(盘古PGX-Nano开发板/PG2L50H_MBG324第十三章)蓝牙透传实验例程说明

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 适用于板卡型号&#xff1a; 紫光同创PG2L50H_MBG324开发平台&#xff08;盘古PGX-Nano&#xff09; 一&#xff1a;…

OZON成本低卖价高产品,OZON单价高产品

Top1 Crocs鞋扣配件 Джиббитсы набор украшения для обуви крокс значки на crocs клипсы аксессуары украшение для сабо бутылка вина бокал 商品id&#xff1a;1409545850…