我有一组三角形。我正在寻找一种方法来找到这些三角形的所有组合,这些三角形在连接在一起时构成一个凸包。凸壳应该是空的,即。仅在边缘上的凸包内没有点。并且只有共享一侧的三角形可以连接在一起,即。工会没有差距。
示例:以下几点给出了12个三角形(Delaunay Triangulation)。
xy = [3.3735 0.7889; -0.1072 -3.4814; -3.9732 4.1955; -5 5; 5 5; 5 -5; -5 -5];
DT = delaunayTriangulation(xy);
triplot(DT);
%The coordinates for each triangle -- each row is a triangle.
TRIX = reshape(DT.Points(DT.ConnectivityList, 1), size(DT.ConnectivityList));
TRIY = reshape(DT.Points(DT.ConnectivityList, 2), size(DT.ConnectivityList));
我正在寻找最大的凸包,因此凸包应该包括尽可能多的三角形。但如果我拥有所有可能的组合,我可以轻松过滤出三角形较少的组合。在上面的例子中,我应该得到这六个凸包:
我猜我应该使用每个三角形最多有三个相邻的三角形(每边一个)。并且我应该检查角度的总和是否在相交点处小于或等于180度。这将确保联合是凸的 - 见下图。 (如果几个三角形形成一个完整的圆,角度也可能正好是360度。)
三角形角度:
% Vectors connecting points
diffx = diff([TRIX TRIX(:,1)], [], 2); diffy = diff([TRIY TRIY(:,1)], [], 2); diffxy = [diffx(:) diffy(:)];
% Norm
normxy = reshape( arrayfun(@(row) norm(diffxy(row,:)), 1:size(diffxy,1)), size(DT.ConnectivityList));
nominator = repmat(sum(normxy.^2, 2), 1, 3) - 2*normxy.^2;
denominator = 2 * repmat(prod(normxy, 2), 1, 3)./normxy;
% Angle
tri_angle = acosd(nominator./denominator);
tri_angle = circshift(tri_angle, [0 -1]); % Shift so the angles match the correct point.
我重新格式化信息,使得行是点,列是三角形:
n_tri = size(TRIX,1); % Number of triangles
% Adjacency matrix connecting points (rows) with triangles (columns).
adj_points = zeros(size(xy,1), n_tri);
adj_angle = NaN(size(adj_points));
for point =1:size(xy,1)
idx = find(DT.ConnectivityList == point);
[a_tri, ~] = ind2sub(size(DT.ConnectivityList), idx);
adj_points(point,a_tri) = 1;
adj_angle(point,a_tri) = tri_angle(idx);
end
我遍历所有边缘并计算边缘两侧的角度(edges angles
)。这样我就可以找到形成凸集(adj_convex
)的三角形对:
DT_edges = edges(DT); % All edges in the Delaunay triangulation
% Adjacency matrix connecting edges (rows) with triangles (columns).
adj_edge = logical(adj_points(DT_edges(:,1),:) .* adj_points(DT_edges(:,2),:));
edgesangles = NaN(size(DT_edges));
adj = zeros(n_tri); % Adjacency matrix indicating which triangles are neighbours.
adj_convex = zeros(n_tri);
for edge=1:size(DT_edges,1)
% The angles on either side of the edge.
tri = adj_edge(edge,:);
t = adj_angle(DT_edges(edge,:), tri );
edgesangles(edge,:) = sum(t, 2);
tri_idx = find(tri);
adj(tri_idx,tri_idx) = 1;
adj_convex(tri_idx,tri_idx) = prod(edgesangles(edge,:) <= 180);
end
convexedges = (edgesangles <= 180);
% Set diagonals to zero.
adj(logical(eye(n_tri))) = 0;
adj_convex(logical(eye(n_tri))) = 0;
但是,如果我想要所有组合或最大的凸包,我不确定如何继续。而且我不确定如何解释特殊情况下整个圆圈中的几个三角形(即360度)。
答案 0 :(得分:2)
这个答案可以通过一个简单的递归算法来解决:
所以这个算法是递归的,因为它贪婪地尝试向集合中添加更多三角形,直到它不再凸起为止。下面的代码给出了这个结果(我省略了所有琐碎的(1个三角形)答案。
检查凸包中是否没有内部点有点天真:构造凸包并查看是否所有点都在其上。
function [convexTriangleSets,DT] = triangles()
% inputs
xy = [3.3735 0.7889; -0.1072 -3.4814; -3.9732 4.1955; -5 5; 5 5; 5 -5; -5 -5];
DT = delaunayTriangulation(xy);
function convexTriangleSets = testAddTriangle(iTriangle,attachedTriangleIndices,includedTriangleIndices)
% add triangle
includedTriangleIndices(end+1) = iTriangle;
% naive test if allpoint of set of triangles are on convex hull
nodes = unique(DT(includedTriangleIndices,:));
coords = DT.Points(nodes,:);
ch = convexHull(delaunayTriangulation(coords));
allNodesOnConvexHull = length(nodes) == length(ch)-1;
if ~allNodesOnConvexHull
convexTriangleSets = {};
return
end
% find triangles connected to iTriangle
currentTriangle = DT.ConnectivityList(iTriangle,:)';
attachedCell = DT.edgeAttachments(currentTriangle([1 2 3]),currentTriangle([2 3 1]));
attachedRow = unique([attachedTriangleIndices,attachedCell{:}]);
attachedTriangleIndices = attachedRow(~ismember(attachedRow,includedTriangleIndices));
% recursively try to expand connected triangles
convexTriangleSets = {sort(includedTriangleIndices)};
for ii = 1:length(attachedTriangleIndices)
convexTriangleSets = [convexTriangleSets,...
testAddTriangle(attachedTriangleIndices(ii),...
attachedTriangleIndices,...
includedTriangleIndices)]; %#ok<AGROW>
end
end
includedTriangleIndices = [];
attachedTriangleIndices = [];
convexTriangleSets = {};
for iTriangle = 1:DT.size
convexTriangleSets = [convexTriangleSets,...
testAddTriangle(iTriangle,attachedTriangleIndices,includedTriangleIndices)]; %#ok<AGROW>
end
% filter single triangles
convexTriangleSets(cellfun(@length,convexTriangleSets) == 1) = [];
% filter unique sets; convert to string because matlab cannot unique a cell array
[~,c] = unique(cellfun(@(x) sprintf('%d,',x),convexTriangleSets,'UniformOutput',false));
convexTriangleSets = convexTriangleSets(c);
% plot result
n = ceil(sqrt(length(convexTriangleSets)));
for kk = 1:length(convexTriangleSets)
subplot(n,n,kk)
triplot(DT,'k')
hold on
patch('faces',DT(convexTriangleSets{kk},:), 'vertices', DT.Points, 'FaceColor','r');
end
end
答案 1 :(得分:1)
希望您可以使用以下代码行解答您的一些疑虑
多边形的凸性
假设您有一组三角形,那么您应该删除该多边形内的所有点,即只查看多边形边界处的点。您可以使用while函数
检查点是否在多边形内部##
在这种情况下,所有角度需要小于180°的条件我认为是足够的。您也可以创建一个凸包,并检查该集是否相同。使用inpolygon
[in,on] = inpolygon(xq,yq,xv,yv);
是较大的子集吗?
您要解决的一个问题是,如何检查一个(凸)多边形是否是另一个(凸)多边形的子集。我们假设如下;你有一个目标多边形,你知道该多边形中的所有三角形。接下来,您还知道包含至少一个多边形的所有其他(凸)多边形。然后,您可以再次使用K = convhull(X,Y)
inpolygon
找到所有条件
在这里,我会使用 - 说 - 穷人方法。只需通过所有组合强制循环并检查凸度。 DelaunayTriangulation为您提供了所有三角形的列表。即
x %// target polygon x
y
xt %// test polygon x
yt
in = inpolygon(x, v, xt, yt);
if sum(in)==length(x)
%// target polygon is subset of testpolygon
end
为您提供所有三角形及其点。
delaunayTriangulation类
您已经在使用delaunayTriangulation类,为什么不使用该类的方法?你基本上只需要