计算空间物体包围球的两种算法实现_charlee44的博客

news/2024/7/8 12:19:25/文章来源:https://www.cnblogs.com/hustshu/p/16733232.html

1. 概述

在进行二维空间几何运算的之前,往往会用包围盒进行快速碰撞检测,从而筛掉一些无法碰撞到的可能。而在三维中,比较常用的就是包围球了。当然,如何计算包围球是一个问题。

2. 详论

2.1. naive算法

一个最简单的思路就是,计算空间顶点在X、Y、Z方向上的最大值和最小值,那么就可以得到8个顶点组成的包围盒。取包围球中心为包围盒中心点,而包围球半径有的人认为可以取中心点到八个顶点的最大距离——这样其实并不严密。最好还是计算中心点到所有顶点距离的最大值:

void BoundingSphere::GetBoundingSphereNative(const std::vector<Vec3d>& pointList)
{if (pointList.empty()){return;}Vec3d minPoint(DBL_MAX, DBL_MAX, DBL_MAX);Vec3d maxPoint(-DBL_MAX, -DBL_MAX, -DBL_MAX);size_t vertexCount = pointList.size();for (size_t vi = 0; vi < vertexCount; vi++){if (minPoint.x() > pointList[vi].x()){minPoint.x() = pointList[vi].x();}if (minPoint.y() > pointList[vi].y()){minPoint.y() = pointList[vi].y();}if (minPoint.z() > pointList[vi].z()){minPoint.z() = pointList[vi].z();}if (maxPoint.x() < pointList[vi].x()){maxPoint.x() = pointList[vi].x();}if (maxPoint.y() < pointList[vi].y()){maxPoint.y() = pointList[vi].y();}if (maxPoint.z() < pointList[vi].z()){maxPoint.z() = pointList[vi].z();}}Vec3d naiveCenter = (maxPoint + minPoint) / 2;double naiveRadius = 0;for (size_t vi = 0; vi < vertexCount; vi++){naiveRadius = std::max(naiveRadius, (pointList[vi] - naiveCenter).length());}data = { naiveCenter.x(), naiveCenter.y(), naiveCenter.z(), naiveRadius };
}

这个算法的思路比较简单,所以称之为naive算法。

2.2. ritter算法

另外一种算法是一个名为ritter提出来的,所以称为ritter算法。

首先计算出X方向上距离最远的两个点,Y方向上距离最远的两个点以及Z方向上距离最远的两个点。以这三个距离最远的范围作为初始直径,这三个距离的中心点作为初始球心。

然后依次遍历所有点,判断点是否在这个包围球内。如果不在,则更新包围球。如下图所示:

imglink1

如果点P在我们的之前得到的包围球之外,那么延长点P与球心O的直线与球相较于T点,很显然,新的直径应该是点T与点P的一半:

R c u r r e n t = ∣ P T → ∣ 2 = ∣ O P → ∣ + ∣ O T → ∣ 2 R_{current} = \frac{|\overrightarrow{PT}|}{2} = \frac{|\overrightarrow{OP}| + |\overrightarrow{OT}|}{2} Rcurrent​=2∣PT ∣​=2∣OP ∣+∣OT ∣​

令点T与点P的中心点为S,也就是新的球心位置。关键就是求向量 O S → \overrightarrow{OS} OS ,从而将球心O移动到新的球心S。

显然,向量 O S → \overrightarrow{OS} OS 的距离还是很好求的,只新的包围球半径与之前包围球的半径之差:
∣ O S → ∣ = R c u r r e n t − R p r e v i o u s |\overrightarrow{OS}| = R_{current} - R_{previous} ∣OS ∣=Rcurrent​−Rprevious​

而向量 O P → \overrightarrow{OP} OP 是已知的,根据向量关系,可求得:
O S → = ∣ O S → ∣ ∣ O P → ∣ O P → \overrightarrow{OS} = \frac{|\overrightarrow{OS}|}{|\overrightarrow{OP}|}\overrightarrow{OP} OS =∣OP ∣∣OS ∣​OP

最后将之前的球心O移动向量 O S → \overrightarrow{OS} OS ,就是新的包围球的球心位置了。

具体的算法代码实现:

