平面点集的凸包可理解为包含所有点的最小凸多边形(点可以在多边形边上或在其内)。这里给出一种求解方法。
一、基本思路
先找所有点中 y 坐标最大最小的点Pmax、Pmin,所找点必定是凸包上的点;
找距离直线PmaxPmin两侧最远的点P1,P0,构成初始三角形,
;
再对每个三角形新生成的边(、
和
、
)继续找与改变对应顶点(
)不在同一侧的最远点。
二、算法流程
三、实现代码
该算法由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