点集凸包算法python实现
什么是凸包?
凸包定义
点集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实现相关推荐
- 点集凸包算法python实现(二)
算法逻辑 在点集凸包算法python实现这篇博客中介绍了一种凸包算法,这种算法中凸包点搜索的过程较为麻烦,主要是因为计算点集连线与X轴的夹角需要考虑到四个不同象限,在这里通过计算向量夹角的方式,对凸包 ...
- 凸包计算几何matlab,计算几何-凸包算法 Python实现与Matlab动画演示
凸包算法是计算几何中的最经典问题之一了.给定一个点集,计算其凸包.凸包是什么就不罗嗦了 本文给出了<计算几何--算法与应用>中一书所列凸包算法的Python实现和Matlab实现,并给出了 ...
- 凸包计算几何matlab,計算幾何-凸包算法 Python實現與Matlab動畫演示
凸包算法是計算幾何中的最經典問題之一了.給定一個點集,計算其凸包.凸包是什么就不羅嗦了 本文給出了<計算幾何--算法與應用>中一書所列凸包算法的Python實現和Matlab實現,並給出了 ...
- Graham-Scan算法计算凸包的Python代码实现
对于一个点集P来讲,它的凸包就是一个凸多边形Q,其中满足P中的每个点都在Q的边界上或内部.就像下图所示 凸包的计算算法有好多种,wiki和算法导论第33章中都有比较详细的介绍,比如下面是算法导论中给出 ...
- 凸包问题-Graham-Scan算法-python实现
一般来说凸包问题有三种解决方式:蛮力法.Graham-Scan法和分治法.关于蛮力法和分治法的python实现可参考博文:蛮力法.分治法,博主写的很清晰. 这里主要介绍Graham-Scan算法的实现 ...
- c语言凸包算法,基于C语言的凸包算法实现
基于C语言的凸包算法实现 非计算机专业,代码有些的不好的地方,大佬轻喷^ _ ^ 根据要求,需要使用C语言实现凸包算法--Graham扫描法,本文将从算法理解.实现思路.遇到的问题及其解决方案三个方面 ...
- CGAL笔记之凸包算法—3D凸包
CGAL笔记之凸包算法-3D凸包 1 介绍 2 静态凸壳结构 2.1 特性类 2.1.1 示例 2.1.2 低维结果示例 2.2 极值点 2.3 半空间交集 2.3.1 例子 2.4 凸性检查 3 动 ...
- 算法(Python版)|156Kstars|神级项目-(1)The Algorithms - Python简介
文章目录 算法(Python版) 项目地址 项目概况 说明 参与入门 社区频道 算法列表 Arithmetic Analysis 算术分析 Audio Filters 音频过滤器 Backtracki ...
- PCA算法(python版本)
PCA算法 python版本 原理 算法流程 特性 PCA求主方向python代码 法向量python,使用sklearn建树 PCA算法的局限 PCA算法应用: 原理 PCA算法,全程主成分分析法, ...
- java 地理围栏实现_使用Path2D和凸包算法实现地理围栏服务
前言 地理围栏(Geo-fencing)是LBS的一种新应用,就是用一个虚拟的栅栏围出一个虚拟地理边界.在物流配送行业应用比较广,划分每个配送网点或者商家配送的范围,提高配送员的配送效率和服务的范围. ...
最新文章
- c语言switch不允许实型,C语言中switch语句什么意思
- js实现元素水平垂直居中
- 摄像头线性矫正的c语言实现,摄影测量考试试题及详细答案
- [Java in NetBeans] Lesson 17. File Input/Output.
- Linux增加虚拟内存的配置方案
- CRM和C4C里的组织架构 - Organizational Structure
- Pandas知识点-合并操作join
- 正则表达式符号解释1
- CoreOS coreos-assembler文档
- java获取键盘输入
- Paip.声明式编程以及DSL 总结
- matlab如何获得数组有多少数,请问MATLAB里有得到一个数组中相同数有多少个的函数么?...
- 年薪百万计划之高级JAVA架构师之路视频教程
- matlab指派问题求法,matlab指派问题
- 关于rollup 和cude 举例浅分析
- kafka seek方法
- illegal multibyte sequence
- 山东省2013高职分数线
- 为何丧尸只会攻击人类,而不“咬”动物?
- Windows 程式设计书籍
热门文章
- php前台点击按钮导出excel,php上导出excel表格数据-PHP如何将查询出来的数据导出成excel表格(最好做一个按钮)...
- 百度SEO之-关键词的种类
- Java知识总结,不止为了秋招(下)!!!
- C++ priority_queue
- 误删电脑配置信息还原
- 【180928】小飞机打陨石游戏源码
- ubuntu离线安装fish
- 按键手机java下载_经典按键java手机游戏
- PMP报考 你成功了吗?
- 【读书笔记《Android游戏编程之从零开始》】19.游戏开发基础(游戏音乐与音效)