void BoundingSphere::GetBoundingSphereRitter(const std::vector<Vec3d>& pointList)
{//Vec3d minPoint(DBL_MAX, DBL_MAX, DBL_MAX);Vec3d maxPoint(-DBL_MAX, -DBL_MAX, -DBL_MAX);size_t minX = 0, minY = 0, minZ = 0;size_t maxX = 0, maxY = 0, maxZ = 0;size_t vertexCount = pointList.size();for (size_t vi = 0; vi < vertexCount; vi++){if (minPoint.x() > pointList[vi].x()){minPoint.x() = pointList[vi].x();minX = vi;}if (minPoint.y() > pointList[vi].y()){minPoint.y() = pointList[vi].y();minY = vi;}if (minPoint.z() > pointList[vi].z()){minPoint.z() = pointList[vi].z();minZ = vi;}if (maxPoint.x() < pointList[vi].x()){maxPoint.x() = pointList[vi].x();maxX = vi;}if (maxPoint.y() < pointList[vi].y()){maxPoint.y() = pointList[vi].y();maxY = vi;}if (maxPoint.z() < pointList[vi].z()){maxPoint.z() = pointList[vi].z();maxZ = vi;}}//double maxLength2 = (pointList[maxX] - pointList[minX]).length2();Vec3d min = pointList[minX];Vec3d max = pointList[maxX];{double yMaxLength2 = (pointList[maxY] - pointList[minY]).length2();if (maxLength2 < yMaxLength2){maxLength2 = yMaxLength2;min = pointList[minY];max = pointList[maxY];}double zMaxLength2 = (pointList[maxZ] - pointList[minZ]).length2();if (maxLength2 < zMaxLength2){maxLength2 = zMaxLength2;min = pointList[minZ];max = pointList[maxZ];}}//Vec3d ritterCenter = (min + max) / 2;double ritterRadius = sqrt(maxLength2) / 2;for (size_t i = 0; i < vertexCount; i++){Vec3d d = pointList[i] - ritterCenter;double dist2 = d.length2();if (dist2 > ritterRadius * ritterRadius){double dist = sqrt(dist2);double newRadious = (dist + ritterRadius) * 0.5;double k = (newRadious - ritterRadius) / dist;ritterRadius = newRadious;Vec3d temp = d * k;ritterCenter = ritterCenter + temp;}}data = { ritterCenter.x(), ritterCenter.y(), ritterCenter.z(), ritterRadius };
}

2.3. 其他

理论上来说,ritter算法的实现要优于naive算法,能够得到更加贴合的包围球。当然理论只是理论,具体的实现还要看最终的效果。根据文献2中所说,经过Cesium的比对测试,19%的情况下,ritter算法的效果比naive算法差;11%的情况下,ritter算法的效果会比naive算法好。所以在Cesium中,包围球的实现是把两者都实现了一遍,然后取半径较小的结果。

3. 参考

  1. 3D空间包围球(Bounding Sphere)的求法
  2. Cesium原理篇:3最长的一帧之地形(2:高度图)

本文转自 https://blog.csdn.net/charlee44/article/details/127044893,如有侵权,请联系删除。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux配置当前用户java环境

cd ~ ls -al 这里可以看到一个 .bash_profile 的文件 然后vim 它 vim .bash_profile 插入如下代码 PATH=$PATH:$HOME/binexport JAVA_HOME=/apps/upgrade_sjzx/jdk/jdk1.8.0_162export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jarexport PATH=$JAVA_HOME/b…

JAVA代码操作HDFS

1、客户端环境准备 &#xff08;1&#xff09;将Hadoop-2.9.2安装包解压到非中文路径&#xff08;例如&#xff1a;E:\hadoop-2.9.2&#xff09; &#xff08;2&#xff09; 配置HADOOP_HOME环境变量 &#xff08;3&#xff09; 配置Path环境变量。 &#xff08;4&#xff09;…

使用SqlSugar连接多个数据库(sqlserver,sqlite,mysql)

有时候&#xff0c;一个项目只有一个数据库&#xff0c;比如只有SQLite&#xff0c;或者MySQL数据库&#xff0c;那么我们只需要使用一个固定的数据库即可。但是一个项目如果写好了&#xff0c;有多个用户使用&#xff0c;但是多个用户使用不同的数据库&#xff0c;这个时候&am…

多测师肖sir_疑难杂症_linux中设置中文,数据库中插入中文

一、linux中如何切换出中文 讲解是Centos6.5版本 &#xff08;1&#xff09;第一步打开控制台输入安装中文输入法&#xff1a; yum install “Chinese Support” &#xff08;2&#xff09;查清自己目前的系统版本&#xff1a;cat /etc/issue 查看系统版本&#xff1a; 下载好…

操作系统漏洞利用思路

目录 前言&#xff1a; &#xff08;一&#xff09;漏洞发现工具 0x01、Goby 0x02、Nmap 1、vuln 2、vulscan 0x03 Nessus &#xff08;二&#xff09;漏洞利用 0x01、框架利用 0x02、单点EXP 0x03 搜索文章 &#xff08;三&#xff09;修补 1、打上补丁 2、关闭…

node.js基于微信小程序的外卖订餐系统 uniapp 小程序

美食是人类永恒的话题&#xff0c;无论是在古代还是现代人们对美食都有一种非常的热爱在里面&#xff0c;但是随着时代的发展&#xff0c;人们可能没有更多的时间去研究美食&#xff0c;很多时候人们在下班或者放学之后更希望通过网络来进行订餐&#xff0c;为此我开发了本基于…

顺序栈和链式栈(C++实现)

数据结构&#xff08;面向对象方法与C语言描述&#xff09;&#xff08;第2版&#xff09;顺序栈和链式栈内容整理 栈 栈&#xff08;stack&#xff09;可定义为只允许在表的末端进行插入和删除的线性表。允许插入和删除的一端叫做栈顶&#xff08;top&#xff09;&#xff0…

学习:网络基础知识 HTTP协议之请求报文

