我有许多相互不相交的简单多边形,但有些多边形可能嵌入到其他多边形中。
例如:
+--------------------------------------------+
| |
| +----------------+ +--------+ |
| | | / | |
| | +--------+ | / | |
| | | | | / +----(2)-+ |
| | | | | / | |
| | +----(3)-+ | / | +---+ |
| | | +-----+ | | |
| +------------(2)-+ +(2)+ |
| |
+----------------------------------------(1)-+
如何找出所有多边形的“深度”?换句话说,如何找出多边形包含多少个多边形? “深度”是括号中的数字。
我可以计算多边形点在所有其他多边形内部的次数,但这具有二次复杂度。如何更快地计算这些深度?
答案 0 :(得分:2)
根据多边形的最小边界矩形,将多边形放入某种spatial lookup structure,例如R-tree。然后,您应该能够在O( n log n )中计算您所关注的包含关系。 (除非您处于病态情况下,多边形的许多最小边界矩形重叠,根据您的描述,这似乎不太可能。)
编辑添加:当然,您不依赖于R树来告诉您一个多边形是否在另一个内部(它基于最小边界矩形,因此它只能给您一个近似值)。您可以使用R树来廉价地识别候选内含物,然后以昂贵的方式验证(检查一个多边形中的点是否在另一个内部)。
答案 1 :(得分:0)
(这种方法遵循与@GarethRees类似的想法:首先,便宜地发现你不需要检查包含的多对多边形。一旦仍然需要检查的对数是可以接受的,进行确切的(昂贵的)几何检查。)
很容易计算每个多边形p的边界矩形,即左边,右边,顶部和底部,所以让我们先做。例如。 for left:p.L = min { x : (x,y) is a vertex of p }
时间是点数的线性。
为避免必须将每个多边形相互比较,可以将区域划分为2x2网格。假设区域的宽度和高度分别由Dx
和Dy
给出,那么您可以创建九组top,bottom,left,right,topright,topleft,bottomright,bottomleft,rest
并执行以下操作:
for p in polygons:
in_top = p.B > Dy/2
in_bottom = p.T < Dy/2
in_left = p.R < Dx/2
in_right = p.L > Dx/2
if in_top:
if in_left:
add p to topleft
elsif in_right:
add p to topright
else:
add p to top
elsif in_bottom:
if in_left:
add p to bottomleft
elsif in_right:
add p to bottomright
else:
add p to bottom
if in_right and not (in_top or in_bottom):
add p to right
elsif in_left and not (in_top or in_bottom):
add p to left
if not (in_top or in_bottom or in_left or in_right):
add p to rest
这又是线性时间。每个多边形都已被分类到最紧密的#34;包含部门。你有什么收获的?好吧,例如,您知道p
中的任何多边形left
都可能与集合right
存在任何包含关系,因此您无需进行比较他们。同样地,在bottomleft
和right
,bottomleft
和topleft
之间,依此类推。这是你的例子的样子:
Dx/2
+----------------------|---------------------+
| | |
| +----------------+ | +--------+ |
| | | | / | |
| | +--------+ | | / | |
|___|___|________|___|_|____ /__+===d(2)=+___|_ Dy/2
| | | | | | / | |
| | +---b(3)-+ | | / | +---+ |
| | | | +-----+ | | |
| +-----------c(2)-+ | e(2)+ |
| | |
+----------------------|----------------a(1)-+
所以rest = {a}, top = {}, bottom = {}, left = {b,c}, right = {d}
topleft = {}, topright = {}, bottomleft = {}, bottomright = {e}
所以基本上你现在需要比较(使用昂贵的精确检查)最多b
到c
,d
到e
和a
到所有其他人 - 事实上,如果您以聪明的方式订购支票,您不需要将a
与其他所有人进行比较,因为包含是可传递的,所以如果您注意到c
包括b
,a
包含c
,那么您无需检查a
是否包含b
。
另一点是你可以递归地应用上述推理。比如说集topright
对你来说太大了;然后你可以通过进一步划分该子区域来应用相同的技术(只需要保持正确的记账)。
答案 2 :(得分:0)
在我看来,你可以通过测试一个是否在另一个内部作为比较运算符来排除多边形。
假设我们定义了关系'&lt;'在多边形之间如下:A&lt; B iff A在B内。 如果A&lt; B和B&lt; C,然后A&lt; C(即如果多边形A在B内,B在C内,则A必须在C内)。现在,我们在任意多边形之间有一个严格的弱排序。
[编辑:你需要使用某种点内非凸多边形测试,但可能你已经这样做了。]
使用您最喜欢的基于比较的排序算法,根据此比较对多边形进行排序。例如,合并排序具有O(nlogn)比较的最坏情况时间复杂度,其中n是多边形的数量。
[编辑:这是重要的一步,因为它摆脱了二次复杂性。]
确保“最大”(即最外层)元素首先位于排序的多边形阵列上。 (如果需要,可以反转列表以实现此目的 - 它与多边形的数量呈线性关系)。
现在“最大”(即最外面)的多边形应该是第一个元素。
[编辑: 实际上,多边形已根据其深度进行了排序。但是,具有相同深度的两个多边形可能会以不同的顺序出现,具体取决于排序是否稳定。这对我们来说无关紧要;我们感兴趣的是深度的更改。]
我们现在将为每个多边形指定深度,如下所示。 首先,将每个的深度初始化为0([编辑:初始化为1,根据示例])。接下来,遍历排序列表,但这次只将每个元素p与下一个元素p + 1进行比较。如果(p + 1
答案 3 :(得分:0)
步骤1:将多边形定向在相同的方向,比如逆时针方向。
步骤2:对于需要计算“深度”的任何点(x,y),计算总匝数。这可以通过多种方式完成;实际上最快的是计算源自(x,y)的水平(或垂直)射线之间的SIGNED交叉点数。
特别是,每个多边形的深度将是其任何顶点的深度。
答案 4 :(得分:0)
在您的示例中,您描述了一个非凸多边形,因此其他人建议的rtree方法本身将不会有效。但是,只要您找到与rtree方法匹配的对象,就可以将其与其他检查结合使用,以查看多边形的顶点是否在另一个顶点内。这样可以减少必须进行“多边形中的点”检查的次数。
另一种方法是采用您的第一个想法-即检查每个多边形与每个其他多边形的顶点-并对其进行修改以缓存您已经计算的结果,并重新使用它们以减少时间复杂度。下面介绍的方法本质上是根据多边形本身构建树结构,而不是使用rtree。它本质上是一种不同的树结构,可用于非凸多边形。