形成凸包的三角形的组合

时间:2016-02-07 14:58:27

标签: matlab geometry delaunay set-union

我有一组三角形。我正在寻找一种方法来找到这些三角形的所有组合,这些三角形在连接在一起时构成一个凸包。凸壳应该是空的,即。仅在边缘上的凸包内没有点。并且只有共享一侧的三角形可以连接在一起,即。工会没有差距。

示例:以下几点给出了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));

12 triangles

我正在寻找最大的凸包,因此凸包应该包括尽可能多的三角形。但如果我拥有所有可能的组合,我可以轻松过滤出三角形较少的组合。在上面的例子中,我应该得到这六个凸包:

6 convex hulls

我猜我应该使用每个三角形最多有三个相邻的三角形(每边一个)。并且我应该检查角度的总和是否在相交点处小于或等于180度。这将确保联合是凸的 - 见下图。 (如果几个三角形形成一个完整的圆,角度也可能正好是360度。)

5 convex hulls

三角形角度:

% 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度)。

2 个答案:

答案 0 :(得分:2)

这个答案可以通过一个简单的递归算法来解决:

  1. 从任何三角形开始
  2. 查找与此三角形共享边缘的所有三角形
  3. 对于这些三角形中的每一个,检查此组是否为凸。
    • 如果不是凸起则停止
    • 添加连接到最后添加的三角形的三角形以设置仍需要测试
  4. 所以这个算法是递归的,因为它贪婪地尝试向集合中添加更多三角形,直到它不再凸起为止。下面的代码给出了这个结果(我省略了所有琐碎的(1个三角形)答案。

    检查凸包中是否没有内部点有点天真:构造凸包并查看是否所有点都在其上。

    enter image description here

    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类,为什么不使用该类的方法?你基本上只需要

  1. convhull
  2. Check if triangulation is subset of other triangulation
  3. Get boundary points of triangulation.
  4. 你需要更多吗?