1、暴力法

 def g(A,B,P):
     """
     判断点PA矢量在AB矢量的顺时针还是逆时针方向,
     若在逆时针方向则返回1,同向返回0,在顺时针方向返回-1
     :param A:
     :param B:
     :param P:
     :return: 1或0或-1
     """
     #使用PxQ=XpYq-XqYp,若大于0则表示Q在P的逆时针方向
     result = (P[1]-A[1])*(B[0]-A[0])-(B[1]-A[1])*(P[0]-A[0])
     if result<0:
         return -1
     elif result==0:
         return 0
     else:
         return 1

 def isInTriangle(Pi,Pj,Pk,P):
     """
     判断点P是否在其他三个点组成的三角形中,是的话返回true
     :param P:
     :param Pi:
     :param Pj:
     :param Pk:
     :return:
     """
     if g(Pi,Pj,Pk)==0:
         return 0
     if g(Pi,Pj,P)*g(Pi,Pj,Pk)>=0 and g(Pj,Pk,P)*g(Pj,Pk,Pi)>=0 and g(Pk,Pi,P)*g(Pk,Pi,Pj)>=0:
         return 1
     return 0

 def bruteForce(S):
     """
     暴力方法求解凸包
     :param S: 输入的顶点集合
     :return: Q的凸包
     """
     n=len(S)
     flag=ones((n,1))
     output = []
     if n==3:
         #以逆时针方式输出Q的点
         if g(S[0], S[1], S[2])>0:
             output.append(S[0])
             output.append(S[1])
             output.append(S[2])

         elif g(S[0], S[1], S[2])<0:
             output.append(S[2])
             output.append(S[1])
             output.append(S[0])
         return output
     # 若取得的三个点共线怎么办?????
     for i in range(n - 3):
         for j in range(i + 1, n - 2):
             for k in range(j + 1, n - 1):
                 for p in range(k + 1, n):
                     # 有一个点在其他点组成的三角形里
                     if isInTriangle(S[i], S[j], S[k], S[p]):
                         # 则将该点对应的标志位置为0
                         flag[p] = 0
                     if isInTriangle(S[p], S[j], S[k], S[i]):
                         # 则将该点对应的标志位置为0
                         flag[i] = 0
                     if isInTriangle(S[k], S[p], S[i], S[j]):
                         # 则将该点对应的标志位置为0
                         flag[j] = 0
                     if isInTriangle(S[p], S[j], S[i], S[k]):
                         # 则将该点对应的标志位置为0
                         flag[k] = 0
     print(flag)
     sub_S = []
     for i in range(n):
         if flag[i][0]:  # if标志不为0,将添加到sub_S:
             sub_S.append(S[i])  # 则sub_S保存的是在凸包的顶点

     sub_S = np.array(sub_S)
     # 找到sub_S的x坐标最大点B和x坐标最小点A
     sub_S_index = argsort(sub_S[:, 0])
     A = sub_S[sub_S_index[0]]
     B = sub_S[sub_S_index[-1]]

     # 按照点在AB直线上方还是下方将sub_S分为两部分Sup,Sdown
     Sup = []
     Sdown = []
     for i in range(len(sub_S)):
         if g(A, B, sub_S[i]) > 0:
             Sup.append(sub_S[i])
         if g(A, B, sub_S[i]) < 0:
             Sdown.append(sub_S[i])

     # 将Sup按照横坐标递减排序,将Sdown按照横坐标递增排序
     Sup = np.array(Sup)
     Sup = Sup[argsort(-Sup[:, 0])]
     Sdown = np.array(Sdown)
     Sdown = Sdown[argsort(Sdown[:, 0])]

     # 从B开始按照x坐标递减依次输出Sup,到达A,按照x坐标从小到大依次输出Sdown
     output=[]
     # for i in range(len(sub_S)):
     output.append(A)
     output.extend(Sdown)
     output.append(B)
     output.extend(Sup)
     return output

2、GrahamScan

def GrahamScan(S):
     """
     GrahamScan求凸包
     :param S:
     :return:
     """
     #预处理:找到S中y坐标最小的点P0,以水平为极轴求得每个点极角
     n = len(S)
     P = []

     S = S[argsort(S[:, 1])]
     #P.append(tuple(S[0]))
     P.append(list(S[0, 0:2]))
     PointPolar = []  # 保存(x,y,极角)
     for i in range(1, n):
         polar = math.atan2(S[i][1] - S[0][1], S[i][0] - S[0][0])
         polar = polar / math.pi * 180
         PointPolar.append([S[i][0], S[i][1], polar])
     # 将PointPolar的点按照极角从小到大排序,保存在result
     result = preProcessing(PointPolar)

     new_dict2 = remove_dup(result, P[0])
     #P.extend(new_dict2.keys())
     for key in new_dict2:
         P.append(list(key))
     #若m<=1返回凸包是空
     m=len(P)
     if m<=2:
         return
     # 将P[0],P[1],P[2]依次压栈Q
     stack = []
     stack.append(P[0])
     stack.append(P[1])
     stack.append(P[2])
     for i in range(3, m):
         while isInTriangle(P[0], P[i], stack[-2], stack[-1]):
             stack.pop()
         stack.append(P[i])
     return stack
 def preProcessing(PointPolar):
     """
     当多个点的极角相同时,保留距离原点最远的点
     :param dict:
     :return:一个list,经预处理的P[0:m],按照极角从小到大保存要处理的点集
     """
     sorted_polar=sorted(PointPolar,key=lambda d:d[2])
     return sorted_polar

 def remove_dup(sorted_polar,raw):
     """
     :param sorted_dict:
     :return:
     """
     sorted_dict = {}
     for d in sorted_polar:
         sorted_dict[(d[0], d[1])] = d[2]
     new_dict = {}
     new_dict2 = {}
     for k, v in sorted_dict.items():
         new_dict.setdefault(v, []).append(k)
     for k, v in new_dict.items():
         if len(v) > 1:
             d = []
             for item in v:
                 d.append((item[0]-raw[0]) * (item[0]-raw[0]) + (item[1]-raw[1]) * (item[1]-raw[1]))
             v = v[argmax(d)]
             new_dict2[v] = k
         else:
             new_dict2[v[0]] = k
     return new_dict2

