% -------------------------------------------------------------------------
% script to draw a cylinder of randomly varying radius
% -------------------------------------------------------------------------

% plotting parameters
feature('UseGenericOpenGL', 1);
set(gcf, 'Renderer', 'OpenGL');

% viewing parameters
hold off; newplot; hold on;
caxis([-5.5 4.5]); colormap('jet');
%shading faceted;
light( ...
  'Position', [5 -5 5], 'Style', 'local', ...
  'Color', [1 1 1] ...
);
view(30, 15); axis([-5 5 -5 5 -5 5], 'square');
grid on;

% video parameters
FileName = 'morphingcylinder.avi';
FrameRate = 10; % frames per second
KeyRate = 10; % key frames per second (=FrameRate => no interpolation)
Duration = 12; % total duration of the animation in seconds
nFrames = Duration * FrameRate; % number of frames after the initial one

% create the avi file and set its parameters
video = avifile( ...
  FileName,'fps', FrameRate, 'keyframe', KeyRate, ...
  'quality', 100, 'compression', 'None' ...
);

% -------------------------------------------------------------------------
% define the geomtery of the random cylinders

ni = 73; nj = 73; % 72 intervals
ravg = 2; % average radius of cylinder
zmin = -2; zmax = 2; % range of z values

% create the surfaces
[x, y, z] = RandomCylinder(ravg, zmin, zmax, ni, nj);
cyl = surf2patch(x, y, z, z); v1 = cyl.vertices;
[x, y, z] = RandomCylinder(ravg, zmin, zmax, ni, nj);
cyl = surf2patch(x, y, z, z); v2 = cyl.vertices;

cp = [4 0 0 1]'; % initial center point
cl = [[0 0 0 1]' cp]; % initial radial center line

% -------------------------------------------------------------------------
% define the transforms that move things around

% translate from the origin to the starting point on the orbit
T = ConstructTranslation(cp(1), cp(2), cp(3));

Fo = 1/12; % orbital frequency in orbits per second
Ro = ConstructRotation('z', 2*pi * Fo/FrameRate);

Fs = 1/12; % spin frequency in rotations per second
Rs = ConstructRotation('x', -2*pi * Fs / FrameRate);

% draw the initial frame
v = cyl.vertices;
v = [v ones(size(v,1),1)] * T';
cyl.vertices = v(:,1:3);
h = patch(cyl, ...
  'FaceLighting', 'phong', 'FaceColor', 'interp', ...
  'EdgeLighting', 'phong', 'EdgeColor', 'none', ...
  'FaceAlpha', 1 ...
);
video = addframe(video, getframe); % capture the frame
% getframe;

Rst = eye(4); Rot = eye(4); % initialize accumulated transforms
nk = 10; k = 0; % counter to control morphing

% draw subsequent frames
for Frame = 1:nFrames
  k = k + 1;
  % accumulate total rotations
  Rot = Ro * Rot; Rst = Rs * Rst;
  % morph, spin and move the cylinder around its orbit
  v = [(v1*(nk-k) + v2*k)/nk ones(size(v,1),1)] * T' * Rst' * Rot';
  % draw the cylinder
  set(h,'vertices',v(:,1:3));
  video = addframe(video, getframe); % capture the frame
%   getframe;
  % when morphing is complete, get anothere morph destination
  if k == nk
    k = 0; v1 = v2;
    [x2, y2, z2] = RandomCylinder(ravg, zmin, zmax, ni, nj);
    cyl = surf2patch(x2, y2, z2, z2); v2 = cyl.vertices;
  end;
end;
video = close(video);
hold off;
