我正在处理由2D网格上的方形拼贴组成的多边形。多边形简单地存储为元组列表,每个元组表示一个区块的坐标。多边形总是连续的,没有孔。
我想要做的是确定哪个图块沿着多边形的边界表示顶点,以便稍后我可以在每个图块之间进行跟踪以生成多边形的边框,或者确定两个连续顶点之间的距离。找到一边的长度等等。
这是一个多边形的例子(从左上角减去3x2矩形的5x4矩形,产生向后的'L'):
polygon_tiles = [(3, 0), (4, 0), (3, 1), (4, 1), (0, 2), (1, 2), (2, 2), (3, 2),
(4, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3)]
理想情况下,我正在寻找的算法会产生如下结果:
polygon_verts = [(3, 0), (4, 0), (4, 3), (0, 3), (0, 2), (3, 2)]
列出顶点,顺序跟踪边界。
只有fiddling around有一些测试用例,这个问题似乎比我想象的要复杂得多,特别是在奇怪的情况下,比如多边形有一个1瓦宽的挤压(在这种情况下,其中一个)瓷砖可能必须作为顶点存储两次??)。
我正在使用Python,但任何见解都会受到赞赏,即使它是伪代码。
答案 0 :(得分:2)
假设你的形状没有内部孔。
找到最上面的一行。选择此行最左边的图块。这保证了我们从一个角落开始。
从这块瓷砖中,尝试直接向右走,如果你不能,直接向下,直接向下等,直到你选择了一个方向。这个guarnatees我们可以追踪多边形的顺时针周长
继续按照您选择的方向采取措施。每一步之后:
一旦移动到空的空间并再次返回到瓷砖上,就停止旋转。
如果我们从初始方向旋转,我们必须站在一个顶点上。标记为。
将您遍历的每个其他图块标记为边缘的一部分。
继续走边,直到到达初始的瓷砖。在1个瓷砖挤压的情况下,您可以多次走过瓷砖。
如果这个算法没有意义,请尝试拿出一些纸并手工操作:)
答案 1 :(得分:0)
我只计算顶点之间线条的斜率
# Do sort stuff
vertices = []
for position, polygon in enumerate(polygon_tiles):
# look for IndexErrors
try:
polygon_tiles[position+1]
except IndexError:
break
try:
polygon_tiles[position+2]
except IndexError:
# Bad practice
position = position - 1
# calculate the slope of the line between of vertex 1 and vertex 2
s1 = (polygon_tiles[position+1][1] - polygon[1]) / (polygon_tiles[position+1][0] - polygon[0])
# calculate the slope of vertex 2 and vertex 3
s2 = (polygon_tiles[position+2][1] - polygon_tiles[position+1][1]) / (polygon_tiles[position+2][0] - polygon_tiles[position+1][0])
# if the slopes differ then you have a vertex
if d1 != d2:
vertices.append(polygon_tiles[position+1])
答案 2 :(得分:0)
此问题属于convex hull变体,例如可以应用gift wrapping algorithm。离散坐标和线方向的约束导致简化。这里有一些python代码可以提供所需的答案(Patashu的回答是本着同样的精神):
#!/usr/bin/python
import math
def neighbors(coord):
for dir in (1,0):
for delta in (-1,1):
yield (coord[0]+dir*delta, coord[1]+(1-dir)*delta)
def get_angle(dir1, dir2):
angle = math.acos(dir1[0] * dir2[0] + dir1[1] * dir2[1])
cross = dir1[1] * dir2[0] - dir1[0] * dir2[1]
if cross > 0:
angle = -angle
return angle
def trace(p):
if len(p) <= 1:
return p
# start at top left-most point
pt0 = min(p, key = lambda t: (t[1],t[0]))
dir = (0,-1)
pt = pt0
outline = [pt0]
while True:
pt_next = None
angle_next = 10 # dummy value to be replaced
dir_next = None
# find leftmost neighbor
for n in neighbors(pt):
if n in p:
dir2 = (n[0]-pt[0], n[1]-pt[1])
angle = get_angle(dir, dir2)
if angle < angle_next:
pt_next = n
angle_next = angle
dir_next = dir2
if angle_next != 0:
outline.append(pt_next)
else:
# previous point was unnecessary
outline[-1]=pt_next
if pt_next == pt0:
return outline[:-1]
pt = pt_next
dir = dir_next
polygon_tiles = [(3, 0), (4, 0), (3, 1), (4, 1), (0, 2), (1, 2), (2, 2), (3, 2),
(4, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3)]
outline = trace(polygon_tiles)
print(outline)