平面點集的凸包計算


平面點集的凸包可理解為包含所有點的最小凸多邊形(點可以在多邊形邊上或在其內)。這里給出一種求解方法。

一、基本思路

先找所有點中 y 坐標最大最小的點Pmax、Pmin,所找點必定是凸包上的點;

image

找距離直線PmaxPmin兩側最遠的點P1,P0,構成初始三角形clip_image002[7], clip_image004

image

再對每個三角形新生成的邊(clip_image002[9]clip_image004[5]clip_image006clip_image008)繼續找與改變對應頂點(clip_image010)不在同一側的最遠點。

image

二、算法流程

1 找所有點中 y 坐標最大和最小的點

     1.1 若找到的點少於兩個,return,輸出(無凸包結構)

     1.2 若y坐標最大最小點各只有一個記為Pmax,Pmin,找直線PmaxPmin兩側最遠的點P1,P0,將構成的三角形clip_image002[11], clip_image004[7]放入堆棧TriStack

     1.3 若找到的點大於兩個,把這些點能組成的三角形放入堆棧TriStack

2 若TriStack不為空

     2.1 三角形出棧,找三角形前兩個頂點的對邊與該點異側的最遠點

     2.2 若點存在,邊與點組成三角形放入TriStack

     2.3 若點不存在,該邊存入Boundary,返回2

3 返回 Boundary

 

三、實現代碼

該算法由matlab實現:

 1 clc;
 2 clear;
 3 N = 74;
 4 DataPoints = [(1:N)', rand(N, 2).*100];
 5 plot(DataPoints(:, 2), DataPoints(:, 3), '.');
 6 % grid on;
 7 X = DataPoints(:,2);
 8 Y = DataPoints(:,3);
 9 
10 %% 
11 % 根據 y 方向最值點確立初始三角形
12 % 找 y 最大和最小值的點 --------
13 [Ymax, Ymax_i] = max(Y);
14 [Ymin, Ymin_i] = min(Y);
15 PymaxPymin = [X(Ymin_i) - X(Ymax_i), Y(Ymin_i) - Y(Ymax_i)];
16 PtNum = N;
17 % 找距離直線 PymaxPymin 兩側最遠點 --------
18 PtNum_p = 1; PtNum_n = 1;
19 Dis_p = 0; Dis_n = 0;
20 for j = 1 : PtNum
21     PjPymax = [X(Ymax_i) - X(j), Y(Ymax_i) - Y(j)];
22     PjPymin = [X(Ymin_i) - X(j), Y(Ymin_i) - Y(j)];
23     Tri_erea = det([PjPymax; PjPymin]);
24     if Tri_erea < 0
25         if Dis_n < abs(Tri_erea)
26             Dis_n = abs(Tri_erea);
27             PtNum_n = j;
28         end
29     else
30         if Dis_p < Tri_erea
31             Dis_p = Tri_erea;
32             PtNum_p = j;
33         end
34     end
35 end
36 
37 % 計算凸包邊界 ----------
38 TriStack = [];
39 TriStack(1, :) = [Ymax_i, Ymin_i, PtNum_p];
40 TriStack(2, :) = [Ymax_i, Ymin_i, PtNum_n];
41 Boundary = FindBoundary(TriStack, DataPoints);
42 hold on;
43 for i = 1 : size(Boundary, 1)
44     plot([X(Boundary(i,1)), X(Boundary(i,2))], ...
45     [Y(Boundary(i,1)), Y(Boundary(i,2))], '-');
46 end
主程序
 1 function TriPtNum_new = TriFindPt(TriPtNum, DataPoints)
 2 % 擴展三角形的兩邊
 3 % TriPtNum [i,j,k]是三角形 PiPjP 的頂點序號, 過頂點 P 的兩邊要擴展
 4 % DataPoints 是所有點的坐標
 5 % TriPtNum_new [i,j]是兩條擴展邊最外側頂點序號, 若不存在取0
 6 
 7 X = DataPoints(:,2);
 8 Y = DataPoints(:,3);
 9 % 點 Pi, Pj的對邊, 擴展 -------------------
10 PjP = [X(TriPtNum(3)) - X(TriPtNum(2)), Y(TriPtNum(3)) - Y(TriPtNum(2))];
11 PiP = [X(TriPtNum(3)) - X(TriPtNum(1)), Y(TriPtNum(3)) - Y(TriPtNum(1))];
12 PiPj = [X(TriPtNum(2)) - X(TriPtNum(1)), Y(TriPtNum(2)) - Y(TriPtNum(1))];
13 % PiPj x PiP, PjPi x PjP, 向量叉積
14 PiPjxPiP = det([PiPj; PiP]);
15 PjPixPjP = det([-PiPj; PjP]);
16 
17 % 找點 Pi, Pj 的對邊距離最遠點 ------------------ 
18 PtNum = length(X);
19 PtNum_pi = 0; PtNum_pj = 0;
20 Dis_pi = 0; Dis_pj = 0;
21 for k = 1 : PtNum
22     % 點 Pi 的對邊找最遠點
23     PkPj = [X(TriPtNum(2)) - X(k), Y(TriPtNum(2)) - Y(k)];
24     PkP = [X(TriPtNum(3)) - X(k), Y(TriPtNum(3)) - Y(k)];
25     PkPjxPkP = det([PkPj; PkP]);
26     % 點 Pj 的對邊找最遠點
27     PkPi = [X(TriPtNum(1)) - X(k), Y(TriPtNum(1)) - Y(k)];
28     PkPixPkP = det([PkPi; PkP]);
29     
30     if(PiPjxPiP * PkPjxPkP < 0)
31         Tri_ereai = abs(PkPjxPkP);
32         if(Dis_pi < Tri_ereai)
33             Dis_pi = Tri_ereai;
34             PtNum_pi = k;
35         end
36     end
37     
38     if(PjPixPjP * PkPixPkP < 0)
39         Tri_ereaj = abs(PkPixPkP);
40         if(Dis_pj < Tri_ereaj)
41             Dis_pj = Tri_ereaj;
42             PtNum_pj = k;
43         end
44     end
45     TriPtNum_new = [PtNum_pi, PtNum_pj];
46 end
找三角形兩邊外側最遠點
 1 function Boundary = FindBoundary(TriStack, DataPoints)
 2 % 從初始三角形開始查找邊界
 3 
 4 Boundary = [];
 5 while size(TriStack, 1)
 6     TriPtNum_new = TriFindPt(TriStack(end, :), DataPoints);
 7     TriPt = TriStack(end, :);
 8     TriStack(end, :) = [];
 9     if TriPtNum_new(1)
10         TriStack(end+1, :) = [TriPt(:, 2:3), TriPtNum_new(1)];
11     else
12         Boundary(end+1, :) = TriPt(:, 2:3);
13     end
14     if TriPtNum_new(2)
15         TriStack(end+1, :) = [TriPt(1, 1), TriPt(1, 3), TriPtNum_new(2)];
16     else
17         Boundary(end+1, :) = [TriPt(1, 1), TriPt(1, 3)];
18     end
19 end
確定凸包上的所有邊

四、運行示例

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM