如何在Matlab中将3D路径数据绘制为功能区

问题描述

我在3D中有散射数据X1,Y1,Z1,我可以将其绘制为

a=1; c=1; t=0:100;
X1 = (a*t/2*pi*c).*sin(t);
Y1 = (a*t/2*pi*c).*cos(t);
Z1 = t/(2*pi*c);
scatter3(X1,Z1);
% or plot3(X1,Z1);

这些点定义3D路径。如何将其制作成类似于下面的功能区图?

使用delaunay三角剖分,我可以将其绘制为曲面:

tri = delaunay(X1,Y1); h = trisurf(tri,X1,Z1);

但是ribbon并没有达到期望的结果:

ribbon(Y1)

下图显示了我的追求。

,

解决方法

ribbon函数只能接受2D输入,因为它使用第3维来“构建”功能区。

获得3D功能区的一种方法是在每个点之间构建一系列patchsurface并正确定向它们,使它们看起来连续。

以下代码将在由(x,y,z)矢量定义的任意3D路径周围构建功能区。我不会解释代码的每一行,但是有很多注释,我停下来进行中间可视化,以便您可以了解其构造。

%% Input data
a=1; c=1; t=0:.1:100;
x = (a*t/2*pi*c).*sin(t);
y = (a*t/2*pi*c).*cos(t);
z = t/(2*pi*c);

nPts = numel(x) ;

%% display 3D path only
figure;
h.line = plot3(x,z,'k','linewidth',2,'Marker','none');
hold on
xlabel('X')
ylabel('Y')
zlabel('Z')

Base path

%% Define options
width = ones(size(x)) * .4 ;

% define surface and patch display options (FaceAlpha etc ...),for later
surfoptions  = {'FaceAlpha',0.8,'EdgeColor','EdgeAlpha','DiffuseStrength',1,'AmbientStrength',1 } ;

%% get the gradient at each point of the curve
Gx = diff([x,x(1)]).' ;
Gy = diff([y,y(1)]).' ;
Gz = diff([z,z(1)]).' ;
% get the middle gradient between 2 segments (optional,just for better rendering if low number of points)
G = [ (Gx+circshift(Gx,1))./2 (Gy+circshift(Gy,1))./2 (Gz+circshift(Gz,1))./2] ;

%% get the angles (azimuth,elevation) of each plane normal to the curve

ux = [1 0 0] ;
uy = [0 1 0] ;
uz = [0 0 1] ;

for k = nPts:-1:1 % running the loop in reverse does automatic preallocation
    a = G(k,:) ./ norm(G(k,:)) ;
    angx(k) =  atan2( norm(cross(a,ux)),dot(a,ux))  ;
    angy(k) =  atan2( norm(cross(a,uy)),uy))  ;
    angz(k) =  atan2( norm(cross(a,uz)),uz))  ;
    
    [az(k),el(k)] = cart2sph( a(1),a(2),a(3) ) ;
end
% compensate for poor choice of initial cross section plane
az = az + pi/2 ; 
el = pi/2 - el ;


%% define basic ribbon element
npRib = 2 ;
xd = [ 0 0] ;
yd = [-1 1] ;
zd = [ 0 0] ;

%% Generate coordinates for each cross section

cRibX = zeros( nPts,npRib ) ;
cRibY = zeros( nPts,npRib ) ;
cRibZ = zeros( nPts,npRib ) ;
cRibC = zeros( nPts,npRib ) ;

for ip = 1:nPts
    % cross section coordinates.
    csTemp = [ ( width(ip) .* xd )  ; ... %// X coordinates
               ( width(ip) .* yd )  ; ... %// Y coordinates
                               zd    ] ;   %// Z coordinates
    
    %// rotate the cross section (around X axis,around origin)
    elev = el(ip) ;
    Rmat = [ 1     0           0     ; ...
             0 cos(elev)  -sin(elev) ; ...
             0 sin(elev)   cos(elev) ] ;
    csTemp = Rmat * csTemp ;
    
    %// do the same again to orient the azimuth (around Z axis)
    azi = az(ip) ;
    Rmat = [ cos(azi)  -sin(azi) 0 ; ...
             sin(azi)   cos(azi) 0 ; ...
               0            0    1 ] ;
    csTemp = Rmat * csTemp ;
    
    %// translate each cross section where it should be and store in global coordinate vector
    cRibX(ip,:) = csTemp(1,:) + x(ip) ;
    cRibY(ip,:) = csTemp(2,:) + y(ip) ;
    cRibZ(ip,:) = csTemp(3,:) + z(ip) ;
end

%% Display the full ribbon
hd.cyl = surf( cRibX,cRibY,cRibZ,cRibC ) ;
set( hd.cyl,surfoptions{:} )

3D ribbon,contruction lines

现在,您的图形对象包含在一个曲面对象中,您可以设置最终渲染的选项。例如(仅作为示例,探索surface对象属性以找到所有可能性)。

%% Final render
h.line.Visible = 'off' ;
surfoptionsfinal  = {'FaceAlpha','none',1 } ;
set( hd.cyl,surfoptionsfinal{:} )
axis off

final render


请注意,此代码是对此answer(针对该问题:Matlab: “X-Ray” plot line through patch)中提供的代码的改编(简化)。

此方法允许绘制任意横截面(答案中为光盘)并构建将遵循路径的表面。对于您的问题,我用一条简单的线替换了disc横截面。您也可以将其替换为任意横截面(圆盘,正方形,马铃薯状的形状……是极限)。


编辑

替代方法:

事实证明,有一个Matlab函数可以做到这一点。我首先将其丢弃是因为它是用于3D 体积可视化的,并且大多数调用它的方法都需要网格输入(meshgrid样式)。对我们来说幸运的是,还有一种调用语法可以处理您的数据。

% Same input data
a=1; c=1; t=0:.1:100;
x = (a*t/2*pi*c).*sin(t);
y = (a*t/2*pi*c).*cos(t);
z = t/(2*pi*c);

% Define vertices (and place in cell array)
verts = {[x.',y.',z.']};
% Define "twistangle". We do not need to twist it in that direction but the
% function needs this input so filling it with '0'
twistangle = {zeros(size(x.'))} ;
% call 'streamribbon',the 3rd argument is the width of the ribbon.
hs = streamribbon(verts,tw,0.4) ;

% improve rendering
view(25,9)
axis off
shading interp;
camlight
lighting gouraud

将呈现下图: enter image description here

对于其他图形控制(在功能区的边缘),可以参考此问题和我的答案:MATLAB streamribbon edge color