function [TE,YE,IE] = learntouseevents(pos1,pos2,distance,speed1,speed2);
%learntouseevents(pos1,pos2,distance,speed1,speed2);
%This program shows how to use events in ode integrators to keep track of
%user-defined significant time-points
%
%In this example, two cars are RACING and when either crosses the finish
%line the odeintegrator ends and the winner is announced
%
% { pos1 }
% -------------------------------------------------------------------------
%      >1>                                                                X
%  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -X
%            >2>                                                          X
% -------------------------------------------------------------------------
% {    pos2     }
% {                               distance                                }
%
%EXAMPLE
%car1 gets a head start but car2 is faster...for the win!
%[TE,YE,IE] = learntouseevents(10,0,100,1,5)
%
%WARNING: MATLAB's event handling doesn't seem as robust as I'd like it as
%I have had program failure when more than one event triggers at a time...
%such as when both cars start at the same position and when both cars
%finish at the same time
%I have heard that this bug has been fixed in some verisons of Matlab

tmax = 100000; %maximum integration time
x0 = [pos1,pos2]; %initial car positions
param.finish = 100; %distance raced to
param.v1 = speed1;
param.v2 = speed2;

options = odeset('Events',@playbyplay);
[t,x,TE,YE,IE] = ode45(@speedfunction,[0,tmax],x0,options,param);
%[t,x] = ode45(fun,[0,tmax],x0);

numberofevents = length(IE);
%determine what happened, event information is stored in TE, YE, and IE
%TE stores the times events happened
%YE stores the function values f at each event
%IE stores the index of the event function triggered
for(i = 1:numberofevents);
    switch IE(i);
        case 1;
            disp(['The Race is on! at t =',num2str(TE(i))]);
            disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
                ' and ',num2str(YE(i,2))]);
        case 2;
            disp(['The Race is over at t =',num2str(TE(i))]);
            disp(['Car1 WINS!!!!!!']);
            disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
                ' and ',num2str(YE(i,2))]);
        case 3;
            disp(['The Race is over at t =',num2str(TE(i))]);
            disp(['Car2 WINS!!!!!!']);
            disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
                ' and ',num2str(YE(i,2))]);
        case 4;
            disp(['Car1 passes Car2 at t =',num2str(TE(i))]);
            disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
                ' and ',num2str(YE(i,2))]);
        case 5;
            disp(['Car2 passes Car1 at t =',num2str(TE(i))]);
            disp(['Car1 and Car2 are in positions ',num2str(YE(i,1)),...
                ' and ',num2str(YE(i,2))]);
        otherwise;
            error('illegal case value');
    end
end

plot(x,t);
xlabel('position');
ylabel('time');
legend('car1','car2');

return;



%in this simple example, the two cars move at constant speeds for all
%times (acceleration and time/position dependence could easily be added)
function velocities = speedfunction(t,x,param);
    velocities = [0 0]';
    velocities(1) = param.v1;
    velocities(2) = param.v2;
return;

function [value,isterminal,direction]=playbyplay(t,x,param);
%The events function is triggered whenever a zero is reached
%We will have five functions, one for the beginning of the race,
%one for car 1, one for car 2, and two for cars passing each other
car1position = x(1);
car2position = x(2);

%these are our four possible events.  The last two look the same, but we
%will distinguish between them later by looking at the direction zero is
%approached from and left from
racestarted = t;
car1finished = car1position - param.finish;
car2finished = car2position - param.finish;
car1passedcar2 = car1position - car2position;
car2passedcar1 = car1position - car2position;


%value is the result returned by the event function, zeros => events
value      = [racestarted; car1finished;  car2finished; car1passedcar2; car2passedcar1;];
%isterminal tells whether a given event causes the integrator to stop
%  we want to stop when a racer finishes but not when a racer passes
isterminal = [          0;            1;             1;              0;              0;];
%direction acts as a filter to distinguish between some zeros
%  if direction is zero, we care about all zeros
%  if +1, we care about cases where the event function increases
%  if -1, we care about cases where the event function decreases
direction  = [           0;           0;             0;              1;              -1;];
return;