什么是凸包?

凸包定义

点集p的凸包是指一个最小凸多边形(内角均小于180°),满足p中的点或者在多边形边上或者在其内

下图中的红色线段表示的多边形就是点集p={p0,p1,p2,p3,…………,p12}的凸包

通俗理解

  • 一组平面上的点,求一个包含所有点的最小的凸多边形
  • 这可以形象地想成这样:在地上放置一些不可移动的木桩(代表点集中的点),用一根绳子把他们尽量紧地圈起来,这就是凸包

凸包有什么特点?

  • 整个凸包都在任意一条边的一侧
  • 凸包任意两点的中点都在凸包内
  • 凸包内的任意点集的加权平均(凸组合)都在凸包内

凸包有什么用途?

  • 从点集中抽象出一个唯一确定的凸多边形,即一组点集的凸包是唯一的,凹包并不唯一
  • 用尽量少的点来描述一个点集的边界
  • 使点集有序
  • 对复杂多边形进行化简
  • 为其它算法做预处理

绘制凸包的常见算法?

  • Jarvis march(包裹法)

  • Graham Scan(扫描法)

  • Divide and conquer(分治法)

  • Divide and conquer(分治法)

这里只讲解最简单常用的Jarvis march(包裹法)

Jarvis march(包裹法)

这种算法利用了凸包的一个特性:整个凸包都在任意一条边的一侧

基本思想如下:

  • 选取必定在凸包上的一个点作为起点p0,可以是最低点,最高点,最左侧点,最右侧点其中一个,以最低点为例,将其放入凸包点集convexPoints=[p0]
  • 从点集剩余点中选取一点p1,使得点集中的所有点都在p0p1连线的同侧,方法如下:

点集中任意一点与p0的连线与x轴的夹角为alfa,选择使得夹角alfa最小的点为p1,此时点集中的所有点都在p0p1连线的同侧,将p1放入凸包点集中convexPoints=[p0,p1],并从点集p中删除点p1

  • 以点集p1为起点startPoint,p0为上一点previousPoint,在点集p的剩余点中寻找下一个凸包点p2=nextPoint,使得从startPoint出发到previousPoint 和nextPoint的夹角最大,此时该点为下一凸包点convexPoints=[p0,p1,p2],从点集p中删除点nextPoint

  • 以p2为新起点startPoint,p1为新的上一点previousPoints,重复上一步骤,在p剩余点集中寻找下一点p3=nextPoint,直到寻找的nextPoint在convexPoints中已经出现,此时凸包点已经首位闭合

算法流程图

补充

如何计算与x轴的逆时针夹角alfa

  • 第一象限

alfa=arctan(dy/dx)

  • 第二象限

alfa=arctan(dy/dx)+pi

  • 第三象限

alfa=arctan(dy/dx)+pi

  • 第四象限

alfa=arctan(dy/dx)+2pi

python代码

def getAlfa(startPoint, endPoint):dx = endPoint[0] - startPoint[0]dy = endPoint[1] - startPoint[1]if dx == 0:if dy > 0:return np.pi / 2elif dy < 0:return 3 * np.pi / 2else:return np.pialfa = np.arctan(dy / dx)if dx < 0:alfa += np.pielif dy < 0:alfa += np.pi * 2return alfa

如何计算startPoint与previousPoint,nextPoint连线的夹角dalfa

  • 记startPoint与previousPoint连线与x轴的夹角为alfa1
  • 记startPoint与nextPoint连线与x轴的夹角为alfa2

dlfa=abs(alfa2-alfa1)

如果dalfa大于pi,由于凸多边形的内角小于180°,因此此时还需要用dalfa=2pi-dalfa

完整代码

基于上述算法,用gda库计算点SHP文件的凸包

