测试点是否在某个矩形中

时间:2009-12-13 21:17:31

标签: python algorithm point

我有一大堆矩形,大小都相同。我生成的随机点不应该落在这些矩形中,所以我想做的是测试生成的点是否位于其中一个矩形中,如果是,则生成一个新点。

使用R-tree似乎可行,但它们实际上是用于矩形而不是点。我可以使用R-tree算法的修改版本,它也适用于点,但如果已经有一些更好的解决方案,我宁愿不重新发明轮子。我对数据结构不太熟悉,所以也许已经存在一些适用于我的问题的结构?

总之,基本上我要问的是,是否有人知道一个好的算法,在Python中有效,可用于检查一个点是否位于给定矩形集中的任何矩形中。

编辑:这是2D,矩形不会旋转。

5 个答案:

答案 0 :(得分:8)

这个Reddit线程解决了你的问题:

I have a set of rectangles, and need to determine whether a point is contained within any of them. What are some good data structures to do this, with fast lookup being important?

如果你的Universe是整数,或者精度水平是众所周知的并且不是太高,你可以使用abelsson来自线程的建议,使用着色的O(1)查找:

  

像往常一样,你可以换空间   时间..这里是一个O(1)查找非常   低常数。 init:创建一个位图   大到足以包围所有矩形   具有足够的精度,初始化   它变黑了。着色所有像素   包含任何矩形白色。 O(1)   查找:点(x,y)是白色吗?如果   所以,一个矩形被击中了。

我建议你去那篇文章并完整阅读ModernRonin的答案,这是最受欢迎的答案。我把它贴在这里:

  

首先是微观问题。你有一个   任意旋转的矩形,和   点。是内在的重点   矩形?

     

有很多方法可以做到这一点。但   我认为最好的是使用2d   矢量交叉产品。首先,确保   存储矩形的点   按顺时针顺序。然后做矢量   与1)矢量交叉产品   由侧面的两个点组成   2)来自第一点的矢量   测试点的一面。校验   结果的标志 - 积极的是   在里面(右边),   消极是在外面。如果它在里面   四面都是,它在里面   长方形。或者相当于,如果是的话   在任何一方之外,它在外面   矩形。 More explanation here

     

此方法每次需要3次减法   vector *每侧2个向量,   每侧加一个十字产品   是三次乘法和两次加法。 11   每边翻牌,每人44次   矩形。

     

如果你不喜欢十字架产品,   然后你可以这样做:   找出铭文和   每个的外接圆圈   矩形,检查内部是否有点   刻有铭文的。如果是这样,它就在   矩形也是。如果没有,请检查是否   它在受限制之外   长方形。如果是这样的话,它就在外面了   矩形也是。如果介于两者之间   这两个圈子,你和你在一起   必须以艰难的方式检查它。

     

查找某个点是否在圆圈内   在2d中需要两次减法和两次减法   squarings(= multiplies),然后你   比较距离平方以避免   不得不做一个平方根。那是4   翻牌圈,时间两圈是8个翻牌圈 -   但有时你仍然不会知道。   这也假设你不付钱   任何CPU时间来计算   限定或刻录的圆圈,   这可能是也可能不是真的   关于你有多少预先计算   愿意在你的矩形集上做。

     

无论如何,它可能不是   测试反对意见的好主意   每个矩形,特别是如果你   他们有一亿人。

     

这给我们带来了宏观问题。   如何避免测试点   集合中的每个矩形?在   2D,这可能是quad-tree   问题。在3d中,什么是generic_handle   说 - 一个八叉树。在我的顶部   我可能会把它实现为   一个B+ tree。使用d = 5很诱人,   这样每个节点最多可以有4个   孩子们,因为那个地图很好   四叉树抽象。但如果   矩形的集合太大了   适合主存(不太可能   这些天),然后有节点   可能与磁盘块大小相同   要走的路。

     

注意恼人的堕落   例如,有些数据集有10个   几千个几乎相同的矩形   中心位于同一点。   :P

     

为什么这个问题很重要?它的   在计算机图形学中有用,可以检查   如果光线与多边形相交。即,   那只狙击步枪射击了你   击中你射击的人   在?它也用于实时地图   软件,比如GPS单位。全球定位系统   告诉你你的坐标,   但是地图软件必须找到哪里   那一点是大量的地图   数据,并且每次执行几次   第二

再次归功于ModernRonin ......

答案 1 :(得分:2)

对于与轴对齐的矩形,您只需要两个点(四个数字)来标识矩形 - 通常是左下角和右上角。确定给定点(X test ,Y test )是否与矩形重叠(X BL ,Y BL ,X TR ,Y TR )通过测试两者:

  • X test > = X BL && X test < = X TR
  • Y test > = Y BL && Y test < = Y TR

显然,要测试足够多的点,这可能相当耗时。那么,问题是如何优化测试。

显然,一个优化是为所有矩形(边界框)周围的框建立最小和最大X和Y值:对此进行快速测试表明是否需要进一步观察。

  • X test > = X min && X test < = X max
  • Y test > = Y min && Y test < = Y max

根据矩形覆盖的总表面积的多少,您可能能够找到包含矩形的非重叠子区域,然后您可以避免搜索那些不包含与矩形重叠的矩形的子区域这一点,在搜索过程中再次保存比较,代价是预先计算合适的数据结构。如果矩形集足够稀疏,则可能没有重叠,在这种情况下,这会退化为强力搜索。同样,如果矩形集非常密集,那么边界框中没有可以在不破坏矩形的情况下拆分的子范围。

但是,您也可以随意将边界区域分解为四分之一(每个方向的一半)。然后,您将使用一个框列表,其中包含的框比原始框中的框多(每个框的两个或四个框与任意边界之一重叠)。这样做的好处是,您可以从搜索中消除四个季度中的三个,从而减少总共进行的搜索量 - 以辅助存储为代价。

因此,有时空权衡取舍。并且预先计算与搜索权衡。如果你运气不好,预计算什么都没有(例如,只有两个盒子,并且它们在任一轴上都不重叠)。另一方面,它可以获得相当大的搜索时间效益。

答案 2 :(得分:0)

我建议您查看BSP trees(以及可能的四叉树或八叉树,该页面上可用的链接)。它们用于递归地划分整个空间,并允许您快速检查您需要检查的矩形点。

至少你只有一个巨大的分区,需要检查所有矩形,最多你的分区变得那么小,它们可以达到单个矩形的大小。当然,分区越精细,您需要走下树才能找到想要检查的矩形。

但是,您可以自由决定适合检查一个点的矩形数量,然后创建相应的结构。

注意重叠的矩形。由于BSP树无论如何都需要预先计算,因此您可以在此期间删除重叠,这样您就可以获得清晰的分区。

答案 3 :(得分:0)

你的R树方法是我所知道的最好的方法(这是我选择的四叉树,B +树或BSP树的方法,因为在你的情况下R树看起来很方便)。警告:我不是专家,尽管我记得高年级大学课程中的一些东西!

答案 4 :(得分:0)

为什么不尝试这个。计算和内存似乎都很轻松。

考虑将所有矩形投影到空间的基线上。将该行间隔表示为

 {[Rl1, Rr1], [Rl2, Rr2],..., [Rln, Rrn]}, ordered by increasing left coordinates. 

现在假设你的点是(x,y),在这个集合的左边开始搜索,直到你到达包含点x的行间隔。

如果没有,你的点(x,y)在所有矩形之外。

如果有人这样做,比如说[Rlk,Rrk],......,[Rlh,Rrh],(k <= h),那么只需检查y是否在任何这些矩形的垂直范围内。

完成。

祝你好运。

John Doner