从线上找到矩形的高效算法?

时间:2018-03-02 11:55:35

标签: python algorithm geometry computational-geometry rectangles

给定一个仅水平和垂直的路径列表(包含起点和终点坐标),如何找到它们形成的所有矩形?

详细说明:

  • 矩形的端点必须是其组成边的端点。即不需要从线的交叉点形成的矩形。
  • 给出了开始和结束的x,y,表示为每行的复数。
  • 输出应为四行,代表矩形的每个边

这是我的天真实施,太慢了。还有其他方法吗?

def find_rectangles(paths):
    vertical_paths = filter(lambda path: is_vertical(path), paths)
    horizontal_paths = filter(lambda path: is_horizontal(path), paths)

    vertical_paths.sort(key=lambda path: path.start.imag, reverse=True)
    horizontal_paths.sort(key=lambda path: path.start.real)

    h_pairs = []
    for i in range(0, len(horizontal_paths) - 1):
        for j in range(1, len(horizontal_paths)):
            if horizontal_paths[i].start.real == horizontal_paths[j].start.real and horizontal_paths[i].end.real == horizontal_paths[j].end.real:
                h_pairs.append((horizontal_paths[i], horizontal_paths[j]))

    v_pairs = []
    for i in range(0, len(vertical_paths) - 1):
        for j in range(1, len(vertical_paths)):
            if vertical_paths[i].start.imag == vertical_paths[j].start.imag and vertical_paths[i].end.imag == vertical_paths[j].end.imag:
                v_pairs.append((vertical_paths[i], vertical_paths[j]))


    rects = []
    for h1, h2 in h_pairs:
        for v1, v2 in v_pairs:
            if h1.start == v1.start and v1.end == h2.start and h1.end == v2.start and h2.end == v2.end:
                rects.append(Rect(h1.start, h1.end, h2.end, h2.start))

    return rects

修改:(所有建议的改进)

主要区别在于我将所有水平边的端点存储在一个集合中,因此查找它们是O(1):

def find_rectangles(paths):
    vertical_paths = [path for path in paths if is_vertical(path)]
    horizontal_paths_set = set([(path.start, path.end) for path in paths if is_horizontal(path)])

    vertical_paths.sort(key=lambda pair: path.start.imag, reverse=True)

    v_pairs = [pair for pair in list(itertools.combinations(vertical_paths, 2)) if pair[0].start.imag == pair[1].start.imag and pair[0].end.imag == pair[1].end.imag]

    rects = []
    for v1,v2 in v_pairs:
        h1 = (v1.start, v2.start)
        h2 = (v1.end, v2.end)

        if(h1 in horizontal_paths_set and h2 in horizontal_paths_set):
            rects.append(Rect(h1[0], h1[1], h2[1], h2[0 ]))

    return rects

我的新代码运行速度要快得多,但它仍然是O(n2)的顺序。欢迎提出任何改进建议。

1 个答案:

答案 0 :(得分:1)

您可以放弃搜索v_pairs。您只需要知道是否可以关闭潜在的矩形(水平对)。

def find_rectangles(paths):
    vertical_paths = filter(lambda path: is_vertical(path), paths)
    horizontal_paths = filter(lambda path: is_horizontal(path), paths)

    vertical_paths.sort(key=lambda path: path.start.imag, reverse=True)
    horizontal_paths.sort(key=lambda path: path.start.real)

    potential_rectangles = []
    for i,h1 in enumerate(horizontal_paths[:-1]):
        for h2 in horizontal_paths[i+1:]:
            if ((h1.start.real == h2.start.real) 
                    and (h1.end.real == h2.end.real)):
                potential_rectangles.append((h1,h2,None,None))

    rectangles = []
    for v in vertical_paths:
        for i,(h1,h2,v1,v2) in enumerate(potential_rectangles):
            if v1 is None and v.start == h1.start and v.end == h2.start:
                potential_rectangles[i][2] = v
                if v2 is not None:
                    rectangles.append(potential_rectangles.pop(i))
                break
            if v2 is None and v.start == h1.end and v.end == h2.end:
                potential_rectangles[i][3] = v
                if v1 is not None:
                    rectangles.append(potential_rectangles.pop(i))
                break

    return rectangles

根据收到的数据,加速选择肯定有很大的潜力。例如,按长度排序路径。你能提供更多细节吗?

编辑后 Bisect比'快得多,但它需要一个有序的标量值列表。

相关问题