c语言编程笔录

首页 >   > 笔记大全

笔记大全

Python怎么实现绘制凸包

更新时间:2023-10-06

凸包的定义

凸包是指包围给定点集的最小凸多边形,即能包含所有点,且多边形上的所有角都是不大于180度的角。

在凸包的计算中,常用的方法是Graham扫描法和Jarvis旋转法。

Graham扫描法

Graham扫描法是一种基于极角排序的方法,步骤如下:

1. 找到点集中的最低点(最左下角)。

2. 将所有点按照与最低点的极角排序。

3. 从排序后的点集中依次取出点,如果该点与前两个点构成的向量产生了右转,那么将前一个点移除,直到找到左转或形成直线。

4. 最后得到的序列即为凸包的顶点。

import math

def orientation(p, q, r):
    """
    计算点p,q,r的方向
    返回值:
    -1: 右转
    0: 共线
    1: 左转
    """
    val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1])
    if val == 0:
        return 0
    return 1 if val > 0 else -1

def convex_hull(points):
    # 如果点个数小于等于2,直接返回所有点
    if len(points) <= 2:
        return points
     
    hull = []  # 保存结果的凸包
    l = 0  # 最左下角的点的索引
     
    # 找到最左下角的点
    for i in range(1, len(points)):
        if points[i][1] < points[l][1] or (points[i][1] == points[l][1] and points[i][0] < points[l][0]):
            l = i
 
    p = l  # 当前处理的点
    q = 0  # 上一次放在结果里的点
     
    while True:
        # 将当前点加入凸包
        hull.append(points[p])
 
        # 查找下一个点
        q = (p + 1) % len(points)
         
        for i in range(len(points)):
            if orientation(points[p], points[i], points[q]) == -1:
                q = i
 
        p = q
         
        if p == l:
            break
 
    return hull

Jarvis旋转法

Jarvis旋转法是一种逐步递增的方法,步骤如下:

1. 找到点集中的最左点(最左上方)。

2. 从最左点开始,按照逆时针方向找到与当前点构成最大极角的点,顺时针遍历所有点。

3. 找到一个新的点后,将其加入凸包,并将其作为下一步查找的起始点。

4. 当找到的点与起始点重合时,终止,得到的序列即为凸包的顶点。

def leftmost_point(points):
    """
    找到最左点的索引
    """
    leftmost = 0
    for i in range(1, len(points)):
        if points[i][0] < points[leftmost][0]:
            leftmost = i
    return leftmost

def convex_hull(points):
    left = leftmost_point(points)
    hull = []
    n = len(points)
    p = left
    q = None
    
    while True:
        hull.append(points[p])
        q = (p+1) % n
        
        for i in range(n):
            if orientation(points[p], points[i], points[q]) == -1:
                q = i
        
        p = q
        if p == left:
            break
    
    return hull

总结

无论是Graham扫描法还是Jarvis旋转法都可以用来实现凸包的计算。Graham扫描法在整个过程中需要对点进行排序,然后在每一步查找时都需要计算极角,因此时间复杂度为O(nlogn)。Jarvis旋转法在每一步查找时需要顺时针遍历所有点,因此时间复杂度为O(nh),其中h是凸包的边数,在最坏情况下h=n,所以Jarvis旋转法的时间复杂度为O(n^2)。

凸包是在计算几何中常见的问题,可以应用在面积计算、碰撞检测等领域。在Python中,可以通过编写相应的算法来实现凸包的计算。