如何在python中找到矩形交集?

时间:2014-01-07 11:27:03

标签: python algorithm geometry gis computational-geometry

具有与(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))
]

算法不能天真,需要快速。

我尝试了什么:

  1. 找到python区间树实现 - 我找不到任何好的东西......
  2. 我试过这个回购:https://github.com/booo/rectangleintersection/blob/master/rectangleIntersection.py,它适用于上面的示例,但却失败了真实世界的数据。
  3. 我通读了scikit imageShapely文档,但没有找到矩形交集的算法。

1 个答案:

答案 0 :(得分:3)

可以将相交矩形视为图形中的连接节点,将“传递”相交矩形设置为Connected Components。为了找出哪些矩形相交,我们首先进行Plane Sweep。为了使这个速度相当快,我们需要一个Interval TreeBanyan提供了一个:

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 <= righttop <= bottom。 IOW,它们所在的坐标系的原点位于左上角,而不是像几何中常见的左下角。