【问题标题】:Detect overlapping of rectangular prisms检测矩形棱镜的重叠
【发布时间】:2011-05-15 11:51:33
【问题描述】:

给定一个 3D 坐标系和具有非负起点和非负尺寸的直角棱镜(例如,从 (0, 2, 5) 开始,尺寸为 (9, 20, 5)):我怎样才能最好地检查另一个直角棱镜与坐标系中已有的棱镜之一相交?最终,目标是对所有存在的棱镜执行此检查,能够测试一个应该足以完成此任务。

信息:起点和大小是非负长的三元组。我正在寻找一种速度适中的优雅解决方案。

我的项目是java,但任何数学公式、伪代码或描述都绰绰有余。

【问题讨论】:

  • 棱镜可以旋转吗?或者我们可以假设所有边都与轴正交/平行?

标签: algorithm math 3d collision-detection overlap


【解决方案1】:

适用于大型数据集的良好算法方法

将您的棱镜存储在R-Tree 中。对于矩形同轴棱镜,搜索和插入的顺序应该是log(n)

有一些用于 R-Trees 的 Python 包。使用Rtree 0.6.0,您的代码将非常简单:

>>> from rtree import Rtree
>>> idx = Rtree()
>>> minx, miny, maxx, maxy = (0.0, 0.0, 1.0, 1.0)
>>> idx.add(0, (minx, miny, maxx, maxy))
>>> list(idx.intersection((1.0, 1.0, 2.0, 2.0)))
[0L]
>>> list(idx.intersection((1.0000001, 1.0000001, 2.0, 2.0)))
[]

实用而快速的方法

将您的数据存储在sqlite 数据库中,可以使用很少的代码行在文件或内存中创建该数据库(有many java implementations)。创建名为prisms 的表,其列将是idmin_xmin_ymin_zmax_xmax_ymax_z。索引每一行。

插入是O(1),检查交叉点遵循Magnus Skog's approach,给定new_min_x, new_min_y, new_min_z, new_max_x, new_max_y, new_max_z

SELECT COUNT(*) FROM prisms
   WHERE (new_min_x BETWEEN min_x and max_x OR new_max_x BETWEEN min_x and max_x)
   AND   (new_min_y BETWEEN min_y and max_y OR new_max_y BETWEEN min_y and max_y)
   AND   (new_min_z BETWEEN min_z and max_z OR new_max_z BETWEEN min_z and max_z)

【讨论】:

  • +1 Samuel 正在使用 java,但在 java 世界中找到它的实现应该不是问题。
  • +1 但在我的情况下,我不能使用外部库,棱镜的数量非常有限,而且性能方面,这块可以使用较慢的算法。因此,就我而言,我认为我将采用更简单的实现方式,但请记住,尽管这种实现方式在大型数据集中的表现会优于它,而且这是一个很酷的新知识!
  • @Samuel:是否使用 R-trees 取决于您以及您的数据集有多大(以及多快或是否会发生变化)。
  • 另请注意,R-trees 用于空间数据库,因此这也是一种选择(将对象存储在空间数据库中,让数据库回答您的查询)。
  • @ypercube 是的,但我认为像 PostgreSQL+PostGIS 这样的东西对于这个问题来说是一个很长的问题。
【解决方案2】:

假设您有两个棱镜 A 和 B。如果 B 与 A 相交,则否定不完全向右、向左、向上、向下等。

if not (B.x > A.x+A.dx or B.x+B.dx < A.x or
        B.y > A.y+A.dy or B.y+B.dy < A.y or
        B.z > A.z+A.dz or B.z+B.dz < A.z)
        // B intersects A

【讨论】:

  • 检查每个现有的棱镜对于大型数据集可能效率不高。
  • @Adam:我听到了 :) 这当然是一种权衡。算法的复杂性会随着效率要求的提高而增加。
  • 我在对亚当的评论中解释了我的决定,我只是想从 stackoverflow 的角度来看,我应该将其作为答案,因为我将使用它,还是将亚当的答案作为答案对于查看此问题的未来用户?
  • @Magnus Skog 并不是要吹毛求疵,权衡是正确的。
  • @Samuel:我个人会选择我会使用的答案,因为它可以解决我的具体问题。如果替代答案同样正确或提供更多信息,他们很可能会得到很多支持,并且这些信息仍然存在供其他读者随意使用:)
【解决方案3】:

(0, 2, 5) 开始,大小为(9, 20, 5) 的棱镜在(9, 22, 10) 结束。

要检查重叠的棱镜(A 和 B),请使用它们的起点和终点。两个棱镜必须在所有维度上重叠。

要检查 X 维度的重叠,请使用:

If (A.startX <= B.endX) and (B.startX <= A.endX) 

因此:

If 
      (A.startX <= B.endX) and (B.startX <= A.endX) 
  and (A.startY <= B.endY) and (B.startY <= A.endY) 
  and (A.startZ <= B.endZ) and (B.startZ <= A.endZ) 
Then
    (A and B overlap)

当两个棱镜只有一个共同点时,上述检查将产生True。如果您不希望这样,并且您希望重叠空间不仅仅是一个点或一条线段或一个矩形表面,而是一个棱柱,那么将 &lt;= 替换为 &lt;

【讨论】:

  • 感谢您的贡献!
【解决方案4】:

与检查线段的方法相同。如果 B 的开头或结尾在 A 的开头和结尾之间,则它们重叠。

唯一的区别是它们必须在所有三个维度上重叠。

【讨论】:

  • If the start or end of B is between the start and end of A, they overlap :这是正确的,但另一个方向是不正确的!如果它们重叠,则 B 的开始或结束不必在 A 的开始和结束之间。
猜你喜欢
  • 1970-01-01
  • 2018-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-02
  • 1970-01-01
  • 2020-09-07
  • 2019-01-25
相关资源
最近更新 更多