from osgeo import ogr, gdalconst, osr
import numpy as np
import pandas as pd
import osdef getAlfa(startPoint, endPoint):dx = endPoint[0] - startPoint[0]dy = endPoint[1] - startPoint[1]if dx == 0:if dy > 0:return np.pi / 2elif dy < 0:return 3 * np.pi / 2else:return np.pialfa = np.arctan(dy / dx)if dx < 0:alfa += np.pielif dy < 0:alfa += np.pi * 2return alfadef convexHull(xys: np.array):convexPoints = []ymin = np.min(xys, axis=0)[1]index = np.where(xys[:, 1] == ymin)[0][0]convexPoints.append(xys[index, :])n = 1while True:if n == 1:startPoint = convexPoints[0]minAlfa = 0index = 0for i in range(xys.shape[0]):endPoint = xys[i, :]alfa = getAlfa(startPoint, endPoint)if i == 0:minAlfa = alfaindex = 0else:if alfa < minAlfa:minAlfa = alfaindex = iconvexPoints.append(xys[index, :])xys = np.delete(xys, index, axis=0)n += 1else:startPoint = convexPoints[-1]previousPoint = convexPoints[-2]alfa0 = getAlfa(startPoint, previousPoint)maxAlfa = 0index = 0for i in range(xys.shape[0]):nextPoint = xys[i, :]alfa1 = getAlfa(startPoint, nextPoint)dalfa = (alfa0 - alfa1) if alfa0 > alfa1 else (alfa1 - alfa0)if dalfa > np.pi:dalfa = np.pi * 2 - dalfaif i == 0:maxAlfa = dalfaindex = 0else:if dalfa > maxAlfa:maxAlfa = dalfaindex = iconvexPoints.append(xys[index, :])xys = np.delete(xys, index, axis=0)n += 1# 判断首位是否重合firstPoint = convexPoints[0]lastPoint = convexPoints[-1]if firstPoint[0] == lastPoint[0] and firstPoint[1] == lastPoint[1]:breakwktPolygon = ""for i in range(n):x = convexPoints[i][0]y = convexPoints[i][1]wktPolygon = '{} {},'.format(x, y) + wktPolygonwktPolygon = wktPolygon[0:-1]wktPolygon = "POLYGON(({}))".format(wktPolygon)return wktPolygonif __name__ == "__main__":ogr.RegisterAll()ds = ogr.Open("./point.shp", gdalconst.GA_ReadOnly)oLay = ogr.DataSource.GetLayer(ds, 0)ogr.Layer.ResetReading(oLay)xys = []while True:oFea = ogr.Layer.GetNextFeature(oLay)if oFea == None:breakoPoi = ogr.Feature.GetGeometryRef(oFea)x = ogr.Geometry.GetX(oPoi)y = ogr.Geometry.GetY(oPoi)xys.append([x, y])xys = np.array(xys)wktPolygon = convexHull(xys)driver = ogr.GetDriverByName("ESRI Shapefile")convexds = ogr.Driver.CreateDataSource(driver, "convexHull.shp")srs = ogr.Layer.GetSpatialRef(oLay)convexLay = ogr.DataSource.CreateLayer(convexds, "convexhull", srs, ogr.wkbPolygon)labelField = ogr.FieldDefn("label", ogr.OFTInteger)ogr.Layer.CreateField(convexLay, labelField)convexFea = ogr.Feature(ogr.Layer.GetLayerDefn(convexLay))ogr.Feature.SetField(convexFea,"label",1)convexPolygon=ogr.CreateGeometryFromWkt(wktPolygon)ogr.Feature.SetGeometry(convexFea,convexPolygon)ogr.Layer.CreateFeature(convexLay,convexFea)ogr.DataSource.Destroy(convexds)ogr.DataSource.Destroy(ds)print('ok!')

结算结果,如下图所示:

