% -------------------------------------------------------------------------
% animate a double a prism orbiting the origin and spinning on its own axis
% -------------------------------------------------------------------------

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

% viewing parameters
hold off; newplot; hold on;
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 = 'flyingpatches.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', 70, 'compression', 'None' ...
);

% -------------------------------------------------------------------------
% define the prism

% size of base and number of faces
r = 2; n = 5; alpha = 2*pi/n;

ca = cos(alpha);sa = sin(alpha);
R = [ % rotate about z by 2*pi / n
   ca -sa  0   0
   sa  ca  0   0
   0   0   1   0
   0   0   0   1
];
F = [ % reflect across xy plane
   1   0   0   0
   0   1   0   0
   0   0  -1   0
   0   0   0   1
];

vx = r*sin(alpha/2); vy = r*cos(alpha/2);
v = [ % vertices of the first patch
  -vx   vx   0
  -vy  -vy   0
   0    0    r
   1    1    1
];
u = F * v; % upside-down copy of the patch

cp = [0  0  0  1]'; % center point of prism

% just for fun, assign a different color to each patch
clr = [1 0 0]; hue = 0;

% accumulate vertices for the patch object representing the prism
x = []; y = []; z = []; c = [];
x = [x v(1,1:3)']; y = [y v(2,1:3)']; z = [z v(3,1:3)']; c(1,1,1:3) = clr;
for i = 2:n
  v = R * v; [clr hue] = HueRot(hue, alpha);
  x = [x v(1,:)']; y = [y v(2,:)']; z = [z v(3,:)']; c(1,i,1:3) = clr;
end
x = [x u(1,1:3)']; y = [y u(2,1:3)']; z = [z u(3,1:3)']; c(1,n+1,1:3) = clr;
for i = 2:n
  u = R * u; [clr hue] = HueRot(hue, alpha);
  x = [x u(1,1:3)']; y = [y u(2,1:3)']; z = [z u(3,1:3)']; c(1,n+i,1:3) = clr;
end

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

T = [ % translate from the origin to the starting point on the orbit
  1   0   0   4
  0   1   0   0
  0   0   1   0
  0   0   0   1
];

Fo = 1/12; % orbital frequency in orbits per second
dtheta = 2*pi * Fo/FrameRate; ca = cos(dtheta); sa = sin(dtheta);
Ro = [ % rotate about z by dtheta
   ca -sa  0   0
   sa  ca  0   0
   0   0   1   0
   0   0   0   1
];

Fs = 1/2; % spin frequency in rotations per second
dzeta = -2*pi * Fs / FrameRate; ca = cos(dzeta); sa = sin(dzeta);
Rs = [ % rotate about z by dtheta
   ca -sa  0   0
   sa  ca  0   0
   0   0   1   0
   0   0   0   1
];

% -------------------------------------------------------------------------
% draw the initial frame of the animation

% translate the prism to the starting point
n1 = size(x,1); n2 = size(x,2); n12 = n1 * n2;
P = [
  reshape(x, 1, n12);
  reshape(y, 1, n12);
  reshape(z, 1, n12);
  ones(1, n12)
];
P = T * P;
x = reshape(P(1,:), n1, n2);
y = reshape(P(2,:), n1, n2);
z = reshape(P(3,:), n1, n2);

cp = T * cp; % move the center point, too

% draw the patch object and extract the vertices
hp = patch(x, y, z, c);
set(hp, 'FaceAlpha', .5);
vp = get(hp, 'Vertices'); vp = [vp ones(size(vp,1),1)]';

video = addframe(video, getframe); % capture the frame

% -------------------------------------------------------------------------
% draw subsequent frames

for i = 1:nFrames
  % move the prism around the orbit
  vp = Ro * vp; cp = Ro * cp;

  % spin the prism about its own axis
  To = [
    1   0   0  -cp(1)
    0   1   0  -cp(2)
    0   0   1  -cp(3)
    0   0   0    1
  ];
  Ti = [
    1   0   0  cp(1)
    0   1   0  cp(2)
    0   0   1  cp(3)
    0   0   0    1
  ];
  vp = Ti * Rs * To * vp;

  % update the definition of the patch object representing the prism
  set(hp, 'Vertices', vp(1:3,:)');

  video = addframe(video, getframe); % capture the frame
end
video = close(video);
hold off;
