设为首页 收藏本站
查看: 1950|回复: 0

[经验分享] 计算几何-凸包算法 Python实现与Matlab动画演示

[复制链接]

尚未签到

发表于 2015-11-30 12:59:20 | 显示全部楼层 |阅读模式
  凸包算法是计算几何中的最经典问题之一了。给定一个点集,计算其凸包。凸包是什么就不罗嗦了
  本文给出了《计算几何——算法与应用》中一书所列凸包算法的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的右侧,此时外积为正。
   DSC0000.png
  另外需要注意的是,如果在凸包上有三点共线的情况,在本例中三点是均位于凸包边界点集中的。如果想避免这一点,可以通过微量抖动数据的方式解决。
  废话不多说,Python实现如下:



1 #!/usr/bin/env python
2 # coding: gbk
3  
4 ########################################################################
5 #Author: Feng Ruohang
6 #Create: 2014/10/02 13:39
7 #Digest: Computate the convex hull of a given point list
8 ########################################################################
9  
10  
11 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])
12 '''
13     A Quick Side_check version Using Lambda expression
14     Input:  Given a list of three point : m should like [(p_x,p_y), (q_x,q_y), (r_x,r_y)]
15     Output: Return a Number to indicate whether r on the right side of vector(PQ).
16     Positive means r is on the right side of vector(PQ).
17     This is negative of cross product of PQ and PR: Defined by:(Qx-Px)(Ry-Py)-(Rx-Px)(Qy-Py)
18     Which 'negative' indicate PR is clockwise to PQ, equivalent to R is on the right side of PQ
19 '''
20  
21  
22 def convex_hull(point_list):
23     '''
24     Input:  Given a point List: A List of Truple (x,y)
25     Output: Return a point list: A List of Truple (x,y) which is CONVEX HULL of input
26     For the sake of effeciency, There is no error check mechanism here. Please catch outside
27     '''
28     n = len(point_list)  #Total Length
29     point_list.sort()
30  
31     #Valid Check:
32     if n < 3:
33         return point_list
34  
35     #Building Upper Hull: Initialized with first two point
36     upper_hull = point_list[0:1]
37     for i in range(2, n):
38         upper_hull.append(point_list)
39         while len(upper_hull) >= 3 and not direction(upper_hull[-3:]):
40             del upper_hull[-2]
41  
42     #Building Lower Hull: Initialized with last two point
43     lower_hull = [point_list[-1], point_list[-2]]
44     for i in range(n - 3, -1, -1):  #From the i-3th to the first point
45         lower_hull.append(point_list)
46         while len(lower_hull) >= 3 and not direction(lower_hull[-3:]):
47             del lower_hull[-2]
48     upper_hull.extend(lower_hull[1:-1])
49     return upper_hull
50  
51  
52 #========Unit Test:
53 if __name__ == '__main__':
54     test_data = [(i, i ** 2) for i in range(1, 100)]
55     result = convex_hull(test_data)
56     print result
57
58 2015年1月23日
  使用很简单,看DocString就行。
  下面顺便给出了Matlab 的实现,以及可视化的算法演示:
  效果就是个小动画,像这样吧。
DSC0001.png
  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

  
  
  
  
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-145383-1-1.html 上篇帖子: python用法笔记(数组(list、touple、dict)、字符串) 下篇帖子: Eclipse开发Python项目
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表