目录
算法分三个部分:
1、寻找y轴最小的点,如果y轴位置是相同的,那个找x轴位置最小的,称之为基准点。
2、计算1中找到基准点与其他点的极角(即过此2点的直线与x轴正方向的夹角,代码中以弧度表示),将这些点按极角的大小正序排列。
3、进行基准点与2中点的连线迭代,对新连线的点计算其是否符合凸多边形的定义,如果不满足舍弃此点。判断的方法是计算三点组成线段的叉乘,值为正表示满足条件。
运行时间为O(nlgn)
代码
import math
import matplotlib.pyplot as plt
#待测试点集
c = [2, 1, 2, 1.5, 1, 3, 1.5, 0.5, 1.5, 3]
b = [2, 1, 1, 1.5, 2, 1.5, 1.2, 2, 0.5, 0.5]
ps = [{"x": 2, "y": 2}, {"x": 1, "y": 1}, {"x": 2, "y": 1}, {"x": 1.5, "y": 1.5}, {"x": 1, "y": 2}, {"x": 3, "y": 1.5},
{"x": 1.5, "y": 1.2}, {"x": 0.5, "y": 2}, {"x": 1.5, "y": 0.5}, {"x": 3, "y": 0.5}]
#获取基准点的下标
def get_leftbottompoint(p):
k = 0
for i in range(1, len(p)):
if p[i]['y'] < p[k]['y'] or (p[i]['y'] == p[k]['y'] and p[i]['x'] < p[k]['x']):
k = i
return k
#叉乘计算方法
def multiply(p1, p2, p0):
return (p1['x'] - p0['x']) * (p2['y'] - p0['y']) - (p2['x'] - p0['x']) * (p1['y'] - p0['y'])
#获取极角,通过求反正切得出,考虑pi / 2的情况
def get_arc(p1, p0):
# 兼容sort_points_tan的考虑
if (p1['x'] - p0['x']) == 0:
if ((p1['y'] - p0['y'])) == 0:
return -1;
else:
return math.pi / 2
tan = float((p1['y'] - p0['y'])) / float((p1['x'] - p0['x']))
arc = math.atan(tan)
if arc >= 0:
return arc
else:
return math.pi + arc
#对极角进行排序
def sort_points_tan(p, k):
p2 = []
for i in range(0, len(p)):
p2.append({"index": i, "arc": get_arc(p[i], p[k])})
p2.sort(key=lambda k: (k.get('arc', 0)))
p_out = []
for i in range(0, len(p2)):
p_out.append(p[p2[i]["index"]])
return p_out
def graham_scan(p):
k = get_leftbottompoint(p)
p_sort = sort_points_tan(p, k)
p_result = [None] * len(p_sort)
p_result[0] = p_sort[0]
p_result[1] = p_sort[1]
p_result[2] = p_sort[2]
top = 2
for i in range(3, len(p_sort)):
#叉乘为正则符合条件
while (top >= 1 and multiply(p_sort[i], p_result[top], p_result[top - 1]) > 0):
top -= 1
top += 1
p_result[top] = p_sort[i]
for i in range(len(p_result) - 1, -1, -1):
if p_result[i] == None:
p_result.pop()
return p_result
#测试
result = graham_scan(ps)
print (result)
plt.plot(c, b, 'ro')
c=[]
b=[]
for i in range(0, len(result)):
c.append(result[i]['x'])
b.append(result[i]['y'])
c.append(result[0]['x'])
b.append(result[0]['y'])
plt.plot(c, b, 'r-')
plt.axis([0, 4, 0, 4])
plt.show()
本文介绍了如何使用格拉姆扫描算法来找出多边形中的凸包,通过计算极角排序并迭代检查点的连接性来确定基准点和最终凸包。算法的时间复杂度为O(nlgn),适合处理二维点集。
570

被折叠的 条评论
为什么被折叠?



