具有与(minx, miny, maxx, maxy)
形式的轴平行的矩形列表:
rectangles = [
Rectangle(90,40,110,70),
Rectangle(10,40,40,70),
Rectangle(75,60,95,80),
Rectangle(30,20,60,50),
Rectangle(100,20,130,50),
Rectangle(70,10,85,40)
]
我需要得到矩形组列表,其中每个矩形至少与另一个矩形相交:
[
(Rectangle(10,40,40,70), Rectangle(30,20,60,50)),
(Rectangle(70,10,85,40)),
(Rectangle(75,60,95,80), Rectangle(90,40,110,70), Rectangle(100,20,130,50))
]
算法不能天真,需要快速。
我尝试了什么:
答案 0 :(得分:3)
可以将相交矩形视为图形中的连接节点,将“传递”相交矩形设置为Connected Components。为了找出哪些矩形相交,我们首先进行Plane Sweep。为了使这个速度相当快,我们需要一个Interval Tree。 Banyan提供了一个:
from collections import defaultdict
from itertools import chain
from banyan import SortedDict, OverlappingIntervalsUpdator
def closed_regions(rects):
# Sweep Line Algorithm to set up adjacency sets:
neighbors = defaultdict(set)
status = SortedDict(updator=OverlappingIntervalsUpdator)
events = sorted(chain.from_iterable(
((r.left, False, r), (r.right, True, r)) for r in set(rects)))
for _, is_right, rect in events:
for interval in status.overlap(rect.vertical):
neighbors[rect].update(status[interval])
if is_right:
status.get(rect.vertical, set()).discard(rect)
else:
status.setdefault(rect.vertical, set()).add(rect)
# Connected Components Algorithm for graphs:
seen = set()
def component(node, neighbors=neighbors, seen=seen, see=seen.add):
todo = set([node])
next_todo = todo.pop
while todo:
node = next_todo()
see(node)
todo |= neighbors[node] - seen
yield node
for node in neighbors:
if node not in seen:
yield component(node)
rect.vertical
BTW是元组(rect.top, rect.bottom)
。
时间复杂度为O(n log n + k)
,其中n
是矩形的数量,k
是实际交叉点的数量。所以它非常接近最佳状态。
编辑:因为存在一些混淆,我需要补充一点,矩形应该有left <= right
和top <= bottom
。 IOW,它们所在的坐标系的原点位于左上角,而不是像几何中常见的左下角。