MATLAB - 3D 曲面图
MATLAB - 3D surface plot
我有 20 个 3D 数据点 space。在这里你可以看到他们绘制:
clear all
close all
clc
Data = [97.4993 104.3297 0.7500 196.7021
100.0000 105.0000 0.7500 290.9164
100.0000 107.5000 0.7500 142.1626
96.2569 106.4992 0.7500 143.3605
97.5028 104.3317 1.0000 197.1111
100.0000 105.0000 1.0000 290.4210
100.0000 107.5000 1.0000 144.0155
96.2530 106.4969 1.0000 144.0969
98.7055 104.8295 0.7500 239.7734
100.0000 106.2500 0.7500 214.6557
98.0627 107.2455 0.7500 145.4154
96.8781 105.4144 0.7500 161.7000
97.5010 104.3307 0.8750 196.8880
100.0000 105.0000 0.8750 290.6686
100.0000 107.5000 0.8750 141.5008
96.2549 106.4980 0.8750 144.0253
98.7075 104.8300 1.0000 239.3455
100.0000 106.2500 1.0000 215.2104
98.0605 107.2449 1.0000 144.9653
96.8779 105.4143 1.0000 161.4253];
x = Data(:,1); % x coordinates
y = Data(:,2); % y coordinates
z = Data(:,3); % z coordinates
sigma = Data(:,4); % stress value at that point
for ii = 1:length(x)
plot3(x(ii,1),y(ii,1),z(ii,1),'r*')
hold on
grid on
text(x(ii,1),y(ii,1),z(ii,1),[' ' num2str(ii) ' '...
num2str(sigma(ii))],'HorizontalAlignment','left','FontSize',12);
end
此数据表示一个 HEX20 单元 (FEM) 及其 20 个节点。每个节点旁边都写有它的压力值 (sigma)。节点的编号遵循标准程序:
我想绘制如图所示的那个元素的表面。然后(如果可能)我希望根据节点的应力值(颜色映射)对表面进行着色。最终结果应该是这样的:
您本质上是想将数据转换为网格对象。 x,y,z坐标组成Vertices
或点,可以通过连接Vertices
定义Faces
,然后可以设置单个点或Vertex
具有特定的颜色值(在您的情况下为压力值)。要使用 vertices
和 faces
绘制网格,可以使用 patch
方法。
这里最难的部分是你有顶点,但没有面。一种快速尝试的方法是 convhull
,其中 returns 一组点的凸包(考虑收缩包裹点以给出表面)。
所以开始:
patch('Vertices',[x y z],'Faces',convhull(x,y,z),'FaceVertexCData',sigma,'FaceColor','interp');
看看结果如何,如果它不是您想要的,那么您可以更改 faces
。在上面的代码行中,faces = convhull(x,y,z)
。你可能已经知道哪些顶点构成了你的脸,例如Face1 可以是点 2、14 和 9 - faces(1,:) = [2,14,9]
.
此外,如果您想要由四个点组成的面而不是三角形,您的面数组将只是 N×4 而不是 N×3。
您提供的代码和上面的 patch
代码的快速示例结果:
http://uk.mathworks.com/help/matlab/visualize/multifaceted-patches.html
http://uk.mathworks.com/help/matlab/ref/convhull.html
这是构建补丁的另一种方法。您指定一个结构,其中包含点(顶点),然后是面(它们包括哪些点),然后是颜色矢量(您的 sigma
值),然后将批次发送到 patch 函数,它将处理其余的。
然后完成细节(透明度、边缘颜色、绘制点和文本等...)
fv.vertices = Data(:,1:3);
fv.faces = [...
1 9 2 10 3 11 4 12 ;
1 9 2 14 6 17 5 13 ;
5 17 6 18 7 19 8 20 ;
2 10 3 15 7 18 6 14 ;
3 11 4 16 8 19 7 15 ;
4 12 1 13 5 20 8 16 ...
] ;
fv.facevertexcdata = Data(:,4);
hold on
hp = patch(fv,'CDataMapping','scaled','EdgeColor',[.7 .7 .7],'FaceColor','interp','FaceAlpha',1)
hp3 = plot3(x,y,z,'ok','Markersize',6,'MarkerFaceColor','r')
for ii = 1:length(x)
text(x(ii,1),y(ii,1),z(ii,1),{sprintf(' #%d - \sigma:%4.1f',ii,sigma(ii))},...
'HorizontalAlignment','left','FontSize',8,'FontWeight','bold');
end
view(-27,26)
axis equal
axis off
colorbar south
将产生:
编辑:
这比要求 convhull
找到包络稍微乏味一些,但它的优点是尊重元素的实际形状(不关闭节点 9 和 17 附近的向内小体积)。
为避免当面片面不是完全平面时出现图形渲染故障,您可以定义面,使它们都是完全平面的。这意味着定义更多的面孔(我们必须将它们全部分成 2 个),但它解决了故障,现在你所有的面孔都可见。
所以如果你想那样做,只需将上面的面部定义替换为:
fv.faces = [...
1 9 11 4 12 ;
9 2 10 3 11 ;
1 9 17 5 13 ;
9 2 14 6 17 ;
2 10 18 6 14 ;
10 3 15 7 18 ;
3 11 19 7 15 ;
11 4 16 8 19 ;
4 12 20 8 16 ;
12 1 13 5 20 ;
5 17 19 8 20 ;
17 6 18 7 19 ] ;
定义面的方法不止一种,只需要注意faces
向量的每一行,都是定义一个区域的连续点(面会自行闭合,无需重复最后的第一个点关闭曲面)。
我们从 8 点面变成了 5 点面...如果你想 play/refine 你的模型,你可以尝试使用 3 点面,它的工作方式相同。
我有 20 个 3D 数据点 space。在这里你可以看到他们绘制:
clear all
close all
clc
Data = [97.4993 104.3297 0.7500 196.7021
100.0000 105.0000 0.7500 290.9164
100.0000 107.5000 0.7500 142.1626
96.2569 106.4992 0.7500 143.3605
97.5028 104.3317 1.0000 197.1111
100.0000 105.0000 1.0000 290.4210
100.0000 107.5000 1.0000 144.0155
96.2530 106.4969 1.0000 144.0969
98.7055 104.8295 0.7500 239.7734
100.0000 106.2500 0.7500 214.6557
98.0627 107.2455 0.7500 145.4154
96.8781 105.4144 0.7500 161.7000
97.5010 104.3307 0.8750 196.8880
100.0000 105.0000 0.8750 290.6686
100.0000 107.5000 0.8750 141.5008
96.2549 106.4980 0.8750 144.0253
98.7075 104.8300 1.0000 239.3455
100.0000 106.2500 1.0000 215.2104
98.0605 107.2449 1.0000 144.9653
96.8779 105.4143 1.0000 161.4253];
x = Data(:,1); % x coordinates
y = Data(:,2); % y coordinates
z = Data(:,3); % z coordinates
sigma = Data(:,4); % stress value at that point
for ii = 1:length(x)
plot3(x(ii,1),y(ii,1),z(ii,1),'r*')
hold on
grid on
text(x(ii,1),y(ii,1),z(ii,1),[' ' num2str(ii) ' '...
num2str(sigma(ii))],'HorizontalAlignment','left','FontSize',12);
end
此数据表示一个 HEX20 单元 (FEM) 及其 20 个节点。每个节点旁边都写有它的压力值 (sigma)。节点的编号遵循标准程序:
我想绘制如图所示的那个元素的表面。然后(如果可能)我希望根据节点的应力值(颜色映射)对表面进行着色。最终结果应该是这样的:
您本质上是想将数据转换为网格对象。 x,y,z坐标组成Vertices
或点,可以通过连接Vertices
定义Faces
,然后可以设置单个点或Vertex
具有特定的颜色值(在您的情况下为压力值)。要使用 vertices
和 faces
绘制网格,可以使用 patch
方法。
这里最难的部分是你有顶点,但没有面。一种快速尝试的方法是 convhull
,其中 returns 一组点的凸包(考虑收缩包裹点以给出表面)。
所以开始:
patch('Vertices',[x y z],'Faces',convhull(x,y,z),'FaceVertexCData',sigma,'FaceColor','interp');
看看结果如何,如果它不是您想要的,那么您可以更改 faces
。在上面的代码行中,faces = convhull(x,y,z)
。你可能已经知道哪些顶点构成了你的脸,例如Face1 可以是点 2、14 和 9 - faces(1,:) = [2,14,9]
.
此外,如果您想要由四个点组成的面而不是三角形,您的面数组将只是 N×4 而不是 N×3。
您提供的代码和上面的 patch
代码的快速示例结果:
http://uk.mathworks.com/help/matlab/visualize/multifaceted-patches.html http://uk.mathworks.com/help/matlab/ref/convhull.html
这是构建补丁的另一种方法。您指定一个结构,其中包含点(顶点),然后是面(它们包括哪些点),然后是颜色矢量(您的 sigma
值),然后将批次发送到 patch 函数,它将处理其余的。
然后完成细节(透明度、边缘颜色、绘制点和文本等...)
fv.vertices = Data(:,1:3);
fv.faces = [...
1 9 2 10 3 11 4 12 ;
1 9 2 14 6 17 5 13 ;
5 17 6 18 7 19 8 20 ;
2 10 3 15 7 18 6 14 ;
3 11 4 16 8 19 7 15 ;
4 12 1 13 5 20 8 16 ...
] ;
fv.facevertexcdata = Data(:,4);
hold on
hp = patch(fv,'CDataMapping','scaled','EdgeColor',[.7 .7 .7],'FaceColor','interp','FaceAlpha',1)
hp3 = plot3(x,y,z,'ok','Markersize',6,'MarkerFaceColor','r')
for ii = 1:length(x)
text(x(ii,1),y(ii,1),z(ii,1),{sprintf(' #%d - \sigma:%4.1f',ii,sigma(ii))},...
'HorizontalAlignment','left','FontSize',8,'FontWeight','bold');
end
view(-27,26)
axis equal
axis off
colorbar south
将产生:
编辑:
这比要求 convhull
找到包络稍微乏味一些,但它的优点是尊重元素的实际形状(不关闭节点 9 和 17 附近的向内小体积)。
为避免当面片面不是完全平面时出现图形渲染故障,您可以定义面,使它们都是完全平面的。这意味着定义更多的面孔(我们必须将它们全部分成 2 个),但它解决了故障,现在你所有的面孔都可见。 所以如果你想那样做,只需将上面的面部定义替换为:
fv.faces = [...
1 9 11 4 12 ;
9 2 10 3 11 ;
1 9 17 5 13 ;
9 2 14 6 17 ;
2 10 18 6 14 ;
10 3 15 7 18 ;
3 11 19 7 15 ;
11 4 16 8 19 ;
4 12 20 8 16 ;
12 1 13 5 20 ;
5 17 19 8 20 ;
17 6 18 7 19 ] ;
定义面的方法不止一种,只需要注意faces
向量的每一行,都是定义一个区域的连续点(面会自行闭合,无需重复最后的第一个点关闭曲面)。
我们从 8 点面变成了 5 点面...如果你想 play/refine 你的模型,你可以尝试使用 3 点面,它的工作方式相同。