如何计算包含其他边界球的最小边界球

15

我正在寻找一种算法,它可以计算包围一组其他边界球的最小边界球。我已经思考了一段时间,并提出了一些初步解决方案,但我不认为这些方案一定是最准确或最节省计算开销的(速度最快)。

第一个想法

我的第一个解决方案是最简单和朴素的一种,即将球心平均化以获得中心点,然后计算从计算出的中心到每个球心加其半径的距离的最大值作为半径。 因此,伪代码如下:

function containing_sphere_1(spheres)
  center = sum(spheres.center) / count(spheres)
  radius = max(distance(center, spheres.center) + radius)
  return Sphere(center, radius)
end

然而,我认为它的计算成本并不便宜,而且结果球体可能比需要的要大。

第二个想法

我的第二个想法是使用迭代算法来计算最小外接球。它是通过连续测试另一个球来计算的,如果测试的球在边界内,则什么也不做,否则从两个可用的球计算出新的边界球。新的边界球的中心点位于两个中心之间的向量的中点(如果将其延伸到球面上),半径是该线段长度的一半(从新的中心到任何一个球面)。

function containing_sphere_2(spheres)
  bounds = first(spheres)
  for each sphere in spheres
    if bounds does not contain sphere
      line = vector(bounds.center, sphere.center)
      extend(line, bounds.radius)
      extend(line, sphere.radius)
      center = midpoint(line)
      radius = length(line) / 2
      bounds = Sphere(center, radius)
    end
  end
  return bounds
end

一开始我认为这是一个可行的方法,因为它是迭代的,并且似乎相当逻辑一致,但是在阅读了一些资料之后,尤其是Emo Welzl的文章“Smallest enclosing disks (balls and ellipsoids)”,我不太确定了。

Welzl算法

据我所知,该算法的基础是可以通过最多4个点(位于包围球体表面上的点)来确定3维空间中一组点的最小包围球。因此,该算法采用迭代方法,首先选择4个点,然后测试其他点是否在其内部,如果不在,则构造包含新点的新的边界球体。

现在该算法严格处理点,但我认为它可以应用于处理球体,主要的问题在于在构造包围球体时要考虑半径。

回到问题

那么,对于给定的一组球体,创建最小包围球的“最佳”(即计算成本最小)算法是什么?

我描述的其中一个是答案吗?提供伪代码或算法将会很好。


似乎你的天真方法可以通过使用加权质心(按半径)而不是纯质心来实现。也就是说,边界球的中心应该比小球的中心更靠近大球的中心。 - Drew Hall
不幸的是,我认为天真的方法行不通,http://hacksoflife.blogspot.com/2009/01/randomized-bounding-spheres.html 似乎表明有很多反例会导致它失败。它会创建一个包围球,但不一定是最小的。 - Dominik Grabiec
这篇由Thomas Larsson于2008年发表的论文提供了一个有用的边界球算法参考书目(适用于点集合,而非球集合)。 - Gareth Rees
@Daemin 是的,我已经意识到了。我想知道你是否可以做内部和外部边界(即一个在正方形内部,一个包围着正方形),然后二进制分割(切割)这两者之间的距离,以查看所有球体完全被限制的点。至少起点已经确定了。必须承认,这不太可能是最优解。有趣的问题! - wmorrison365
4
原来Welzl算法对于球体并不适用,可以在我的论文中查看反例,链接为http://www.inf.ethz.ch/personal/emo/DoctThesisFiles/fischer05.pdf,第93页。然而,正如@hardmath所回答的那样,[CGAL](http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Bounding_volumes_ref/Class_Min_sphere_of_spheres_d.html)提供了一个非常快速的C++实现。 - Hbf
显示剩余3条评论
2个回答

11

从包围点到包围球的步骤并不简单,正如K. Fischer的论文中讨论Welzl算法(用于包围点)所解释的那样,“最小包围球的球”。请参见第5.1节。

第4章介绍了“包围点”的材料,然后第5章介绍了“包围球”。

Fisher论文中描述的算法已经在CGAL包中实现,自3.0版本发布以来,如果您只是寻找一个实现。


非常感谢您提供的文章链接,它是一篇很有价值的阅读材料,看起来非常全面。 - Dominik Grabiec
6
补充一下你非常准确的回答:CGAL实现了针对"球体中的最小球体"情况的浮点和精确算法实现。你不需要使用CGAL的全部内容,只需提取所需的头文件即可运行。 - 对于点集最小球的情况,有一个C++库可在https://github.com/hbf/miniball下载。 - Hbf

5
这是一种基于Ritter算法的快速、近乎最优的方法https://en.wikipedia.org/wiki/Bounding_sphere。对于每个球体,找到其最小/最大的x/y/z点。将这6个点放入一个桶中。当你完成所有N个球体时,你将拥有一个由6N个点组成的桶。使用任何已知算法为这些点找到一个包围球。
无论使用哪种算法,你得到的包围球很可能会稍微小一些。然后可以进行Ritter方法的第二次遍历,但使用球体的背面作为要测试的点。这里的“背面”指的是距离当前边界球体中心最远的球体表面上的点。如果一个球体的背面点在当前的边界球体之外,则将边界球体扩大以包含它。
除了6个极值点外,你还可以最初包含内切立方体的8个角落:
( [+/-]kR, [+/-]kR, [+/-]kR ),其中k=sqrt(3)/3。这样可以得到14个点,它们在地理上分布得相当均匀。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接