为由正方形组成的多边形添加方块

时间:2012-01-20 19:07:23

标签: python algorithm geometry computational-geometry

我有一个1 * 1多边形的集合,每个多边形由其边界(一组四个点)定义,我在我的代码示例中使用下面的函数 area()来创建这些。我希望将这些相邻的正方形组合成一个多边形,该多边形也根据其边界点定义。

我希望以强力的方式做到这一点,我首先添加两个相邻的1 * 1方块,使用下面的函数 join()创建一个更大的多边形,并按此顺序继续生长多边形。所以join的第一个参数是到目前为止的多边形,第二个参数是一个adjecent 1 * 1 square,我希望将其添加到多边形中。返回值是新多边形的边界,当前与新的1 * 1连接。

这是我到目前为止所得到的:

def join(current, new):
    """ current is the polygon, new the 1*1 square being added to it"""
    return get_non_touching_part_of_boundary(current, new)  + get_non_touching_part_of_boundary(new, current)

def get_non_touching_part_of_boundary(this, other):
    for i,point in enumerate(this):
        if point not in other and this[i-1] in other:
            break # start of non touching boundary from a clockwise perspective
    non_touching_part_of_boundary = []
    for point in this[i:] + this[:i]:
        if not point in other:
            non_touching_part_of_boundary.append(point)
    return non_touching_part_of_boundary    

def area(point):
    """ boundary defined in a clockwise fashion """
    return [point,(point[0],point[1]+1),(point[0]+1,point[1]+1),(point[0]+1,point[1])]

a = area((0,1))            # a assigned a 1*1 polygon
a = join(a, area((0,2)))   # a assigned a 2*1 polygon
a = join(a, area((1,2)))    
a = join(a, area((2,2)))    
a = join(a, area((2,1)))    
a = join(a, area((2,0)))    

print(a)

这给了我以下多边形形状(数字表示其组成方块的添加顺序):

234
1 5
  6

上面代码的打印输出给出:

[(2, 2), (1, 2), (1, 1), (0, 1), (0, 3), (3, 3), (3, 0), (2, 0)]

这是定义多边形边界所需的最小点数。

但是如果我通过 a = join(a,area((1,0)))再向这个形状添加一个方块,从而创建一个洞,我的算法就会崩溃:

234
1 5
 76

这是我的算法无法处理的另一个多边形:

123
 64
  5

任何人都可以帮助我吗?我希望多边形中的孔列在单独的列表中。

感谢!

1 个答案:

答案 0 :(得分:2)

我认为您的算法很难修复。考虑到例如向多边形添加单个方块可能会创建多个孔:

  xxx
  x x
xxx xxx
x  y  x
xxx xxx
  x x
  xxx

想象一下,例如,所有x都是“当前多边形”,然后你和y ...

通常,闭合区域由闭环集合定义,您只能使用单个列表,而只需使用更复杂的方法在循环之间创建零区域桥接。对我看来你正在寻找的东西的简单方法是截然不同的:

  1. 循环每个方格和每个方格:
  2. 如果广场在里面并且左边的方格是外面的(反之亦然)那么你知道你需要一个左边的墙
  3. 如果广场在里面并且上面的方格是外面的(反之亦然)那么你知道你需要一堵墙
  4. 收集字典中的所有边缘,对于每个坐标对,您保留一个开始或到达该边缘的所有墙的列表
  5. 扫描完成后,您可以通过从任何墙开始并保持跟随链直到您回到初始点来重建生成的循环...如果您到达某个点时有多个选择关于哪个墙用来继续散步,然后选择其中任何一个。
  6. 如果您正确收集数据并假设您可以在数据周围添加一个“out”单元格的边框,那么可以保证您将得到一个零或多个闭环的列表,因为每个点都会列出一个偶数墙壁。

    这些循环(当考虑奇数均匀填充规则时)将定义您的初始区域。请注意,您可能会获得自相交循环...如果您想避免算法稍微复杂一点。

    此方法也比一次处理一个边界并执行所有这些合并操作要快得多,结果将是一般的(包括非连接区域和孔)。

    修改

    以下图像是a complete implementation of this algorithm的结果,包括在循环收集期间的右转逻辑,以避免自相交循环。已经为输出多边形分配了不同的颜色,并且已经切割了角以使转弯变得明显。

    output of the cycle collection algorithm