首页 > 编程语言 >计算空间物体包围球的两种算法实现

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

时间:2022-10-03 21:38:56浏览次数:51  
标签:DBL maxPoint vi 物体 minPoint 算法 MAX 包围 pointList

详细介绍了计算空间包围球的两种算法。

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方向上距离最远的两个点。以这三个距离最远的范围作为初始直径,这三个距离的中心点作为初始球心。

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

计算空间物体包围球的两种算法实现_算法

计算空间物体包围球的两种算法实现_算法_02

具体的算法代码实现:

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:高度图)


标签:DBL,maxPoint,vi,物体,minPoint,算法,MAX,包围,pointList
From: https://blog.51cto.com/u_15414551/5730472

相关文章

  • 浙江大学陈越老师《数据结构与算法》课程笔记
    目录1.1什么是数据结构1.1解决问题方法的效率1.2数据结构的定义1.3抽象数据类型1.2什么是算法1.2.1算法指标1.2.2复杂度的渐进表示法1.2.3例子—求最大连续子列和2......
  • AcWing算法提高课 龟速乘(防止由于MOD过大使乘法爆long long)
    在求a*b%MOD的时候,如果MOD>1e10,则即便使用a%MOD*b%MOD,依旧有可能会爆longlong故可以利用和快速幂相似的思想,将乘法按位转化为加法,避免报longlong龟速乘模板:LLSlowM......
  • 数据结构与算法分析——C语言描述(第9章 图论算法)*
    目录9.1若干定义图的表示9.1若干定义一个图(graph)\(G=(V,E)\)由顶点(vertex)的集\(V\)和边(edge)/弧(arc)的集\(E\)组成。每一条边就是一幅点对\((v,w)\),其中\(v,......
  • AcWing 算法提高课 拓展欧几里得算法 同余
    拓展欧几里得算法:1、模板:https://www.cnblogs.com/ydUESTC/p/16676229.html2、原理: 3、应用:拓展欧几里得算法解线性同余方程:  4、例题:(1)线性同余方程:https://w......
  • 数据结构与算法分析——C语言描述(第5章 散列)
    目录5.1一般想法5.2散列函数5.3分离链接法(separatechaining)5.4开放定址法(openaddressing)本章讨论散列表(hashtable)ADT,不过它只支持二叉查找树所允许的一部分......
  • 算法分析相关概念
    算法分析相关概念算法的时间复杂度时间复杂度的分析注意事项同一个算法用不同的语言实现,或者用不同的编译程序进行编译,或者在不同的计算机上运行时,效率均不相同。所以,......
  • 02 线性表 | 数据结构与算法
    1.线性表线性表的定义特点:存在唯一一个被称为第一个的数据元素存在唯一一个被称为最后一个的数据元素除了第一个元素之外,其他的数据元素都有唯一一个直接前驱除......
  • 01 入门 | 数据结构与算法
    1.数据数据:数据是指对客观事物进行记录并且可以可以鉴别的抽象符号数据元素:数据的基本单位,在计算机当中作为一个整体考虑数据对象:具有相同性质的数据元素的集合数据......
  • 自适应滤波之RLS算法
    前言LMS算法的主要优点在于它的计算简单,然而为此付出的代价是缓慢的收敛速度,特别是当自相关矩阵\(\pmb{\varGamma}_M\)的特征值具有较大范围时。从另一个观点来看,LMS算法......
  • 多点DLT (Direct Linear Transformation) 算法
    阅读前可以先参看上一篇代数视觉博客:四点DLT(DierctLinearTransformation)算法对于大于4个点的数据点来进行DLT算法变换,如果数据点的标注都十分准确,那么将所有......