function orbits3
% ORBITS3  Motion of n bodies under mutual gravitional attraction.
%          Artificial 3 body problem used in the text.

   % P = n-by-d array of position coordinates, d = 2 or 3.
   % V = n-by-d array of velocities
   % M = n-by-1 array of masses
   % H = graphics and user interface handles

   [P,V,M] = initialize_orbits;
   H = initialize_graphics(P);

   n = size(P,1);  % Number of bodies
   steps = 100;    % Number of steps between plots
   t = 0;          % time

   while ~get(H.stop,'value')

      % Obtain step size from slider.
      delta = get(H.speed,'value')/steps;
      
      for k = 1:steps

         % Compute current gravitational forces.
         G = zeros(size(P));
         for i = 1:n
            for j = [1:i-1 i+1:n];
               r = P(j,:) - P(i,:);
               G(i,:) = G(i,:) + M(j)*r/norm(r)^3;
            end
         end
 
         % Update velocities using gravitational forces.
         V = V + delta*G;
        
         % Update positions using new velocities.
         P = P + delta*V;

      end

      t = t + steps*delta;
      update_plot(P,H,t)

   end

   finalize_graphics

end 

% ------------------------------------------------------------

function [P,V,M] = initialize_orbits
   % Initial position, velocity, and mass for three bodies.
   P = [ 0  0  0
         1  0  0
         0  1  0]; 
   V = [-0.12 -0.36  0
          0    0.72  0
         0.36 -0.36  0];
   M = [1/2 1/3 1/6]';
end

% ------------------------------------------------------------

function  H = initialize_graphics(P)
% Initialize graphics and user interface controls

   dotsize = [18 14 10]';
   color = [4 3 0     % gold
            0 0 3     % blue
            4 0 0]/4; % red

   clf reset
   set(gcf,'numbertitle','off','name',' n-body')
   s = 2*max(sqrt(diag(P*P')));
   axis([-s s -s s -s/4 s/4])
   axis square
   box on
   view(2)
   n = size(P,1);
   for i = 1:n
      H.planets(i) = line(P(i,1),P(i,2),'color',color(i,:), ...
         'marker','.','markersize',dotsize(i),'userdata',dotsize(i));
   end

   H.clock = title('0','fontweight','normal');
   H.speed = uicontrol('style','slider','min',0,'value',1/50,'max',1/10, ...
      'units','normal','position',[.02 .02 .30 .04],'sliderstep',[1/100 1/50]);
   H.stop = uicontrol('string','stop','style','toggle', ...
     'units','normal','position',[.90 .02 .08 .04]);
   set(gcf,'userdata',H)

   uicontrol('string','trace','style','toggle','units','normal', ...
      'position',[.34 .02 .06 .04],'callback','tracer');
   uicontrol('string','in','style','pushbutton','units','normal', ...
      'position',[.42 .02 .06 .04],'callback','zoomer(1/sqrt(2))')
   uicontrol('string','out','style','pushbutton','units','normal', ...
      'position',[.50 .02 .06 .04],'callback','zoomer(sqrt(2))')
   uicontrol('string','x','style','pushbutton','units','normal', ...
      'position',[.58 .02 .06 .04],'callback','view(0,0)')
   uicontrol('string','y','style','pushbutton','units','normal', ...
      'position',[.66 .02 .06 .04],'callback','view(90,0)')
   uicontrol('string','z','style','pushbutton','units','normal', ...
      'position',[.74 .02 .06 .04],'callback','view(0,90)')
   uicontrol('string','3d','style','pushbutton','units','normal', ...
      'position',[.82 .02 .06 .04],'callback','view(-37.5,30)')
   drawnow
end

% ------------------------------------------------------------

function tracer
% Callback for trace button
   H = get(gcf,'userdata');
   planets = flipud(H.planets);
   trace = get(gcbo,'value');
   n = length(planets);
   for i = 1:n
      if trace
         ms = 4;
         set(planets(i),'markersize',ms,'erasemode','none')
      else
         ms = get(planets(i),'userdata');
         set(planets(i),'markersize',ms,'erasemode','normal')
      end
   end
   if trace
      set(H.clock,'erasemode','xor')
   else
      set(H.clock,'erasemode','normal')
   end
end

% ------------------------------------------------------------

function zoomer(zoom)
% Callback for in and out buttons
   H = get(gcf,'userdata');
   T = view;
   view(3);
   axis(zoom*axis);
   view(T);
   set(H.speed,'max',zoom*get(H.speed,'max'), ...
      'value',zoom*get(H.speed,'value'));
end

% ------------------------------------------------------------

function update_plot(P,H,t)
   set(H.clock,'string',sprintf('%10.2f',t))
   for i = 1:size(P,1)
      set(H.planets(i),'xdata',P(i,1),'ydata',P(i,2),'zdata',P(i,3))
   end
   drawnow
end

% ------------------------------------------------------------

function finalize_graphics
   delete(findobj('type','uicontrol'))
   uicontrol('string','close','style','pushbutton', ...
     'units','normal','position',[.90 .02 .08 .04],'callback','close');
end
