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

Matlab 如何计算三维投影的面积?,matlab,computational-geometry,area,triangulation,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

例如,使用下面的代码,我有一个坐标矩阵,其中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

polyarea
是正确的选择,但您需要在每个投影的最后调用它。如果没有,您将在投影的中心有点,并且结果不是一个“简单”多边形。

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

第一步是使用(as)获得每个投影多边形区域的轮廓。应该注意的是,这里使用凸包是合适的,因为您处理的是长方体,它们是凸面对象。我认为您的第二个长方体(位于
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;
下面是情节:

如果您想计算每个多边形投影的面积并将其相加,这将非常简单:只需更改上面的循环,即可捕获调用
convxhull
的第二个输出并求和:

totalArea = 0;
for iPoly = 1:nPoly
  [~, cuboidArea] = convhull(xPoly{iPoly}, zPoly{iPoly});
  totalArea = totalArea+cuboidArea;
end
但是,如果需要多边形并集的面积,则必须考虑重叠。你有几个选择。如果有,那么可以使用函数获取轮廓,然后使用计算其面积。您还可以在上找到一些实用程序(如和)。我将在这里向您展示另一种使用。首先,我们可以在创建投影点的三角剖分时使用上面创建的边约束
C

oldState = warning('off', 'all');
DT = delaunayTriangulation(R(:, [1 3]), vertcat(C{:}));
warning(oldState);
这将自动创建受约束边相交的新顶点。不幸的是,它还将在所有点的凸包上执行三角剖分,填充我们不希望填充的点。下面是三角测量的样子:

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

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

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

注意:上述代码已被推广用于任意数量的长方体。

第一步是使用(as)获得每个投影多边形区域的轮廓。应该注意的是,这里使用凸包是合适的,因为您处理的是长方体,它们是凸面对象。我认为您的第二个长方体(位于
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;
下面是情节:

如果您想计算每个多边形投影的面积并将其相加,这将非常简单:只需更改上面的循环,即可捕获调用
convxhull
的第二个输出并求和:

totalArea = 0;
for iPoly = 1:nPoly
  [~, cuboidArea] = convhull(xPoly{iPoly}, zPoly{iPoly});
  totalArea = totalArea+cuboidArea;
end
但是,如果需要多边形并集的面积,则必须考虑重叠。你有几个选择。如果有,那么可以使用函数获取轮廓,然后使用计算其面积。您还可以在上找到一些实用程序(如和)。我将在这里向您展示另一种使用。首先,我们可以在创建投影点的三角剖分时使用上面创建的边约束
C

oldState = warning('off', 'all');
DT = delaunayTriangulation(R(:, [1 3]), vertcat(C{:}));
warning(oldState);
这将自动创建受约束边相交的新顶点。不幸的是,它还将在所有点的凸包上执行三角剖分,填充我们不希望填充的点。下面是三角测量的样子:

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

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

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

注意:上述代码已被推广用于任意数量的长方体。

我试图将此代码扩展到具有for循环的多个长方体,但在测试具有3个建筑的a矩阵时,我得到了面积上的差异。我做错了什么?@g0dspl4y:我在回答的末尾添加了一个通用版本。@g0dspl4y:我修复了代码的最后一步。这是一个关于
自由边界
连接独立区域的问题。新方法更简单,现在应该可以弥补差距了。答案很好+1.@g0dspl4y:这对未旋转的数据来说是正确的。你忘了先应用旋转吗?我试图用for循环将这个代码扩展到多个长方体,但在测试3个建筑的a矩阵时,我得到了面积上的差异。我做错了什么?@g0dspl4y:我在回答的末尾添加了一个通用版本。@g0dspl4y:我修复了代码的最后一步。这是一个关于
自由边界
连接独立区域的问题。新方法更简单,现在应该可以弥补差距了。答案很好+1.@g0dspl4y:这对未旋转的数据来说是正确的。您是否忘记先应用旋转?