凸包算法是计算几何中的最经典问题之一了。给定一个点集,计算其凸包。凸包是什么就不罗嗦了

本文给出了《计算几何——算法与应用》中一书所列凸包算法的Python实现和Matlab实现,并给出了一个Matlab动画演示程序。

啊,实现谁都会实现啦╮(╯▽╰)╭,但是演示就不一定那么好做了。

算法CONVEXHULL(P) 
输入:平面点集P 
输出:由CH(P)的所有顶点沿顺时针方向组成的一个列表
1.   根据x-坐标,对所有点进行排序,得到序列p1, …, pn
2.   在Lupper中加入p1和p2(p1在前)
3. for(i←3 ton) 
4.   do 在Lupper中加入pi
5.   while(Lupper中至少还有三个点,而且最末尾的三个点所构成的不是一个右拐) 
6.   do 将倒数第二个顶点从Lupper中删去
7.   在Llower 中加入pn和pn-1(pn在前)
8. for(i←n-2 downto1) 
9.   do 在Llower 中加入pi
10.    while(Llower 中至少还有三个点,而且最末尾的三个点所构成的不是一个右拐) 
11.    do 将倒数第二个顶点从Llower 中删去
12.  将第一个和最后一个点从Llower 中删去
(以免在上凸包与下凸包联接之后,出现重复顶点)
13.  将Llower 联接到Lupper后面(将由此得到的列表记为L)
14.  return(L) 

看看,不是很多的样子是吧。
这里面需要说明的地方只有一点,那就是方向的判定问题。

设有三个点P,Q,R,现需求R位于向量PQ的左侧还是右侧(或者R在PQ上)。

计算PR与PQ的叉积,也就是外积。

如果将向量PR以P为旋转中心旋转只向量PQ的方向走过一个正角(逆时针),意味着R在PQ的右侧,此时外积为正。

另外需要注意的是,如果在凸包上有三点共线的情况,在本例中三点是均位于凸包边界点集中的。如果想避免这一点,可以通过微量抖动数据的方式解决。

废话不多说,Python实现如下:

 #!/usr/bin/env python
# coding: gbk ########################################################################
#Author: Feng Ruohang
#Create: 2014/10/02 13:39
#Digest: Computate the convex hull of a given point list
######################################################################## direction = lambda m: (m[2][0] - m[0][0]) * (m[1][1] - m[0][1]) - (m[1][0] - m[0][0]) * (m[2][1] - m[0][1])
'''
    A Quick Side_check version Using Lambda expression
    Input:  Given a list of three point : m should like [(p_x,p_y), (q_x,q_y), (r_x,r_y)]
    Output: Return a Number to indicate whether r on the right side of vector(PQ).
    Positive means r is on the right side of vector(PQ).
    This is negative of cross product of PQ and PR: Defined by:(Qx-Px)(Ry-Py)-(Rx-Px)(Qy-Py)
    Which 'negative' indicate PR is clockwise to PQ, equivalent to R is on the right side of PQ
''' def convex_hull(point_list):
'''
Input:  Given a point List: A List of Truple (x,y)
Output: Return a point list: A List of Truple (x,y) which is CONVEX HULL of input
For the sake of effeciency, There is no error check mechanism here. Please catch outside
'''
n = len(point_list)  #Total Length
point_list.sort() #Valid Check:
if n < 3:
return point_list #Building Upper Hull: Initialized with first two point
upper_hull = point_list[0:1]
for i in range(2, n):
upper_hull.append(point_list[i])
while len(upper_hull) >= 3 and not direction(upper_hull[-3:]):
del upper_hull[-2] #Building Lower Hull: Initialized with last two point
lower_hull = [point_list[-1], point_list[-2]]
for i in range(n - 3, -1, -1):  #From the i-3th to the first point
lower_hull.append(point_list[i])
while len(lower_hull) >= 3 and not direction(lower_hull[-3:]):
del lower_hull[-2]
upper_hull.extend(lower_hull[1:-1])
return upper_hull #========Unit Test:
if __name__ == '__main__':
test_data = [(i, i ** 2) for i in range(1, 100)]
result = convex_hull(test_data)
print result 2015年1月23日

