有关在MATLAB中绘制表面图的问题

时间:2019-10-01 12:19:36

标签: matlab

enter image description here我写了一个用于拓扑优化的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个元素,则绘制图将花费很长时间。 因此,我希望能帮助您更快地完成此任务。

1 个答案:

答案 0 :(得分:1)

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]重大改进:

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

幸运的是,我注意到您的基本坐标实际上组织得很好,可以直接作为patch插入到Matlab中。因此,无需对数据进行解复用/再复用,我们可以直接创建全局色块并为其着色:

% 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"

Voila!无需任何循环或任何计算。首先,您已经拥有所需的所有数据;-)

我建议您阅读patch的文档,尤其是使用属性FaceVertexCData的方式