【问题标题】:Multiple Bounding Boxes containment detection algorithm多边界框包含检测算法
【发布时间】:2018-11-12 08:11:08
【问题描述】:

有谁知道多边界框包含检测算法(或实现参考),描述如下:

  1. 让我们收集 Axis Aligned Bounding Boxes,其中一些可能相交
  2. 和一个简单的 3D 形状,例如一个球体(或者它可以是另一个 AABB)。
  3. 我需要能够检测形状是否完全包含在 AABB-s 中的算法。换句话说,球体的任何部分都不在 AABB-s 之外。

问题是:在单个 AABB 中测试遏制很容易,但是存在形状可能在多个 AABB-s 之间拆分的情况,甚至可能与多个 AABB-s 相交但有些情况球体的一部分在外面。

【问题讨论】:

  • 您可以在每个 AABB 外部剪切查询形状,看看剩下的是否是空集。如果查询形状是 AABB 则更简单,但对于球体则有点棘手。

标签: algorithm geometry collision-detection computational-geometry containment


【解决方案1】:

受 Yves 递归扫描平面算法思想的启发,这里提供了一个更精细的版本,用于尝试在球体内找到未被任何给定框覆盖的点。

首先,我们必须找到 z 坐标的所有值,当沿 z 轴移动时,相应平面中的完全覆盖范围会发生变化。这可能发生在

  • 球体的最大和最小 z 坐标(即 z_center +/- 半径)
  • 所有框的最大和最小 z 坐标
  • 球体的所有相交圆/弧与所有长方体面的最大和最小 z 坐标

一旦这些 z 值被收集、排序并限制在球体的 z 范围内,我们就会将球体的 z 范围划分为多个区间。我们在每个 z 间隔(例如中心)inside 中选择一个值来检查相应平面中的覆盖范围。每个 2D 切口都可以类似于 3D 问题来解决 - 从而将覆盖检查减少到一组 1D 问题。在一维情况下,我们有一个区间而不是球体或圆,我们也有区间而不是盒子或矩形。因此,球体对盒子的覆盖问题被简化为一个区间对一组区间的一组普通覆盖问题。

main 函数的实现可能如下所示:

# if the n-dimensional sphere is not fully covered by the boxes
# find a point inside the sphere but outside the boxes
# by a recursive sweep-plane algorithm.
# center: n-dimensional point
# radius: real value
# boxes: list of n-dimensional boxes (each box is a list of n intervals)
def getUncoveredSphereWitness(center, radius, boxes):
    sphereLimitsN = [center[-1]-radius, center[-1]+radius]
    if len(center) == 1: 
        # 1D case
        witness = getUncoveredIntervalWitness(sphereLimitsN, [box[0] for box in boxes])
        return [witness] if witness is not None else None

    boxLimitsN = sum([b[-1] for b in boxes], [])
    cutLimitsN = getCutLimitsN_boxes(center, radius, boxes)
    limitsN = list(set(sphereLimitsN + boxLimitsN + cutLimitsN))
    limitsN.sort()

    # get centers of relevant intervals
    coordNValsToCheck = []
    for b in limitsN:
        if b > sphereLimitsN[1]: break
        if b > sphereLimitsN[0]:
            coordNValsToCheck.append((bPrev+b)/2.)
        bPrev = b

    for z in coordNValsToCheck:
        # reduce to a problem of with 1 dimension less
        centerN1, radiusN1 = cutSphereN(center, radius, z)
        boxesN1 = cutBoxesN(boxes, z)
        witness = getUncoveredSphereWitness(centerN1, radiusN1, boxesN1)
        if witness is not None:
            return witness+[z] # lift witness to full dimension by appending coordinate

    return None

【讨论】:

  • 感谢 Yves Daoust 和 coproc 提供此解决方案。这看起来很有希望,我会尝试一下。
【解决方案2】:

IMO,您可以通过扫描平面方法来做到这一点。

按顶部和底部“应用程序”(z 坐标)对所有 AABB 进行排序。现在考虑一个从一个面到另一个面向下移动的水平面,每次更新一个活动列表(即与平面相接的那些框)。一个框在其顶面进入列表并在其底面离开。

