function tubeplot3(x,y,z,varargin) %tubeplot3(x,y,z) % % plot curve as tube % x,y,z contain coordinates of points on curve as in plot3(x,y,z) % %optional arguments width, color: (can be given in any order) % % tubeplot(x,y,z,width,color) % % width: thickness of tube % color: 'r', 'g', 'b', 'c', 'm', 'y', 'k' % or 'red','green','blue','cyan','magenta','yellow','black' % or [r g b]: e.g. [1 0 0] for red % or vector of the same size as x,y,z: color according to vector % % default for color is rainbow colored according to z coordinate % ( same as tubeplot3(x,y,z,z) ) % %Examples: % t = 0:.1:20; % tubeplot3(cos(t), sin(t), t); axis equal % tubeplot3(cos(t), sin(t), t, 2, 'r'); axis equal width = []; color = []; colorv = []; for i=1:length(varargin) a = varargin{i}; if isa(a,'double') & length(a)==1 width = a; else if isa(a,'double') & length(a)>3 colorv = a; else color = a; end end end v{1} = [x(:),y(:),z(:)]; daspect([1 1 1]) if isempty(width) % streamtube0(v) streamtube0(colorv,v) else % streamtube0(v,width) streamtube0(colorv,v,width) end view(3); camlight lighting gouraud h = get(gca,'children'); if ~isempty(color) set(h(2),'FaceColor',color,'EdgeColor','none'); else set(h(2),'FaceColor','interp','EdgeColor','none'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function hout=streamtube0(colorv,varargin) % modified from streamtube %STREAMTUBE 3D stream tube. % Copyright 1984-2001 The MathWorks, Inc. % $Revision: 1.6 $ $Date: 2001/04/15 12:04:13 $ [x, y, z, u, v, w, sx, sy, sz, verts, div, width, scale, n] = ... parseargs(nargin-1,varargin); if any(isnan(u(:))) | any(isnan(v(:))) | any(isnan(w(:))) error('Vector data U,V,W must not contain any NaNs') end if isempty(n), n=20; end if isempty(scale), scale=1; end % Calculate the vertices if isempty(verts) [msg x y z] = xyzuvwcheck(x,y,z,u,v,w); error(msg) verts = stream3(x,y,z,u,v,w,sx,sy,sz); end dar = []; f = get(0, 'currentfigure'); if ~isempty(f) ax = get(f, 'currentaxes'); if ~isempty(ax) & strcmp(get(ax, 'dataaspectratiomode'), 'manual') dar = get(ax, 'dataaspectratio'); end end if isempty(dar) vv = cat(1,verts{:}); if isempty(vv) dar = [1 1 1]; else dar = max(vv,[],1) - min(vv,[],1); dar(dar==0) = 1; end end dar = dar/max(dar); % Calculate and scale the widths from the divergence if isempty(width) if ~isempty(u) & isempty(div) div = divergence(x,y,z,u,v,w); end for k = 1:length(verts) vv = verts{k}; if ~isempty(vv) if ~isempty(div) if ~isempty(x) divi{k} = interp3(x,y,z,div,vv(:,1), vv(:,2), vv(:,3)); else divi{k} = interp3(div,vv(:,1), vv(:,2), vv(:,3)); end end vertminmax(k,:) = [min(vv,[],1) max(vv,[],1)]; else divi{k} = []; vertminmax(k,:) = [nan nan nan nan nan nan]; end end vertmin = min(vertminmax(:,1:3),[],1); vertmax = max(vertminmax(:,4:6),[],1); maxwidth = .05*max((vertmax-vertmin)./dar); if ~isempty(div) for k = 1:length(divi) if scale==0 width{k} = divi{k}; else divrange = max(divi{k})-min(divi{k}); if divrange>0 width{k} = (divi{k}-min(divi{k}))/divrange *maxwidth*scale; else width{k} = maxwidth*scale; end end end else width = maxwidth*scale; end else if iscell(width) for k = 1:length(width) width{k} = width{k}*scale; end else width = width*scale; end end h = []; for k = 1:length(verts) vv = verts{k}; if ~isempty(vv) & size(vv,1)>1 if iscell(width) [xv yv zv] = tubecoords(vv,width{k},n,dar); else [xv yv zv] = tubecoords(vv,width,n,dar); end if isempty(colorv) surf(xv,yv,zv); else cv = repmat(colorv(:),1,n+1); surf(xv,yv,zv,cv); end % h = [h; surface(xv,yv,zv,cv)]; end end if nargout>0 hout = h; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [x,y,z]=tubecoords(verts,width,n,dar) verts(:,1) = verts(:,1)/dar(1); verts(:,2) = verts(:,2)/dar(2); verts(:,3) = verts(:,3)/dar(3); d1 = diff(verts); zindex = find(~any(d1,2)); verts(zindex,:) = []; if size(verts,1)<2 x = []; y = []; , z = []; return; end d1 = diff(verts); numverts = size(verts,1); unitnormals = zeros(numverts,3); % Radius of the tube. if length(width)==1 width = repmat(width, [numverts,1]); else width(zindex) = []; end R = width/2; d1(end+1,:) = d1(end,:); x10 = verts(:,1)'; x20 = verts(:,2)'; x30 = verts(:,3)'; x11 = d1(:,1)'; x21 = d1(:,2)'; x31 = d1(:,3)'; a = verts(2,:) - verts(1,:); b = [0 0 1]; c = crossSimple(a,b); if ~any(c) b = [1 0 0]; c = crossSimple(a,b); end b = crossSimple(c,a); normb = norm(b); if normb~=0, b = b/norm(b); end %b = b*R(1); unitnormals(1,:) = b; for j = 1:numverts-1; a = verts(j+1,:)-verts(j,:); c = crossSimple(a,b); b = crossSimple(c,a); normb = norm(b); if normb~=0, b = b/norm(b); end % b = b*R(j); unitnormals(j+1,:) = b; end unitnormal1 = unitnormals(:,1)'; unitnormal2 = unitnormals(:,2)'; unitnormal3 = unitnormals(:,3)'; speed = sqrt(x11.^2 + x21.^2 + x31.^2); % And the binormal vector ( B = T x N ) binormal1 = (x21.*unitnormal3 - x31.*unitnormal2) ./ speed; binormal2 = (x31.*unitnormal1 - x11.*unitnormal3) ./ speed; binormal3 = (x11.*unitnormal2 - x21.*unitnormal1) ./ speed; % s is the coordinate along the circular cross-sections of the tube: s = (0:n)'; s = (2*pi/n)*s; % Finally, the parametric surface. % Each of x1, x2, x3 is an (m+1)x(n+1) matrix. % Rows represent coordinates along the tube. Columns represent coordinates % sgcfin each (circular) cross-section of the tube. xa1 = ones(n+1,1)*x10; xb1 = (cos(s)*unitnormal1 + sin(s)*binormal1); xa2 = ones(n+1,1)*x20; xb2 = (cos(s)*unitnormal2 + sin(s)*binormal2); xa3 = ones(n+1,1)*x30; xb3 = (cos(s)*unitnormal3 + sin(s)*binormal3); R = repmat(R(:)',[n+1,1]); x1 = xa1 + R.*xb1; x2 = xa2 + R.*xb2; x3 = xa3 + R.*xb3; %x1 = xa1 + xb1; %x2 = xa2 + xb2; %x3 = xa3 + xb3; x = x1' *dar(1); y = x2' *dar(2); z = x3' *dar(3); %nx = unitnormal1; %ny = unitnormal2; %nz = unitnormal3; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % simple cross product function c=crossSimple(a,b) c(1) = b(3)*a(2) - b(2)*a(3); c(2) = b(1)*a(3) - b(3)*a(1); c(3) = b(2)*a(1) - b(1)*a(2); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [x, y, z, u, v, w, sx, sy, sz, verts, div, width, scale, n] = parseargs(nin, vargin) x = []; y = []; z = []; u = []; v = []; w = []; sx = []; sy = []; sz = []; verts = []; div = []; width = []; scale = []; n = []; if (nin==6 | nin==7) & ~iscell(vargin{1}) % streamtube(u,v,w,sx,sy,sz) or streamtube(u,v,w,sx,sy,sz,scale) u = vargin{1}; v = vargin{2}; w = vargin{3}; sx = vargin{4}; sy = vargin{5}; sz = vargin{6}; if nin==7, scale = vargin{7}; end elseif nin==9 | nin==10 % streamtube(x,y,z,u,v,w,sx,sy,sz) or streamtube(x,y,z,u,v,w,sx,sy,sz,scale) x = vargin{1}; y = vargin{2}; z = vargin{3}; u = vargin{4}; v = vargin{5}; w = vargin{6}; sx = vargin{7}; sy = vargin{8}; sz = vargin{9}; if nin==10, scale = vargin{10}; end elseif (nin==2 | nin==3 ) & ... (length(size(vargin{2}))==3 | ... iscell(vargin{2}) | ... prod(size(vargin{2}))==1) % streamtube(verts,divergence) or streamtube(verts,divergence,scale) % streamtube(verts,width) or streamtube(verts,width,scale) verts = vargin{1}; if length(size(vargin{2}))==3 div = vargin{2}; else width = vargin{2}; end if nin==3, scale = vargin{3}; end elseif nin==5 | nin==6 % streamtube(verts,x,y,z,divergence) or streamtube(verts,x,y,z,divergence,scale) verts = vargin{1}; x = vargin{2}; y = vargin{3}; z = vargin{4}; div = vargin{5}; if nin==6, scale = vargin{6}; end elseif nin==1 | nin==2 % streamtube(verts) or streamtube(verts,scale) verts = vargin{1}; if nin==2, scale = vargin{2}; end else error('Wrong number of input arguments.'); end if ~isempty(sx) sx = sx(:); sy = sy(:); sz = sz(:); end if ~isempty(scale) if length(scale) == 2 n = scale(2); scale = scale(1); else error('[SCALE N] must be a 2 element vector.'); end end %%%%%%%%%%%%%%%%%%%%%%%%%%% function [msg,nx,ny,nz] = xyzuvwcheck(x,y,z,u,v,w) %XYZUVWCHECK Check arguments to 3D vector data routines. % [MSG,X,Y,Z] = XYZCHK(X,Y,Z,U,V,W) checks the input aguments % and returns either an error message in MSG or valid X,Y,Z. % Copyright 1984-2001 The MathWorks, Inc. % $Revision: 1.5 $ $Date: 2001/04/15 12:04:02 $ msg = ''; nx = x; ny = y; nz = z; sz = size(u); if ~isequal(size(v), sz) | ~isequal(size(w), sz) msg='U,V,W must all be the same size.'; return end if ndims(u)~=3 msg='U,V,W must all be a 3D arrays.'; return end if min(sz)<2 msg = 'U,V,W must all be size 2x2x2 or greater.'; return end nonempty = ~[isempty(x) isempty(y) isempty(z)]; if any(nonempty) & ~all(nonempty) msg = 'X,Y,Z must all be empty or all non-empty.'; return; end if ~isempty(nx) & ~isequal(size(nx), sz) nx = nx(:); if length(nx)~=sz(2) msg='The size of X must match the size of U or the number of columns of U.'; return else nx = repmat(nx',[sz(1) 1 sz(3)]); end end if ~isempty(ny) & ~isequal(size(ny), sz) ny = ny(:); if length(ny)~=sz(1) msg='The size of Y must match the size of U or the number of rows of U.'; return else ny = repmat(ny,[1 sz(2) sz(3)]); end end if ~isempty(nz) & ~isequal(size(nz), sz) nz = nz(:); if length(nz)~=sz(3) msg='The size of Z must match the size of U or the number of pages of U.'; return else nz = repmat(reshape(nz,[1 1 length(nz)]),[sz(1) sz(2) 1]); end end