python 三维凸包_凸包问题,Graham扫描法,python实现

2022-09-20 14:39:17

凸包问题是指在n个点中,寻找一个凸多边形,使所有的点在凸多边形的边界或者内部。这是一个很有意思的计算机图形学问题,一种常用的解法是Graham扫描法,运行时间为O(nlgn)。

笔者拿processing语言对整个算法过程进行了模拟,上动态图:

c2cee9639519d3271605848a379fd4b7.gif

注意processing拿左上为(0,0)原点,与一般数学的原点位置不同。

从动态图上可以看出整个算法分三个部分:

1、寻找y轴最小的点,如果y轴位置是相同的,那个找x轴位置最小的,称之为基准点。

2、计算1中找到基准点与其他点的极角(即过此2点的直线与x轴正方向的夹角,代码中以弧度表示),将这些点按极角的大小正序排列。

3、进行基准点与2中点的连线迭代,对新连线的点计算其是否符合凸多边形的定义,如果不满足舍弃此点。判断的方法是计算三点组成线段的叉乘,值为正表示满足条件。

以下是python的算法实现

# -*- coding: utf-8 -*-

import math

#获取基准点的下标

def get_leftbottompoint(p):

k = 0

for i in xrange(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 xrange(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 xrange(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 xrange(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 xrange(len(p_result) - 1, -1, -1):

if p_result[i] == None:

p_result.pop()

return p_result

#测试

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}]

print graham_scan(ps)

  • 作者:weixin_39924179
  • 原文链接:https://blog.csdn.net/weixin_39924179/article/details/113640407
    更新时间:2022-09-20 14:39:17