如何计算三维投影的面积?

时间:2017-11-20 18:16:44

标签: matlab computational-geometry area triangulation

例如,使用下面的代码,我有一个坐标矩阵,其中3个立方体对象各自由8个角定义,总共24个坐标。我对我的坐标应用旋转,然后删除y坐标以获得x-z平面中的投影。如何在x-z平面中计算这些立方体的面积,忽略间隙并考虑重叠?我尝试过使用polyarea,但这似乎不起作用。

clear all
clc
A=[-100 -40 50
-100    -40 0
-120    -40 50
-120    -40 0
-100    5   0
-100    5   50
-120    5   50
-120    5   0
-100    0   52
-100    0   52
20  0   5
20  0   5
-100    50  5
-100    50  5
20  50  52
20  50  52
-30 70  53
-30 70  0
5   70  0
5   70  53
-30 120 53
-30 120 0
5   120 53
5   120 0]; %3 Buildings Coordinate Matrix
theta=60; %Angle
rota = [cosd(theta) -sind(theta) 0; sind(theta) cosd(theta) 0; 0 0 1]; %Rotation matrix
R=A*rota; %rotates the matrix
R(:,2)=[];%deletes the y column

2 个答案:

答案 0 :(得分:3)

第一步是使用convhull(作为yar suggests)来获取每个投影多边形区域的轮廓。应该注意的是,凸起的船体适合在这里使用,因为你正在处理长方体,它们是凸起的物体。我认为你的第二个长方体的坐标有错误(位于A(9:16, :)),所以我将你的代码修改为以下内容:

A = [-100   -40    50
     -100   -40     0
     -120   -40    50
     -120   -40     0
     -100     5     0
     -100     5    50
     -120     5    50
     -120     5     0
     -100     0    52
     -100     0     5
       20     0    52
       20     0     5
     -100    50     5
     -100    50    52
       20    50     5
       20    50    52
      -30    70    53
      -30    70     0
        5    70     0
        5    70    53
      -30   120    53
      -30   120     0
        5   120    53
        5   120     0];
theta = 60;
rota = [cosd(theta) -sind(theta) 0; sind(theta) cosd(theta) 0; 0 0 1];
R = A*rota;

您可以生成多边形轮廓并将其可视化:

nPerPoly = 8;
nPoly = size(R, 1)/nPerPoly;
xPoly = mat2cell(R(:, 1), nPerPoly.*ones(1, nPoly));
zPoly = mat2cell(R(:, 3), nPerPoly.*ones(1, nPoly));
C = cell(1, nPoly);
for iPoly = 1:nPoly
  P = convhull(xPoly{iPoly}, zPoly{iPoly});
  xPoly{iPoly} = xPoly{iPoly}(P);
  zPoly{iPoly} = zPoly{iPoly}(P);
  C{iPoly} = P([1:end-1; 2:end].')+nPerPoly.*(iPoly-1);  % Constrained edges, needed later
end

figure();
colorOrder = get(gca, 'ColorOrder');
nColors = size(colorOrder, 1);
for iPoly = 1:nPoly
  faceColor = colorOrder(rem(iPoly-1, nColors)+1, :);
  patch(xPoly{iPoly}, zPoly{iPoly}, faceColor, 'EdgeColor', faceColor, 'FaceAlpha', 0.6);
  hold on;
end
axis equal;
axis off;

这是情节:

enter image description here

如果你想计算每个多边形投影的面积并将它们相加,那将非常简单:只需更改上面的循环即可捕获并汇总调用convexhull的第二个输出:

totalArea = 0;
for iPoly = 1:nPoly
  [~, cuboidArea] = convhull(xPoly{iPoly}, zPoly{iPoly});
  totalArea = totalArea+cuboidArea;
end

然而,如果您想要多边形的 union 区域,则必须考虑重叠。你有几个选择。如果您拥有Mapping Toolbox,则可以使用函数polybool获取大纲,然后使用polyarea计算其区域。您还可以在MathWorks File Exchange上找到实用工具(例如thisthis)。我将在这里向您展示另一种使用delaunayTriangulation的替代方法。首先,我们可以采用上面创建的边缘约束C来创建投影点的三角剖分时使用:

oldState = warning('off', 'all');
DT = delaunayTriangulation(R(:, [1 3]), vertcat(C{:}));
warning(oldState);

这将自动创建约束边相交的新顶点。不幸的是,它还将在所有点的凸包上执行三角测量,填充我们不想填充的点。这是三角测量的样子:

figure();
triplot(DT, 'Color', 'k');
axis equal;
axis off;

enter image description here

我们现在必须确定我们不想要的额外三角形并将其删除。我们可以通过找到每个三角形的质心并使用inpolygon测试它们是否在我们所有3个单独的长方体投影之外来做到这一点。然后我们可以计算剩余三角形的面积并使用polyarea对它们求和,得出投影的总面积:

dtFaces = DT.ConnectivityList;
dtVertices = DT.Points;
meanX = mean(reshape(dtVertices(dtFaces, 1), size(dtFaces)), 2);
meanZ = mean(reshape(dtVertices(dtFaces, 2), size(dtFaces)), 2);
index = inpolygon(meanX, meanZ, xPoly{1}, zPoly{1});
for iPoly = 2:nPoly
  index = index | inpolygon(meanX, meanZ, xPoly{iPoly}, zPoly{iPoly});
end
dtFaces = dtFaces(index, :);
xUnion = reshape(dtVertices(dtFaces, 1), size(dtFaces)).';
yUnion = reshape(dtVertices(dtFaces, 2), size(dtFaces)).';
totalArea = sum(polyarea(xUnion, yUnion));

此示例的总面积为:

totalArea =

     9.970392341143055e+03

注意:以上代码已针对任意数量的长方体进行了推广。

答案 1 :(得分:1)

polyarea是正确的方法,但您需要在每个投影的es6 string interpolation上调用它。如果没有,您将在投影的中心有点,结果不是“简单”多边形。