首页 > 解决方案 > 一个关于在MATLAB中绘制曲面图的问题

问题描述

在此处输入图像描述我写了一个用于拓扑优化的matlab代码。在曲面图中显示结果的代码是:(一个非常简单的示例)

XYZG=[2.5 0 0;2.5 0 2.5;2.5 0 5;0 -2.5 0;0 -2.5 2.5;0 -2.5 5;-2.5 0 0;-2.5 0 2.5;-2.5 0 5];
ELNOD=[1 4 5 2;2 5 6 3;4 7 8 5;5 8 9 6];
nelement=4;
Dens=[0 1 1 0];
for element=1:nelement
for i=1:4
X(i)=XYZG(ELNOD(element,i),1);
Y(i)=XYZG(ELNOD(element,i),2);
Z(i)=XYZG(ELNOD(element,i),3);
end

XX=[X(1) X(2);X(4) X(3)];
YY=[Y(1) Y(2);Y(4) Y(3)];
ZZ=[Z(1) Z(2);Z(4) Z(3)];
tick=-Dens(element)*[1 1;1 1]; 
figure(1)
hold on
surf(XX,YY,ZZ,tick); 
colormap gray; 
end 

这段代码太慢了。例如,如果我有 10,000 个元素,则绘制绘图需要很长时间。因此,我将不胜感激有关如何加快速度的任何帮助。

标签: matlab

解决方案


1] 小改进:

您作为示例提供的代码可以简化以避免临时分配。考虑以下:

%% Sample data
XYZG=[2.5 0 0;2.5 0 2.5;2.5 0 5;0 -2.5 0;0 -2.5 2.5;0 -2.5 5;-2.5 0 0;-2.5 0 2.5;-2.5 0 5];
ELNOD=[1 4 5 2;2 5 6 3;4 7 8 5;5 8 9 6];
nelement=4;
Dens=[0 1 1 0];

%% pre-initialisation just to set the size (size=[2,2])
XX = zeros(2) ;
YY = XX ;
ZZ = XX ;

figure(1)
hold on
colormap gray;

for element=1:nelement

    % Base vector combining (unused now)
    %   idx=1:4;
    %   X = XYZG( ELNOD(element,idx),1 ).';
    %   Y = XYZG( ELNOD(element,idx),2 ).';
    %   Z = XYZG( ELNOD(element,idx),3 ).';

    % The block above is commented because we do not need these intermediate
    % vectors to build the base matrices XX, YY and ZZ.

    % This can be done directly using linear indexing:
    idxOrder = [1 4 2 3] ;
    XX(1:4) = XYZG( ELNOD(element,idxOrder) , 1 ) ;
    YY(1:4) = XYZG( ELNOD(element,idxOrder) , 2 ) ;
    ZZ(1:4) = XYZG( ELNOD(element,idxOrder) , 3 ) ;

    tick=-Dens(element)*[1 1;1 1]; 

    surf(XX,YY,ZZ,tick) ; 
end

这应该稍微快一点。由于避免了一些临时数组。我们现在更直接地构建每个补丁坐标。此外,只需要使用一次的函数调用也已从循环中取出(如果您的循环花费的时间太长,通常要寻找的东西)。

现在这无论如何都不会令人满意。结构中的真正瓶颈与其说是每次循环迭代中的计算/索引,不如说是系统必须维护的图形句柄数量不断增加。循环的每次迭代都会创建一个surface对象。这些对象需要内存来保持它们的坐标,还要保持大量的内部属性。一旦你将这些对象相乘,你的系统就会开始变慢。一些系统甚至可能无法在同一个图形上创建 10,000 个表面图形对象,如果可以的话,这将是一个缓慢的痛苦(你知道这些情况,你点击屏幕并等待大约 25 秒以注意到任何反应...... )。


2]主要改进:

限制图形对象数量的一种方法是组合所有这些坐标以创建单个图形对象。当然,我们必须根据您的规则为每张脸着色。

幸运的是,我注意到您的基本坐标实际上组织得很好,可以直接作为patchMatlab 中的 a 注入。所以不需要解复用/重新复用输入和输出的数据,我们可以直接创建和着色全局补丁:

% create a Black and White colormap
cmap = [1 1 1;
        0 0 0] ;

figure
% generate a patch with all the 'faces','vertices' and 'color' data :-)
hp = patch('Faces',ELNOD, 'Vertices',XYZG, 'FaceVertexCData',Dens(:) ) ;
% last refinement to have the same appearance than in former code
shading flat
colormap(cmap)
hp.EdgeColor = 'k' ; % <= this needs to be executed AFTER "shading flat"

瞧!不需要任何循环或任何计算。您已经拥有了所有需要的数据;-)

我鼓励您阅读 的文档patch,尤其是使用该属性的方式FaceVertexCData


推荐阅读