Raw File
animate.m
function animate(w,varargin)
% animate(w) 
%   animates the 2-d passive walking model described by w.
% animate(w, 'numsteps', N) automatically repeats the simulation N times (default 2).
% animate(w, x, framecounts) animates w with the given states given in x
%   (rows of the state vector), and with framecounts containing a list
%   of the number of frames in each step, e.g. [16 16 16] for 3 steps.
% animate(w, 'arrows', 1) also draws arrows for COM velocity
% animate(w, 'save', 1) animates w and saves each frame as an 
%   adobe illustrator file
% animate(w, 'frames', Nframes) draws a certain number of frames per step
% Other options: 'treadmill' display moving treadmill or walk overground;
%   'framedelay' (0.05) how long to wait between frames of animation;
%   'groundlinewidth' how thick the ground line should be, in points;
%   Also drawmodel options such as 'modellinewidth', 'showcomvel', and
%   'showgrfs' (show arrows for COM velocity or ground reaction forces)      

% Art Kuo
% Dependency: This calls drawmodel

% allow a keypress or button press in the figure to stop the animation
keypressed = 0;
set(gcf,'KeyPressFcn', @keypress, 'ButtonDownFcn', @keypress); 

treadmill = 1; % by default, draw a treadmill

%parms = get(w,'parms'); % access model parameters
N = get(w, 'N'); L = 1; R = 0;

% dimensions of objects to be drawn
floorheight = 0.02; 
modellinewidth = 4; groundlinewidth = 2; jointsize = 10; footsize = 6;
footn = 10; % how many segments to draw in the curved foot

debg = 0; % set to 1 if you want a long pause between frames

numsteps = 2; saveflag = 0; nframes = 16; % default values
framedelay = 0.05;

showcomvel = 0; showgrfs = 0;

x0 = []; framecounts = []; % default is to use fixed point

% Allow for flexible input arguments, particularly allowing second argument
% to be x, a list of state vectors to animate. Otherwise assume the
% inputs are property/value pairs.
if nargin == 0
  error('animate: need a walk object as argument');
elseif nargin > 1 % optional arguments
  % figure out if the second argument is an initial condition vector, or a
  % bunch of rows of states
  property_argin = varargin;
  secondargument = property_argin{1};
  if isa(varargin{1}, 'double')      % second argument appears to be a number
    if length(secondargument) == N   % and it's a vector, meaning an initial condition
      x0 = secondargument;
      property_argin = property_argin(2:end); 
    elseif size(secondargument,1) > 1 && size(secondargument,2) == N % it's a matrix of states
      xs = varargin{2}; framecounts = varargin{3}; numsteps = length(framecounts);
      property_argin = property_argin(3:end);
    else
      error('animate: unknown second argument')
    end
  end
  % Step through the optional arguments
  while length(property_argin) >= 2,
    prop = property_argin{1};
    val = property_argin{2};
    property_argin = property_argin(3:end);
    switch prop
      case 'numsteps'
        numsteps = val;
      case 'save'
        saveflag = val; if saveflag, numsteps = 1; end; % only save one step by default
      case 'frames'
        nframes = val;
      case 'treadmill'
        treadmill = val;
      case 'showgrfs'
        showgrfs = val;
      case 'showcomvel'
        showcomvel = val;
      case 'framedelay'
        framedelay = val;
      case 'modellinewidth'
        modellinewidth = val;
      case 'groundlinewidth'
        groundlinewidth = val;

    end
  end
end

% send this to drawmodel
drawmodeloptions = {'modellinewidth', modellinewidth, 'footn', footn, ...
  'jointsize', jointsize, 'footsize', footsize, 'showcomvel', showcomvel, 'showgrfs', showgrfs};

if isempty(framecounts) % we've haven't been supplied with a bunch of states
  [xe,te,xs,ts] = onestep(w, x0, 'anim', nframes); framecounts = length(xs);
end

speedinfo = walkspeed(w); sl = speedinfo.steplength;

% Now numsteps contains the number of steps, framecounts
% contains the number of frames in each step, and
% startindex and endindex contain indices for each step

% Estimate range of walking
distance = numsteps*sl; 

if treadmill % make room for treadmill or overground steps
  xlimit = [-(sl+R)*1.1 sl*1.2];    % horizontal
else
  xlimit = [-(sl+R) distance+0.5*R];% 
end    
ylimit = [-floorheight-0.04 1.02*L];        % vertical limit
if showgrfs, ylimit(1) = ylimit(1) - 0.1; end; % extra room for grf arrows

% Initialize figure with equal axes with correct limits
clf; set(gcf, 'color', [1 1 1]); 
set(gca,'DataAspectRatio',[1 1 1],'Visible','off','NextPlot','Add','XLim',xlimit,'YLim',ylimit);
set(gca,'Units', 'Points'); 
axesinpoints = get(gca,'Position'); ptstodata = diff(xlimit)/axesinpoints(3);

if saveflag % need to provide a bounding box to make the frames consistent when opened in Flash
  hboundingbox = rectangle('Position',[xlimit(1) ylimit(1) diff(xlimit) diff(ylimit)],'Visible','On','FaceColor','w','EdgeColor','none');
end

