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

本文给出了《计算几何——算法与应用》中一书所列凸包算法的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. CF241E Flights 题解

    题目 做了一下这道题,突然发现自己忘了差分约束,赶紧复习一下. 设当前有n个变量 a1,a2,...,an ,有若干组限制形如 ai≤aj+k (其中k为常数),则由点j向点i连一条边权为k的边,再从 ...

  2. 04-树6 Complete Binary Search Tree (30 分)

    A Binary Search Tree (BST) is recursively defined as a binary tree which has the following propertie ...

  3. Linux expect详解

    随处可见的expect第一次见expect这个命令还是我第一次参加全量上线的时候,那是公司的一个牛人用Shell脚本写的一套自动部署.MD5 比对.发布的全量上线工具,没事的时候,看了下其中的几个脚本 ...

  4. Java 整数间的除法运算如何保留所有小数位?

      1.情景展示 double d = 1/10; System.out.println(d); 返回的结果居然是0.0!这是怎么回事儿? 2.原因分析 第一步:你会发现用运算结果也可以用int类型接 ...

  5. WebSocket专题(阿里)

    我们的项目中使用了websocket 用java-websocket 开源项目做的,阿里的人问我用啥实现的websocket一时没有答上来 回来做了总结: 1.前言 最近有同学问我有没有做过在线咨询功 ...

  6. 用shedlock实现分布式定时任务锁

    添加包 <dependency>     <groupId>net.javacrumbs.shedlock</groupId>     <artifactId ...

  7. SQLServer len 函数, 查字符串长度函数

    declare @name char(1000) --注意:char(10)为10位,要是位数小了会让数据出错 set @name='s{sss}fc{fggh}dghdf{cccs}x' selec ...

  8. C# Area区域配置,修改默认路由

    1.右键项目新建文件夹 Areas 2.先把项目分类包好,建两个文件夹,放Controller和View,Model也可以放在这里 因为项目启动默认打开的是Home/Index ,我把它放在了Webs ...

  9. Linux下安装java及配置(yum安装)

    1.查看java的所有版本:yum list java* 2.安装免费版1.8: yum install java-1.8.0-openjdk.x86_64 3.配置java环境 JAVA_HOME= ...

  10. ospf的路由更新和撤销总结

    首先ospf 的报文有:hello报文,主要作用ospf 邻居建立及维护.dd报文,主要作用主从选举,序列号主从的确认,mtu的协商(可选).lsr 报文,主要作用向邻居请求lsa.lsu报文,主要作 ...