结果:

python学习5---实现凸包的更多相关文章

  1. Python学习--04条件控制与循环结构

    Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...

  2. Python学习--01入门

    Python学习--01入门 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.和PHP一样,它是后端开发语言. 如果有C语言.PHP语言.JAVA语言等其中一种语言的基础,学习Py ...

  3. Python 学习小结

    python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...

  4. Python学习路径及练手项目合集

    Python学习路径及练手项目合集 https://zhuanlan.zhihu.com/p/23561159

  5. python学习笔记-python程序运行

    小白初学python,写下自己的一些想法.大神请忽略. 安装python编辑器,并配置环境(见http://www.cnblogs.com/lynn-li/p/5885001.html中 python ...

  6. Python学习记录day6

    title: Python学习记录day6 tags: python author: Chinge Yang date: 2016-12-03 --- Python学习记录day6 @(学习)[pyt ...

  7. Python学习记录day5

    title: Python学习记录day5 tags: python author: Chinge Yang date: 2016-11-26 --- 1.多层装饰器 多层装饰器的原理是,装饰器装饰函 ...

  8. [Python] 学习资料汇总

    Python是一种面向对象的解释性的计算机程序设计语言,也是一种功能强大且完善的通用型语言,已经有十多年的发展历史,成熟且稳定.Python 具有脚本语言中最丰富和强大的类库,足以支持绝大多数日常应用 ...

  9. Python学习之路【目录】

    本系列博文包含 Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习编程的童鞋提供一点帮助!!! 目录: Python学习[第一篇]python简介 Python学习[第二篇]p ...

随机推荐

  1. 基于mykernel的时间片轮转调度

    学号: 363 原创作品,转载请注明出处.本实验资源来源: https://github.com/mengning/linuxkernel/ 一. 实验环境配置 本次实验在实验楼完成: 在实验楼的终端 ...

  2. 【技巧】easyUI的datagrid,如何在翻页以后仍能记录被选中的行

    easyUI的datagrid在复选框多选时,如何在翻页以后仍能记录被选中的行: 注意datagrid中需要配置idField属性,一般为数据的主键

  3. oracle 字符串 正则表达式 拆分,排序,合并

    需求,表数据如:要求圈中的数据,必须根据线芯有序排列. 思路: 1.首先根据分号分隔元素.oracle 很蛋疼,没有提供字符串分隔函数,网上倒是多觉得有点麻烦,耐着性子继续网上找了下,还真让我找到一篇 ...

  4. 静态方法和实例方法(mark)

    借花献佛[转自 ivony's blog] 关于静态方法和实例方法的一些误区. 一.    静态方法常驻内存,实例方法不是,所以静态方法效率高但占内存.     事实上,方法都是一样的,在加载时机和占 ...

  5. lua 基础 之 坑一样的地方

    -- local 局部-- local表=全局表,是同一个表,这主要是由于lua的表机制是匿名的,相当于函数的指针,local foo = foo,-- 即使本地foo没有在全局_G注册,还是引用的是 ...

  6. mysql Navicat客户端

    Navicat是一个用来操作多种数据库的客户端. 可应用操作系统:Windows.macOS.Linux. 可应用 Navicat 产品:Navicat for MySQL.Navicat for P ...

  7. 获取.properties后缀的数据

    在MyPro.properties中的数据如下: Name=ABC 测试类中: Properties properties = new Properties(); String configFile ...

  8. Docker容器的管理

    创建容器的工作原理: 当利用docker run来创建容器时,Docker在后台运行的标准操作包括:检查本地是否存在指定的镜像,不存在就从公有仓库下载,利用镜像创建并启动一个容器分配一个文件系统,并在 ...

  9. JDBC学习DayOne

    一.相关概念 1.JDBC的定义 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它 ...

  10. 接口自动化:pytest----环境搭建

    出处:https://www.cnblogs.com/yoyoketang/p/9356693.html 前言: python鄙视链:pytest 鄙视 > unittest 鄙视 > r ...