% Drawmodel will plot the foot's ground contact at (0,0) so let's plot
% the ground and tiles underneath that, taking into account the thickness
% of the lines.
%ygndoffset = -0.5*(groundlinewidth+modellinewidth)*ptstodata; % for curved feet
ygndoffset = -0.5*(groundlinewidth+footsize)*ptstodata; % for point feet
ytileoffset = ygndoffset - 0.5*groundlinewidth*ptstodata;
hgnd = line(xlimit,[1 1]*ygndoffset,'color',[0 0 0],'linewidth',groundlinewidth);

% fill the floor with tiles extending horizontally two extra 
% tiles to the right (one black, one white) so that when the treadmill 
% scrolls left, we always show all tiles

tilelen = sl/4; % tile length, equal to an integer fraction of step length
% tilexs is x positions across the screen, while also giving an odd number 
% of vertices horizontally, for an even number of tiles. 

% Make an odd number of vertices to stretch across the floor, for an 
% even number of tiles.
Nc = floor(diff(xlimit)/tilelen) + 1; if mod(Nc,2)==0, Nc = Nc + 1; end;
tilexs = xlimit(1) + (0:Nc-1)*tilelen;
% Tiles are defined by vertex and face matrices
% where the vertices are rows of x-y-z triples, in two groups of rows.
% The first group is the vertices stretching across the screen at ground
% height, and the second group (below the first) is the same set of
% vertices but at floorheight below ground. 
%  1      2      3      4      5
%  *------*      *------*      *    (We end up not drawing the last
%  |-  I -|      |- II -|      |     vertices on the right since they are 
%  *------*      *------*      *     white) 
%  6      7      8      9     10     

tilevm = [tilexs' ones(Nc,1)*ytileoffset zeros(Nc,1);
  tilexs' ones(Nc,1)*ytileoffset-floorheight zeros(Nc,1)];
% define dark faces from the vertices (white faces are not drawn)
tilefm = repmat((1:2:Nc-1)',1,4) + repmat([0 1 Nc+1 Nc],floor(Nc/2),1);
hgndtiles = patch('Vertices', tilevm, 'Faces', tilefm);

% contactpoint with floor can move backwards if we're on
% a treadmill, or it stays in one place. For additional
% steps it has to move forward at each s2s transition.

startpoint = 0; % start us forward so it's approximately
% centered on the treadmill
if treadmill == 0, startpoint = -xs(1,1)+R; end % or try zero

h = drawmodel(w, xs(1,:), [startpoint;0], [], drawmodeloptions{:});

cntr = 1; % absolute frame counter

for j = 1:numsteps % Loop through each step
  if treadmill % we'll move the model with the treadmill
    modelorigin = startpoint; 
    dx = sl / framecounts(min(end,j)); % how much to move the treadmill
  else         % or allow it to advance down the floor
    modelorigin = startpoint + (j-1)*sl;
    dx = 0;
  end
  for i = 1:framecounts(min(end,j)) % each step has this many frames
    drawmodel(w, xs(i,:), [modelorigin; 0], h, drawmodeloptions{:});
    set(hgndtiles,'Vertices', tilevm); % update treadmill vertices
    
    modelorigin = modelorigin - dx; % move model to left    
    tilevm(:,1) = tilevm(:,1) - dx; % and move treadmill to the left
    
    if tilevm(2,1) < xlimit(1), % scrolled a whole tile to left
      tilevm(:,1) = tilevm(:,1) + 2*tilelen;  % reset two tiles to the right
    end
        
    drawnow; pause(framedelay)

    if saveflag
      print('-depsc2',sprintf('walk%02d',cntr));
      %print('-depsc2',sprintf('walk%02d',cntr));

      % Note Matlab is threatening to remove Illustrator format. The
      % alternative is to use -depsc2, which does not import directly
      % into Flash. We have to import the eps into Illustrator and then
      % export from Illustrator to Flash format. See below for more info.
    end
    
    if debg, pause, end;
    cntr = cntr + 1;
    if keypressed
      return
    end
    
  end % frame loop 
  
end % numsteps loop

  function keypress(src,eventdata)
    keypressed = 1;
  end
  
end

%
% 1. DILL AI -> Flash -> SWF
%    Export as Illustrator, then use Flash to read the Illustrator files,
%    using import to stage. You can select multiple files. Then publish
%    as SWF. Need to fix size in Flash, where editing is possible.
%
% 2. EPSC2 -> ILL CS5 -> AI -> Flash
%    Export as EPSC2, then use Illustrator to read EPS using script.
%    Then save as Illustrator. Use Flash to read AI file using
%    import to stage. This is editable in Flash and can be published
%    with SWF, but you have to set the stage size.
%
% 3. EPSC2 -> ILL CS5 -> SWF export
%    Export as EPSC2, then use Illustrator to read EPS using script.
%    Then export as SWF. Works fine except lines come out rounded 
%    ends. Very fast and usable. But cannot read the SWF as editable
%    file in Flash. 
%
% 4. EPSC2 -> ILL CS5 (embed) -> SWF export [bad method]
%    Export as EPSC2, then use Illustrator to read EPS using script.
%    If the linked files are converted to embed, the exported SWF has
%    screwed up lines. Not recommended. Of course the Illustrator file
%    can be saved as AI and read by Flash and used.


back to top