点集凸包算法python实现相关推荐

  1. 点集凸包算法python实现(二)

    算法逻辑 在点集凸包算法python实现这篇博客中介绍了一种凸包算法,这种算法中凸包点搜索的过程较为麻烦,主要是因为计算点集连线与X轴的夹角需要考虑到四个不同象限,在这里通过计算向量夹角的方式,对凸包 ...

  2. 凸包计算几何matlab,计算几何-凸包算法 Python实现与Matlab动画演示

    凸包算法是计算几何中的最经典问题之一了.给定一个点集,计算其凸包.凸包是什么就不罗嗦了 本文给出了<计算几何--算法与应用>中一书所列凸包算法的Python实现和Matlab实现,并给出了 ...

  3. 凸包计算几何matlab,計算幾何-凸包算法 Python實現與Matlab動畫演示

    凸包算法是計算幾何中的最經典問題之一了.給定一個點集,計算其凸包.凸包是什么就不羅嗦了 本文給出了<計算幾何--算法與應用>中一書所列凸包算法的Python實現和Matlab實現,並給出了 ...

  4. Graham-Scan算法计算凸包的Python代码实现

    对于一个点集P来讲,它的凸包就是一个凸多边形Q,其中满足P中的每个点都在Q的边界上或内部.就像下图所示 凸包的计算算法有好多种,wiki和算法导论第33章中都有比较详细的介绍,比如下面是算法导论中给出 ...

  5. 凸包问题-Graham-Scan算法-python实现

    一般来说凸包问题有三种解决方式:蛮力法.Graham-Scan法和分治法.关于蛮力法和分治法的python实现可参考博文:蛮力法.分治法,博主写的很清晰. 这里主要介绍Graham-Scan算法的实现 ...

  6. c语言凸包算法,基于C语言的凸包算法实现

    基于C语言的凸包算法实现 非计算机专业,代码有些的不好的地方,大佬轻喷^ _ ^ 根据要求,需要使用C语言实现凸包算法--Graham扫描法,本文将从算法理解.实现思路.遇到的问题及其解决方案三个方面 ...

  7. CGAL笔记之凸包算法—3D凸包

    CGAL笔记之凸包算法-3D凸包 1 介绍 2 静态凸壳结构 2.1 特性类 2.1.1 示例 2.1.2 低维结果示例 2.2 极值点 2.3 半空间交集 2.3.1 例子 2.4 凸性检查 3 动 ...

  8. 算法(Python版)|156Kstars|神级项目-(1)The Algorithms - Python简介

    文章目录 算法(Python版) 项目地址 项目概况 说明 参与入门 社区频道 算法列表 Arithmetic Analysis 算术分析 Audio Filters 音频过滤器 Backtracki ...

  9. PCA算法(python版本)

    PCA算法 python版本 原理 算法流程 特性 PCA求主方向python代码 法向量python,使用sklearn建树 PCA算法的局限 PCA算法应用: 原理 PCA算法,全程主成分分析法, ...

  10. java 地理围栏实现_使用Path2D和凸包算法实现地理围栏服务

    前言 地理围栏(Geo-fencing)是LBS的一种新应用,就是用一个虚拟的栅栏围出一个虚拟地理边界.在物流配送行业应用比较广,划分每个配送网点或者商家配送的范围,提高配送员的配送效率和服务的范围. ...

最新文章

  1. c语言switch不允许实型,C语言中switch语句什么意思
  2. js实现元素水平垂直居中
  3. 摄像头线性矫正的c语言实现,摄影测量考试试题及详细答案
  4. [Java in NetBeans] Lesson 17. File Input/Output.
  5. Linux增加虚拟内存的配置方案
  6. CRM和C4C里的组织架构 - Organizational Structure
  7. Pandas知识点-合并操作join
  8. 正则表达式符号解释1
  9. CoreOS coreos-assembler文档
  10. java获取键盘输入
  11. Paip.声明式编程以及DSL 总结
  12. matlab如何获得数组有多少数,请问MATLAB里有得到一个数组中相同数有多少个的函数么?...
  13. 年薪百万计划之高级JAVA架构师之路视频教程
  14. matlab指派问题求法,matlab指派问题
  15. 关于rollup 和cude 举例浅分析
  16. kafka seek方法
  17. illegal multibyte sequence
  18. 山东省2013高职分数线
  19. 为何丧尸只会攻击人类,而不“咬”动物?
  20. Windows 程式设计书籍

热门文章

  1. php前台点击按钮导出excel,php上导出excel表格数据-PHP如何将查询出来的数据导出成excel表格(最好做一个按钮)...
  2. 百度SEO之-关键词的种类
  3. Java知识总结,不止为了秋招(下)!!!
  4. C++ priority_queue
  5. 误删电脑配置信息还原
  6. 【180928】小飞机打陨石游戏源码
  7. ubuntu离线安装fish
  8. 按键手机java下载_经典按键java手机游戏
  9. PMP报考 你成功了吗?
  10. 【读书笔记《Android游戏编程之从零开始》】19.游戏开发基础(游戏音乐与音效)