使用很简单,看DocString就行。

下面顺便给出了Matlab 的实现,以及可视化的算法演示:

效果就是个小动画,像这样吧。

Matlab的凸包算法有三个文件:

side_check2:检查三个点构成的弯折的方向

Convex_hull: 凸包算法Matlab实现

Convex_hull_demo:凸包算法的演示。

拷在一个目录里

运行convex_hull_demo( randn(200,2)*100); 就可以看到可视化演示了

这个是辅助函数

%filename: side_check2.m
%Input: Matrix of three point: (2x3 or 3x2)
% P(p_x,p_y),Q(q_x,q_y),R(r_x,r_y)
%Output: 如果P Q R三点构成一个右拐,返回True
% 右拐意味着点R在PQ向量的右侧.此时 function result = side_check2(D)
if all(size(D) ~= [3,2])
if all(size(D)==[2,3])
D = D';
else
error('error dimension')
end
end
result = (det([[1;1;1], D]) < 0 );

这个是纯算法实现。

%filename:     convex_hull.m
%CONVEX_HULL
%INPUT: Point Set:(n x 2)
%OUPUT: HULL Point List: (x x 2)
function L=t(P)
[num,dimension] = size(P);
if dimension ~= 2
error('dimension error')
end P = sortrows(P,[1,2]);
%if there is only one or two point remain,return it
if num < 3
L = P;
return
end %STEP ONE: Upper Hull:
L_upper = P([1,2],:); %Take first two points
for i = 3:num
L_upper = [L_upper;P(i,:)]; %add the point into list
while size(L_upper,1) >= 3
l_size = size(L_upper,1);
if det([ones(3,1),L_upper(l_size-2:l_size,:)])= 3
l_size = size(L_lower,1);
if det([ones(3,1),L_lower(l_size-2:l_size,:)])

这个是演示:

%CONVEX_HULL
%INPUT: Point Set:(n x 2)
%OUPUT: HULL Point List: (x x 2)
%Samples: convex_hull_demo( randn(200,2)*100) function L=convex_hull_demo(P) %Test Data
%data_size = data_size
%P = randi([-50,50],[data_size,2]);
[num,dimension] = size(P);
if dimension ~= 2
error('dimension error')
end P = sortrows(P,[1,2]); %====Visual Lization
board_left = min(P(:,1));
board_right = max(P(:,1));
board_bottom = min(P(:,2));
board_up = max(P(:,2));
x_padding = (board_right- board_left)*0.1;
y_padding = (board_up- board_bottom)*0.1;
plot_range= [board_left - x_padding,board_right + x_padding,board_bottom-y_padding,board_up+y_padding]; clf;
scatter(P(:,1),P(:,2),'b.');
axis(plot_range);
hold on
%====VisualLization %if there is only one or two point remain,return it
if num < 3
L = P;
end %STEP ONE: Upper Hull:
L_upper = P([1,2],:); %Take first two points
hull_handle = plot(L_upper(:,1),L_upper(:,2),'ob-');
for i = 3:num
L_upper = [L_upper;P(i,:)]; %add the point into list while size(L_upper,1) >= 3
l_size = size(L_upper,1);
if side_check2(L_upper(l_size-2:l_size,:)) %Check if it is valid
break; %Quit if Valid
else
L_upper(l_size-1,:) = []; %Remove the inner point and continue if not
end
set(hull_handle,'XData',L_upper(:,1),'YData',L_upper(:,2));drawnow; end
set(hull_handle,'XData',L_upper(:,1),'YData',L_upper(:,2));drawnow;
end %Visualization
plot(L_upper(:,1),L_upper(:,2),'bo-');
%Visualization %STEP Two: Build the lower hull
L_lower = [P([num,num-1],:)]; % Add P(n) and P(n-1)
set(hull_handle,'XData',L_lower(:,1),'YData',L_lower(:,2));drawnow; for i = num-2:-1:1
L_lower = [L_lower;P(i,:)];
while size(L_lower,1) >= 3
l_size = size(L_lower,1);
if side_check2(L_lower(l_size-2:l_size,:)) %Check if it is valid
break; %Quit if Valid
else
L_lower(l_size-1,:) = []; %Remove the inner point and continue if not
end
set(hull_handle,'XData',L_lower(:,1),'YData',L_lower(:,2));drawnow;
end
set(hull_handle,'XData',L_lower(:,1),'YData',L_lower(:,2));drawnow;
end L_lower([1,size(L_lower,1)],:) = [];
if isempty(L_lower)
L = L_upper;
else
L = [L_upper;L_lower(2:size(L_lower,1)-1,:)];
end
hold off;
return