HTTP协议 和 安全版 HTTPS协议 HTTP(Hyper Text Transfer Protocol)超文本传输协议 HTTP协议 是基于TCP协议 默认端口是80 功能:用来规定客户端和服务端的数据传输格式 特点:基于请求与响应模式的、无状态、无连接的应用层协议 示例:粉色部分是请求 紫色是响应部分 HTTP请…

Pro09丨高频波动率RSJ与成交量因子迭代升级

量化策略开发&#xff0c;高质量社群&#xff0c;交易思路分享等相关内容 『正文』 ˇ 大家好&#xff0c;今天我们分享Pro系列第9篇量化策略及内容说明。 在2021年7月中&#xff0c;某开源平台发布一个研报策略复现文章&#xff0c;而后大家象征性的积极讨论了一番&#xf…

大裁员时代,我们究竟该如何提升自己?

我以为进大厂可以逃过 35 岁的坎儿&#xff0c;结果还没到 35 呢就遇上了大裁员。。。被裁的那一个月&#xff0c;我拿着公司给的 2N 在家躺了大半个月&#xff0c;刚开始是不甘&#xff0c;到后面每个月一万多的房贷催着我不得不重新审视自己&#xff0c;随后踏上了海投之路。…

贤鱼的刷题日常--P2671 [NOIP2015 普及组] 求和

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;学会求和题目 ✅创作者&#xff1a;贤鱼 &#x1f389;个人主页&#xff1a;贤鱼的个人主页 &#x1f525;专栏系列&#xff1a;c 求和题目[NOIP2015 普及组] 求和题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例…

电脑屏幕监控,员工行为监控,上网行为监控解决方案

本文镜像&#xff1a;https://linkpi.cn/archives/1612 本文链接&#xff1a;https://blog.csdn.net/weixin_45326556/article/details/127050574 电脑屏幕监控,员工行为监控,上网行为监控解决方案1. 背景2. 设备清单3. 设备连接示意图3.1 灵派编码器 USB摄像头方式3.2 灵派编…

C++运算符重载

运算符重载引入一.运算符重载是什么二.运算符重载的格式三.部分运算符重载的实现3.1 简单‘ ’ ‘ - ’ ‘ * ’运算符重载3.2 ,- - 运算符3.3 运算符3.4 <<&#xff0c;>>运算符四.运算符重载注意事项五.运算符重载的限制六.MyString的简单实现引入 对于基本类型…

java中的IO流

IO流1、File类1.1 获取文件或目录信息1.2 操作文件1.3 操作目录1.4 案例&#xff1a;递归列出目录的下一级1.5 案例&#xff1a;递归列出目录下的所有Java源文件2、IO流的分类和设计2.1 输出纯文本数据2.2 读取纯文本数据2.3 按行读取2.4 复制文件基本版2.5 复制文件提升效率版…

硬件基础:电路基础知识

电路的研究方式&#xff1a;从电路模型出发&#xff0c;研究电路基本理论、分析方法以及工程技术中典型类电路的特点和规律。 电路的四类知识 基础知识 电路模型&#xff0c;电路基本物理量&#xff0c;电路基本元件&#xff0c;基尔霍夫定律&#xff0c;磁路的基础知识。。。工…

CloudCompare——软件汉化

目录1.效果预览2.软件实现1.效果预览 如图所示&#xff0c;软件界面上显示内容翻译成中文。 2.软件实现 1、下载最新版本的CloudCompare&#xff0c;如图所示&#xff0c;下载箭头所指的任意一个版本即可。 官网下载链接&#xff1a;http://www.danielgm.net/cc/release/ …

数据分析:单元4 Matplotlib库入门

Matplotlib 可能是 Python 2D-绘图领域使用最广泛的套件。它能让使用者很轻松地将数据图形化&#xff0c;并且提供多样化的输出格式。在这里我将介绍一下它的相关知识&#xff0c;你可以在这里快速学会如何用它画出好看的数据图像&#xff0c;如果你想学习到更多的知识&#xf…

跟 HTML 说hello

目 录 ​1.HTML的骨架标签 2.迎接自己的第一个HTML网页 聊起前端,最最最基础的应该就是HTML语言了哈!首先, HTML 指的是超文本标记语言 (Hyper Text Markup Language)是用来描述网页的一种语言 。超文本的含义就在于它可以加入图片、声音、动画、多媒体等内容&#xff08…

8、React路由

1、介绍 SPA概念&#xff1a;单页Web应用&#xff08;single page web application&#xff09;&#xff0c;就是只有一张Web页面的应用&#xff0c;由一个主页面和多个页面片段组成&#xff0c;由JS控制页面片段的展示与否。整个页面不会刷新&#xff0c;只会做局部页面的更新…

第三章、运输层(重点知识梳理)

3.1概述和运输层服务 3.1.1运输层概述 运输层协议是为运行在不同主机上的应用进程之间提供逻辑通信 传输协议运行在端系统 发送方&#xff1a;将应用层的报文分成报文段&#xff0c;然后传递给网络层接收方&#xff1a;将报文段重组成报文&#xff0c;然后传递给应用层有多个传…