我有一大堆矩形,大小都相同。我生成的随机点不应该落在这些矩形中,所以我想做的是测试生成的点是否位于其中一个矩形中,如果是,则生成一个新点。
使用R-tree似乎可行,但它们实际上是用于矩形而不是点。我可以使用R-tree算法的修改版本,它也适用于点,但如果已经有一些更好的解决方案,我宁愿不重新发明轮子。我对数据结构不太熟悉,所以也许已经存在一些适用于我的问题的结构?
总之,基本上我要问的是,是否有人知道一个好的算法,在Python中有效,可用于检查一个点是否位于给定矩形集中的任何矩形中。
编辑:这是2D,矩形不会旋转。
答案 0 :(得分:8)
这个Reddit线程解决了你的问题:
如果你的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和Y值:对此进行快速测试表明是否需要进一步观察。
根据矩形覆盖的总表面积的多少,您可能能够找到包含矩形的非重叠子区域,然后您可以避免搜索那些不包含与矩形重叠的矩形的子区域这一点,在搜索过程中再次保存比较,代价是预先计算合适的数据结构。如果矩形集足够稀疏,则可能没有重叠,在这种情况下,这会退化为强力搜索。同样,如果矩形集非常密集,那么边界框中没有可以在不破坏矩形的情况下拆分的子范围。
但是,您也可以随意将边界区域分解为四分之一(每个方向的一半)。然后,您将使用一个框列表,其中包含的框比原始框中的框多(每个框的两个或四个框与任意边界之一重叠)。这样做的好处是,您可以从搜索中消除四个季度中的三个,从而减少总共进行的搜索量 - 以辅助存储为代价。
因此,有时空权衡取舍。并且预先计算与搜索权衡。如果你运气不好,预计算什么都没有(例如,只有两个盒子,并且它们在任一轴上都不重叠)。另一方面,它可以获得相当大的搜索时间效益。
答案 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