计算几何-凸包算法 Python实现与Matlab动画演示的更多相关文章

  1. Graham Scan凸包算法

    获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的 ...

  2. 计算几何-凸包-toleft test

    toLeftTest toLeftTest是判断一个点是否在有向直线左侧的算法. 当点s位于向量pq左侧时,toLeftTest返回true.当点s位于向量pq右侧时,toLeftTest返回fals ...

  3. 压缩感知重构算法之IRLS算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  4. 压缩感知重构算法之OLS算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  5. 压缩感知重构算法之CoSaMP算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  6. 压缩感知重构算法之IHT算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  7. 压缩感知重构算法之SP算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  8. 压缩感知重构算法之OMP算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  9. 模拟退火算法Python编程(2)约束条件的处理

    1.最优化与线性规划 最优化问题的三要素是决策变量.目标函数和约束条件. 线性规划(Linear programming),是研究线性约束条件下线性目标函数的极值问题的优化方法,常用于解决利用现有的资 ...

随机推荐

  1. 第09组 Alpha冲刺(1/6)

    队名:观光队 组长博客 作业博客 组员实践情况 王耀鑫 过去两天完成了哪些任务 文字/口头描述 完成服务器连接数据库部分代码 展示GitHub当日代码/文档签入记录 接下来的计划 与服务器连接,配合前 ...

  2. 声源定位之3精读《The Generalized Correlation Method for Estimation of Time Delay》

    2.2.1 标题(2019年9月5日) 估计时间差的广义互相关方法 互相关可以表示两个信号的相似程度. 计算:两个信号循环移位相乘再相加,得到的一组互相关值. 相关函数: 何为广义?通用的框架,可以设 ...

  3. ping某域名的整个流程

    实验环境:主机A,B(可不再同一网段),主机B有域名假设为www.baidu.com首先:1. 本地主机A在命令行下执行"ipconfig/flushdns"命令来清空本地DNS高 ...

  4. Linux下挂载超过2T的磁盘

    1.使用命令进入交互模式并且查看当前硬盘分区信息 parted /dev/sdb p 2.删除当前存在分区,并在此查看结果 rm 1 p 3.将硬盘格式化为gpt mklabel gpt 4.对磁盘分 ...

  5. 运维笔记--Docker环境ubuntu系统安装指定版本python[3.6]

    场景描述: 直接安装出现如下异常: root@ae2d02e458f3:/home# apt-get install python3.6 Reading package lists... Done B ...

  6. idel上传代码到github时遇到的Push rejected: Push to origin/master was rejected

    1 没有权限 2 先pull之后,再push即可

  7. mysql 得到指定时间段的日期

    set @startDate='2019-01-01'; set @endDate='2019-04-01'; DAY) AS DAY FROM ( SELECT a.a ) AS a ) AS b ...

  8. PhpStorm2019 代码自动换行

    我的版本是2019.1里面没有了Use soft wrap in editor 所以在这里新加上*.php;*.html,并且在前面选上打勾就可以了,其余类似编辑器使用类似的方法

  9. 使用VEGAS2(Versatile Gene-based Association Study)进行gene based的关联分析研究

    gene-based关联分析研究是SNP-based关联分析研究的一个补充. 目前有很多工具支持gene-based关联分析研究,比如GCTA,VEGAS2等. 下面主要介绍一下怎么用VEGAS2做g ...

  10. LwIP应用开发笔记之三:LwIP无操作系统UDP客户端

    前一节我们实现了基于RAW API的UDP服务器,在接下来,我们进一步利用RAW API实现UDP客户端. 1.UDP协议简述 UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包 ...