LineSegmentIntersector::Intersections中ratio含义及LineSegmentIntersector相交点说明

news2025/3/1 0:56:09

osg用osgUtil库中的LineSegmentIntersector、IntersectionVisitor类来求线段和三维模型的交点

如下代码:

#include <QtCore/QCoreApplication>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers> 
#include <osgViewer/CompositeViewer> 
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/LineSegmentIntersector>
#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);

   // geode1->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 0.1, 0.1, 20)));
    return geode1;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, 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());
    viewer1->setUpViewInWindow(200, 200, 800, 600, 0);

    return viewer1->run();
}

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

Vec3(0, 0,15)

 终点坐标如下:

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

同时构建了一个长方体,长方体中心位于原点,长、宽、高、分别为:5、4、3。

效果如下(注意:为了便于观察,我使这个长方体绕X轴逆时针转动了一定角度):

                                                                图1

 上述代码的第27、28行构造了一个求交器和求交访问器对象。通过求交器和求交访问器对象相互协同合作,再通过调用第31行代码accept函数,就能求出线段和长方体的交点,结果如下:

图2 

  其中ratio含义如下:                      

                           ( Ls_z - Is_z )  / Line_Z_Length

其中Ls_z表示线段起始点的z坐标值;Is_z表示线段和长方体相交时,长方体在交点处的z坐标;Line_Z_Length表示线段在Z轴的总长度。上例子,线段起点z坐标为15,线段在Z轴的总长度为15 -(-15) = 30,由图2知道,第1个交点的长方体z坐标为3,则第1个ratio为: 

                   ( 15 - 3 ) / 30 = 0.4

       同样地,可以算出最后一个交点的ratio为:                    

                   [ 15 - (-3 )] / 30 = 0.6

当把第27行线段的起始点、终止点坐标换成如下代码:

osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegmentIntesector = new osgUtil::LineSegmentIntersector(osg::Vec3(1, 5, 2), osg::Vec3(15, 0, -2));

则结果如下:

图3 

 则根据上面提到的计算ratio方法,线段起点z坐标为2,线段在Z轴的总长度为2 -(-2) = 4,由图3知道,第1个交点的长方体z坐标为1.2,则第1个ratio为: 

                       (2 - 1.2) / 4.0 =  0.2

在平时的开发中,可以根据ratio知道交点占据整个z轴的比例,即占据厚度的比例。同理,第2个ratio为:

                           ( 2 - 0.857143 ) / 4 = 0.285714

       在平时的开发中,可以根据ratio知道交点占据整个z轴的比例,即占据厚度的比例。

      在图2中,可以看到第1、2个交点是同一个点;第3、4个交点也是同一个点,为何出现两个相同的交点?下面分析如下:

       通过断点跟进到底层源码发现:虽然长方体6个面是四边形,但OPenGl是通过绘制两个三角形来实现一个四边形的。即长方体上顶面、下底面的四边形绘制如下:

 图4

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

       如果把上面代码的第13行改为如下:


    auto box1 = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 0.1, 0.1, 20))

即把长方体宽、高尽量小,则结果如下(注意:为了便于观察,我使这个长方体绕X轴逆时针转动了一定角度):

 图5

可以看到,长方体上顶面和直线的交点只有一个,下底面和直线的交点符合前文提到的三角形描述,输出2个相同的交点值,长方体上顶面和下底面都平行于水平面,应该说上顶面和下底面没啥区别,都应该输出2个相同的交点值才行,跟踪到LineSegmentIntersector.cpp文件的intersect函数:

void intersect(const osg::Vec3& v0, const osg::Vec3& v1, const osg::Vec3& v2)
    {


          ....... // 其它代码略
              if ((u + v) > det)
            {
                return;       // 上顶面本来应该输出2个相同交点,但有一个三角形检测,从这里返回了
            }

           ....... // 其它代码略
   }

上顶面本来应该输出2个相同交点,但上顶面有一个三角形检测时,从return返回了,导致交点没插入交点容器,里面的算法不是很懂,希望懂的人留言交流,感谢了!。

           通过测试发现,只要长方体长、宽、高小于1时,都会存在这个问题。

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

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

