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. shell+Zabbix export应用之AD环境删除离职人员登录主机之资料

    以实际环境:维护环境172.30网段主机 Zabbix hosts export出主机信息至 /tmp/ip.txt shell筛选出ip [root@server ~]# cat /tmp/ip.t ...

  2. java按照指定格式输出系统时间使用SimpleDateFormat方法

    public class TimeThree { public static void main(String[] args) { SimpleDateFormat d = new SimpleDat ...

  3. org.hibernate.ObjectNotFoundException: No row with the given identifier exists

    维护老系统时出现的问题,出现的原因我简述一下: table1与table2是关联表,T1中有T2的主键 "T1_id",当T1中的 "T2_id" 不为null ...

  4. HTML的块级元素和行内元素

    行内元素一般是内容的容器,而块级元素一般是其他容器的容器.一般情况下,行内元素只能包含内容或者其它行内元素,宽度和长度依据内容而定,不可以设置,可以和其它元素和平共处于一行:而块级元素可以包含行内元素 ...

  5. python小总结4(文件)

    一.读文件 过程: a.打开文件:open() b.读取文件内容:read() readline() readlines() c.关闭文件:close() open(path,flag,encodin ...

  6. JS-1

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. C# [Win32] [API] Layered Windows

    static void* WndProc(void* hwnd, uint uMsg, void* wParam, void* lParam) { switch (uMsg) { case WM_PA ...

  8. c#连接db2数据库

    .net项目要连接db2数据库,是要安装客户端的,否则是连接不上的: 若出现“未在本地计算机上注册‘ibmdadb2’提供程序” 解决办法: 1.先找到安装后的ibmdadb2.dll文件复制到c:\ ...

  9. cin.get();cin.clear();cin.sync()

    先看代码: #include<iostream> using namespace std; int main(){ int c,x; cout<<"输入大小" ...

  10. MySQL简单的查询语句

    1.查询特定列:select 列名 from 表名:(必须先进入数据库)或者 select 列名 from 数据库.表名: 2.查询多个列:select 列1,列2,... from 表名: 3.除去 ...