
%
% Basic physical simulation example for multiple 2D particles
%
% Chad Jenkins (cjenkins@cs.brown.edu)
% Modified: January 18, 2009
%
% based on "Particle System Dynamics" by A. Witkin in 
% "Physically Based Modeling: Principles and Practice" (1997)
%

% select a set of simulation parameters to run
sim_case = 5;

% initialization: particle state, timestep, mass
% particle (p) concatenates particle position (x) and velocity (y)
if (sim_case == 1) % two particles with lower time step
    p = [[0.00; 20.00; 4.00; 0.00] ... % particle 1
        [-5.00; 5.00; 10.00*cos(pi/3); 10.00*sin(pi/3)]]; % particle 2
    dt = 0.01;
    t = 0;
    m = 100;
elseif (sim_case == 2) % two particles with higher time step
    p = [[0.00; 20.00; 4.00; 0.00] ... % particle 1
        [-5.00; 5.00; 10.00*cos(pi/3); 10.00*sin(pi/3)]]; % particle 2
    dt = 0.1;
    t = 0;
    m = 100;
elseif (sim_case == 3) % nine particles with higher time step
    p = [[0.00; 20.00; 8.00; 0.00] ...
        [0.00; 20.00; 0.00; 8.00] ...
        [0.00; 20.00; 8.00*sin(pi/6); 10.00*cos(pi/6)] ...
        [0.00; 20.00; 8.00*sin(-pi/6); 10.00*cos(-pi/6)] ...
        [0.00; 20.00; 8.00*sin(pi/3); 10.00*cos(pi/3)] ...
        [0.00; 20.00; 8.00*sin(-pi/3); 10.00*cos(-pi/3)] ...
        [0.00; 20.00; 8.00*sin(pi/4); 10.00*cos(pi/4)] ...
        [0.00; 20.00; 8.00*sin(-pi/4); 10.00*cos(-pi/4)] ...
        [0.00; 20.00; 8.00*sin(pi/2); 10.00*cos(pi/2)]];
    dt = 0.01;
    t = 0;
    m = 100;
elseif (sim_case == 4) % nine particles with lower time step
    p = [[0.00; 20.00; 8.00; 0.00] ...
        [0.00; 20.00; 0.00; 8.00] ...
        [0.00; 20.00; 8.00*sin(pi/6); 10.00*cos(pi/6)] ...
        [0.00; 20.00; 8.00*sin(-pi/6); 10.00*cos(-pi/6)] ...
        [0.00; 20.00; 8.00*sin(pi/3); 10.00*cos(pi/3)] ...
        [0.00; 20.00; 8.00*sin(-pi/3); 10.00*cos(-pi/3)] ...
        [0.00; 20.00; 8.00*sin(pi/4); 10.00*cos(pi/4)] ...
        [0.00; 20.00; 8.00*sin(-pi/4); 10.00*cos(-pi/4)] ...
        [0.00; 20.00; 8.00*sin(pi/2); 10.00*cos(pi/2)]];
    dt = 0.002;
    t = 0;
    m = 100;
elseif (sim_case == 5) % one particle connected to fixed point with light gravity
    p = [[0.00; 20.00; 0.00; 0.00] [1.00; 18.00; 10.00*cos(pi/3); 10.00*sin(pi/3)]];
    dt = 0.1;
    t = 0;
    m = 100;
end


% loop to update particles over time
while (1)
    %fprintf(1,'t = %f : x = %f, %f;  v = %f, %f\n',t,x(1,1),x(2,1),v(1,1),v(2,1));

    % draw bounding box
    figure(1);
    hold off;
    fill([-12 -12 -10 -10],[30 -5 -5 30],'g-');
    hold on;
    fill([12 12 10 10],[30 -5 -5 30],'g-');
    fill([-12 -12 12 12],[0 -5 -5 0],'g-');

    %update each particle
    for i = 1:size(p,2)
        plot(p(1,i),p(2,i),'b.','MarkerSize',25,'Color',[(mod(i,3)==2) (mod(i,3)==0) (mod(i,3)==1)]); % draw current position        %plot([p(1,i) p(1,i)+p(3,i)],[p(2,i) p(2,i)+p(4,i)],'r'); % draw current velocity
        axis('equal');

        % accumulate current forces
        if (sim_case ~= 5)
            F = (m * [0.00; -9.81]) + [0.00; 0.00]; % gravitational force (mass times gravity vector) plus external forces
        end

        % put spring between first two particles
        if ((sim_case == 5) & (i == 1))
            F = [0.00; -2.81] + (-0.99*(norm(p(1:2,1)-p(1:2,2))-1) * (p(1:2,1)-p(1:2,2))) + -(p(3:4,1)-p(3:4,2))/norm(p(1:2,1)-p(1:2,2));
        elseif (sim_case == 5)
            F = [0.00; -2.81] + (-0.99*(norm(p(1:2,1)-p(1:2,2))-1) * (p(1:2,2)-p(1:2,1))) + -(p(3:4,2)-p(3:4,1))/norm(p(1:2,1)-p(1:2,2));;
        end

        % hacky leaky momentum during collisions
        if (p(1,i) >= 10)
            p(3,i) = 0.95 * -p(3,i); % loss in horizontal momentum due to friction
        end
        if (p(1,i) <= -10)
            p(3,i) = 0.95 * -p(3,i); % loss in horizontal momentum due to friction
        end
        if (p(2,i) <= 0.01)
            p(3,i) = 0.98 * p(3,i); % loss in horizontal momentum due to friction
            p(4,i) = 0.9 * -p(4,i); % loss in vertical momentum due to friction
        end

        % compute position and velocity time deriatives
        dx = p(3:4,i);
        dv = F/m;

        % scale derivatives by discrete timestep duration
        dx = dx * dt;
        dv = dv * dt;

        % update position and velocity (using Euler's method) one timestep into the future
        if (sim_case ~= 5)
            p(1:2,i) = p(1:2,i) + dx;
            p(3:4,i) = p(3:4,i) + dv;
        elseif (i == 1)
            p(1:2,i) = p(1:2,i) + dx;
            p(3:4,i) = p(3:4,i) + dv;
        end

    end

    % update (simulation) time
    t = t + dt;

end