相关文章

Duboo介绍与入门

文章目录 1、Dubbo的前世今生2、Dubbo的快速入门2.1、Dubbo的基本架构2.2、Nacos2.3、管理后台2.4、入门案例2.4.1、服务提供者搭建环境代码实现配置文件 2.4.2、服务消费者搭建环境代码实现配置文件 最后说一句 1、Dubbo的前世今生 2011年10月27日&#xff0c;阿里巴巴开源了…

Vue项目解决跨域问题

跨域&#xff08;Cross-Origin&#xff09;是指在浏览器中运行的 JavaScript 代码试图访问不同源的资源时所遇到的一类限制问题。不同源是指协议&#xff08;http、https&#xff09;、域名&#xff08;example.com、google.com&#xff09;、端口号&#xff08;80、8080&#…

双时间维度,你的时间管理大师丨三叠云

双时间维度 路径 表单 >> 表单设计 功能简介 「甘特图视图」新增 双时间维度设置 的配置项。 为了解决日常任务管理中对于“计划时间”维度的时间设置问题&#xff0c;【时间设置】项增加了【双时间维度设置】的配置项&#xff0c;用户开启后可以设置 计划开始时间 …

Matlab 牛顿迭代法(1)牛顿法

一、牛顿迭代公式 1、定义 2、原理推导 泰勒公式&#xff1a; 常用的8个泰勒公式&#xff1a; 推导&#xff1a; 将f(x)f(x)在Xk 处的泰勒公式展开&#xff1a; f(x)f(Xk)f(Xk)(X-Xk) f(Xk)/2 *(x-Xk)^2.......... 我们吧线性的一部分先拿出来&#xff1a;f(x)f(Xk)f(X…

【python知识】容器对象的推导式

一、说明 Python 推导式&#xff0c;是针对容器对象&#xff08;列表,字典&#xff0c;集合&#xff0c;元组&#xff09;的产生方式的语句。它可以从一个数据序列构建另一个新的数据序列的结构体。 Python 支持各种数据结构的推导式&#xff1a; 列表(list)推导式字典(dict)推…

【Java|golang】1048. 最长字符串链

给出一个单词数组 words &#xff0c;其中每个单词都由小写英文字母组成。 如果我们可以 不改变其他字符的顺序 &#xff0c;在 wordA 的任何地方添加 恰好一个 字母使其变成 wordB &#xff0c;那么我们认为 wordA 是 wordB 的 前身 。 例如&#xff0c;“abc” 是 “abac”…

拍卖小程序开发:从需求分析到设计实现

在当今数字时代&#xff0c;拍卖小程序已经成为了一个重要的销售和交易工具。拍卖小程序的开发不仅能够提供高效的销售渠道&#xff0c;还能够为用户提供全新的购物体验。因此&#xff0c;开发一个拍卖小程序成为了许多商家的首要任务。 拍卖小程序的开发可以帮助商家拓展销售…

uniapp打包

niapp 的打包首先要先配置&#xff0c;配置好了才能去进行打包&#xff0c;如图所示。 这只是第一步。 注意&#xff1a; 1.运行基础路径最好用 ./ &#xff0c;如果配置了其他请自行添加路径。 2.由于uniapp 的特性&#xff0c;所以导致了不支持 history 模式&#xff0c;…

第13届蓝桥杯国赛真题剖析-2022年5月29日Scratch编程初中级组

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第127讲。 第13届蓝桥杯Scratch国赛真题&#xff0c;这是2022年5月29日举办的全国总决赛&#xff0c;比赛仍然采取线上…

三分钟教你看懂 spring 官方文档

新手如何学会查看官方文档API 首先进入官网&#xff1a;这里以 spring boot 为例 &#xff0c;进入spring 官方地址 我们进入 spring boot 这里我们要看文档当然是要 learn 了&#xff0c;所以点进去。 我需要的东西在 IO 模块里面&#xff0c;点 IO 进入 发送邮件是不是有了…

python+nodejs+php+springboot+vue 高校大学生创业管理系统