由平面组成的场景部分将由一组矩形和可能的圆形组成。在每一步,圆都需要完全包含在矩形的联合中。

请注意,您还需要在赤道附近的平面上停下来(这不会修改活动列表),因为球体是那里“最大的”。

这样做,您将初始问题转化为一组包含矩形和圆形的二维包含子问题。

遵循相同的原则,您可以通过扫描线技术解决后者,通过矩形顶部/底部的纵坐标对矩形进行排序并移动一个活动列表。在每一步中,iso-y 线的截面定义了一组线段,每个矩形一个,可能一个圆形,并且通过对 x 上的边界进行排序很容易证明包含。

换句话说,通过 3D 扫描过程,您可以分解棱柱板中的空间并构建与球体的交叉点。通过 2D 扫描过程,您可以将平面分解为矩形板,并构建与截面圆盘的交叉点。

【讨论】:

  • +1 用于应用递归扫描平面算法的优雅想法。但是由于您当前的版本由于多种原因(考虑到缺少球体/框的交叉点,在边界处而不是在框内进行切割)无法正常工作,因此我添加了一个新的解决方案来解决这些问题。
  • 非常有前途的方法。我会试试看。此外,不必为所有矩形应用扫描线。对单个球体矩形包含的快速测试将提供必须用于扫描步骤的矩形列表。
  • 我试图提出一个(反)示例,其中需要查看球体/盒子的交叉点 - 但尚未成功。它看起来像这样,而不是查看球体/盒子的交叉点,它真的足以在球体中心切入 - 这会带来巨大的性能提升。有一个合理的论点会很好......
  • @coproc:没有逃脱,每次更改部分时,您都需要执行圆形/矩形遏制测试。根本不需要 3D 球体/盒子测试。
  • 我实现了扫描平面方法。由于我有静态边界框和许多 3D 形状,因此我有准备步骤,其中计算部分一次,然后是每个形状的查询步骤。 @coproc 12 box cover 在未优化的第一个版本上需要 6ms。
【解决方案3】:

在代数上,这个问题可以表示为对实数的约束满足问题。点(x,y,z)在圆心坐标(cx,cy,cz)、半径r的圆内的条件是:

C :=  (x-cx)^2 + (y-cy)^2 + (z-cz)^2 - r^2 <= 0

点在 AABB 内的条件是:

B :=  x0 <= x /\ x <= x1 /\ y0 <= x /\ y <= y1 /\ z0 <= z /\ z <= z1

其中/\ 表示“和”,x0, x1, ..., z1 是实数。

现在给定一个圆圈和几个边界框,问题是约束列表是否

C /\ !(B1 \/ ... \/ Bn)

可以满足。如果是,则在球体内有一个点,但在任何 AABB 内都没有。由于只有三个变量x,y,z 和最多 2 个现有算法/库的多项式可以有效地解决这个问题。 (例如Z3,见intro)。

【讨论】:

  • 感谢您的回答,非常有趣的方法。我怀疑它可能会很慢,因为 CSP 求解器是非常通用的求解器。
  • 有针对特殊情况的特殊求解器。对于这个问题,可以应用“虚拟术语替换”(VST),它应该比一般求解器快得多。 Z3 已经为二次多项式实现了这种算法,并且似乎可以自动检测它是否可以应用。您的问题仍然比 VST 允许的一般设置更专业,但另一方面,AABB 对球体的覆盖仍然非常复杂,因此需要一些代数。
  • @Ross 在我的电脑上检查 12 个盒子是否覆盖了单位球体需要 30 - 50ms(使用 Z3 的 Python 接口)
  • 50ms 的遏制测试与交叉测试相比似乎很多。我的旧笔记本电脑上的 12 个盒子 - 1 个球体相交时间为 0.2 毫秒。我想部分原因是由于 Python 接口和求解器初始化。
猜你喜欢
  • 2015-02-02
  • 1970-01-01
  • 2013-04-06
  • 2016-04-30
  • 1970-01-01
  • 2015-02-01
  • 2014-02-04
  • 2013-12-09
  • 2014-04-23
相关资源
最近更新 更多