计算几何-凸包算法 Python实现与Matlab动画演示
凸包算法是计算几何中的最经典问题之一了。给定一个点集,计算其凸包。凸包是什么就不罗嗦了
本文给出了《计算几何——算法与应用》中一书所列凸包算法的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动画演示的更多相关文章
- Graham Scan凸包算法
获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的 ...
- 计算几何-凸包-toleft test
toLeftTest toLeftTest是判断一个点是否在有向直线左侧的算法. 当点s位于向量pq左侧时,toLeftTest返回true.当点s位于向量pq右侧时,toLeftTest返回fals ...
- 压缩感知重构算法之IRLS算法python实现
压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...
- 压缩感知重构算法之OLS算法python实现
压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...
- 压缩感知重构算法之CoSaMP算法python实现
压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...
- 压缩感知重构算法之IHT算法python实现
压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...
- 压缩感知重构算法之SP算法python实现
压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...
- 压缩感知重构算法之OMP算法python实现
压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...
- 模拟退火算法Python编程(2)约束条件的处理
1.最优化与线性规划 最优化问题的三要素是决策变量.目标函数和约束条件. 线性规划(Linear programming),是研究线性约束条件下线性目标函数的极值问题的优化方法,常用于解决利用现有的资 ...
随机推荐
- 【luoguP2994】[USACO10OCT]吃晚饭的时候Dinner Time
题目链接 按顺序对于每个座位找一个最近的同时编号最小的牛就行了 #include<iostream> #include<cstring> #include<cstdio& ...
- 一起学Makefile(五)
多目标规则 多目标规则,可以简单的理解为是一种将多条具有1)相同依赖和2)相同生成命令的规则,合并成一条规则的语法,其基本格式为: targets...: prerequisites... comma ...
- js 判断一个数是否在数组中
,,,,,,,); ; ; i < arr.length; i++) { ){ console.log(i); flag=; break; } } ){ console.log("66 ...
- AttributeError: module ‘select’ has no attribute 'epoll’
场景:mac 下导入的 ‘select’ 包 import select,然后在 主函数 中创建的 epoll 对象 epl = select.epoll(),运行报错如下 Traceback (mo ...
- docker安装 与 基本配置
1.安装docker #yum remove docker \ docker-common \ container-selinux \ docker-selinux \ docker-engine \ ...
- mysql将多条结果拼接成一条结果
1,实际数据 SELECT resource_id, resource_type FROM res_resource_mount 2,拼接之后数据 SELECT c.resource_id, GROU ...
- php – 通过curl从url获取JSON数据
我试图通过curl连接从URL获取JSON数据.当我打开链接时:它显示{“version”:“N / A”,“success”:true,“status”:true}.现在,我希望获得以上内容. 到目 ...
- Linux系统下zookeeper客户端命令使用
1. 启动客户端 [admin@yrjk bin]$ ./zkCli.sh [zk: localhost:2181(CONNECTED) 0] 2. 显示所有操作命令 [zk: localhost:2 ...
- sharding jdbc(sphere) 3.1.0 spring boot配置
sharding jdbc 2.x系列详解参见https://www.cnblogs.com/zhjh256/p/9221634.html. 最近将sharding jdbc的配置从xml切换到了sp ...
- SoapUI: 设置case的属性变量
琐碎的东西也想一点一滴的记下来