本论文主要论述了如何使用java语言开发一个高校创新创业管理系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;将论述高校创新创业管理系统的当前背景以及系统开发的目的&#xff0c;后续章节将…

node注册和登录你真的清楚了吗?

文章目录 1.创建数据表1.1 创建用户表 2安装并配置mysql文件2.1安装mysql模块2.2 在db index中 3.注册功能3.1检测表单数据合法3.2判断用户占用3.3 密码加密3.4 插入用户封装错误处理函数 4.登录功能4.1 登录密码的判断4.2 生成token字符4.3 解析token中间件 1.创建数据表 1.1…

AD9208子卡设计资料: 2 路 2.6GSPS/3GSPS AD 采集、2 路 12.6G DA 回放、高性能时钟发生器HMC7044 -FMC 子卡模块

板卡概述 FMC123 是一款基于 FMC 标准规范&#xff0c;实现 2 路 14-bit、3GSPSADC 采集功能、2 路 16-bit 12.6GSPS 回放子卡模块。该模块遵循 VITA57.1 标准&#xff0c;可直接与 FPGA 载卡配合使用&#xff0c;板卡 ADC 器件采用 ADI 公司的 AD9208 芯片&#xff0c;&…

如何在Linkedin领英上找客户

LinkedIn是很多想要获客的朋友&#xff0c;不错的选择&#xff0c;它是一家全球职业社交平台&#xff0c;目前全球会员人数已达6亿之多。在领英&#xff0c;我们可以轻松打造职业形象、获取商业洞察、拓展职业人脉并发现更多职业机遇。 Linkedin主要的作用有以下四点 &#xf…

API 文档管理得这么玩,才会效率加倍

随着互联网的迅速发展&#xff0c;越来越多的企业和开发者开始采用 API 接口作为数据交换和服务调用的标准方式。为了保证API接口的可靠性、稳定性和可维护性&#xff0c;API 文档管理变得愈发重要。 API 文档管理的重要性 API 文档管理是指在开发过程中&#xff0c;对API接口…

Seurat -- ScaleData学习

brief seurat提供了一个教学&#xff0c;其中global scale normalization之后又对数据进行了scale。 默认是对上一步 selected highly variable features进行scale。 概要图以及系列博文可以参见链接。 如果是 SCTransform则不需要手动运行这一步。 下面是就是教程提供的流程…

为什么软件iic需要用开漏输出和上拉电阻

1、疑惑&#xff1a; 不知道大家有没有这种疑惑&#xff0c;在软件iic的配置过程当中&#xff0c;有些时候要输出高低电平&#xff0c;为什么使用开漏输出而不是推挽输出&#xff1f; 2.推挽输出和开漏输出的区别 推挽输出: 输出逻辑0&#xff0c;则N-MOS激活&#xff1b;输…

<C++>类和对象-上

目录 前言 一、类的引入 二、类的定义 1.类的两种定义方式 三、类的访问限定符及封装 1.访问限定符 2.封装 四、类的作用域 五、类的实例化 六、类对象模型 1.计算类对象的大小 2 类对象的存储方式猜测 3. 结构体内存对齐规则 七、this指针 1. 引入 2 this指针的特性 总结 前言…

ChatGPT帮你调用PID算法【结合代码】

目录 PID算法是一种控制算法 下面分别介绍PID算法中的三个参数 MATLAB代码实现PID MATLAB代码实现PID PID算法是一种控制算法 用于控制系统的稳定性和精度。PID算法的名称来源于其三个组成部分&#xff1a;比例&#xff08;P&#xff09;、积分&#xff08;I&#xff09;和微…

CVE漏洞复现-CVE-2021-22205 GitLab未授权 RCE

CVE-2021-22205 GitLab未授权 RCE 漏洞背景和描述 2021年4月15日&#xff0c;GitLab官方发布安全补丁更新修复了GitLab命令执行漏洞&#xff08;CVE-2021-22205&#xff09;。由于GitLab中的ExifTool没有对传入的图像文件的扩展名进行正确处理&#xff0c;攻击者通过上传特制…