function h = ezplot3(varargin)
% EZPLOT3  Easy to use 3-d parametric curve plotter.
%   EZPLOT3(x,y,z) plots the spatial curve x = x(t), y = y(t),
%   and z = z(t) over the default domain 0 < t < 2*pi.
%
%   EZPLOT3(x,y,z,[tmin,tmax]) plots the curve x = x(t), y = y(t),
%   and z = z(t) over tmin < t < tmax.
%
%   EZPLOT3(x,y,z,'animate') or EZPLOT(x,y,z,[tminm,tmax],'animate')
%   produces an animated trace of the spatial curve.
%   
%   Examples:
%     The functions x, y, and z can be specified using @, an inline
%     object, or an expression.  M-file functions and inline functions
%     must be written to accept vector inputs:
%        fy = inline('t .* sin(t)')
%        ezplot3(@cos, fy, @sqrt)
%        ezplot3('cos(t)', 't * sin(t)', 'sqrt(t)', [0,6*pi])
%        ezplot3(@cos, fy, @sqrt, 'animate')
%
%  See also EZPLOT, EZSURF, EZPOLAR, PLOT, PLOT3

%   Copyright 1984-2000 The MathWorks, Inc. 
%   $Revision: 1.6 $
%   P. J. Costa ans Z. You 

clf;

% Check each input function or expression
[x,x0,xargs] = ezfcnchk(varargin{1},0,'t');
[y,y0,yargs] = ezfcnchk(varargin{2},0,'t');
[z,z0,zargs] = ezfcnchk(varargin{3},0,'t');

allargs = union(xargs,union(yargs,zargs));
numargs = length(allargs);
if (ismember({''},allargs)), numargs = max(1, numargs-1); end
if (numargs == 2)
   error('To plot parametrized surfaces, use EZSURF')
elseif (numargs > 2)
   error('Functions must take one argument.');
end

Aflag = 0; % Animation option.

Npts = 300;

% Determine the domain in t:
switch nargin
   case 3
      T =  linspace(0,2*pi,Npts);
   case 4
      if isa(varargin{4},'double')   
         T = linspace(varargin{4}(1),varargin{4}(2),Npts);
      elseif isequal(varargin{4},'animate')
         Aflag = 1;
         T =  linspace(0,2*pi,Npts);
      else
         T =  linspace(0,2*pi,Npts);
      end
   case 5
      if isa(varargin{4},'double') & isequal(varargin{5},'animate') 
         T = linspace(varargin{4}(1),varargin{4}(2),Npts);
         Aflag = 1;
      elseif isequal(varargin{4},'animate') & isa(varargin{5},'double')
         T = linspace(varargin{5}(1),varargin{5}(2),Npts);
         Aflag = 1;
      else
         T = linspace(0,2*pi,Npts);
      end
end

H = findobj(gcf,'Type','uicontrol','String','Repeat');
if ~isempty(H) & ~Aflag
   delete(H);
end

% Evaluate each of (X,Y,Z)
X = feval(x,T);
if prod(size(X)) == 1
   X = X*ones(size(T));
end
Y = feval(y,T);
if prod(size(Y)) == 1
   Y = Y*ones(size(T));
end
Z = feval(z,T);
if prod(size(Z)) == 1
   Z = Z*ones(size(T));
end

% Option to Return a handle.
if nargout ~= 0
   h = plot3(X,Y,Z);
else
   plot3(X,Y,Z);
end
xlabel('x'); ylabel('y'); zlabel('z');
title(['x = ' texlabel(x0), ', y = ' texlabel(y0), ', z = ' texlabel(z0)]);
grid on;

if Aflag
   hold on;
   H = plot3(X(1),Y(1),Z(1),'r.','erasemode','xor','markersize',24);

   dk = ceil(length(Y)/Npts);
   for k = 1:dk:length(Y)
      set(H,'xdata',X(k),'ydata',Y(k),'zdata',Z(k));
      drawnow;
   end
   % Slow down the animation for each machine architecture.
   tic, for i = 1:1000, j = i*i; end, tm = toc;
   tm = floor(10/tm);
   % Define the userdata for the callback.
   ud.x = X; ud.y = Y; ud.z = Z; ud.dk = dk; ud.h = H; ud.tm = tm;
   set(gcf,'userdata',ud);
   % Define the callback string.
   s = ['ud = get(gcf,''userdata'');' ...
        'hold on;' ...
        'tm = ud.tm;' ...
        'for k = 1:ud.dk:length(ud.y),' ...
           'set(ud.h,''xdata'',ud.x(k),''ydata'',ud.y(k),''zdata'',ud.z(k));' ...
           'for i = 1:tm, j = i*i; end,' ...
           'drawnow;' ...
        'end,' ...
        'hold off;'];
   uicontrol('Units','normal','Position',[.02 .01 .1 .06], ...
             'String','Repeat','CallBack',s);

end
