
%%% example of 2D navigation with potential fields
%%% CS148 -- Building Intelligent Robots
%%% Author: Chad Jenkins  (cjenkins@cs.brown.edu)
%%%         Yuri Malitsky (ynm@cs.brown.edu)
%%%
%%% call as function with 2 arguments:
%%% gen_field: switch variable for preset examples (1-12)
%%% image_quality: qualilty of display (0,1)
%%%
%%% Internal Variables:
%%% x: current "robot" position
%%% s: struct of attractor positions 
%%% r: struct of repellor positions
%%%
%%% attractors and repellors have fields: 
%%%    x (position), w (weight), and k (shape, 1:cone, 2:exponential)

function [ output_args ] = func( gen_field, image_quality )

if (~exist('gen_field'))
    gen_field = 1;
end
if (~exist('image_quality'))
    image_quality = 1;
end

hold off;

% set a configuration of attractors/repellors
%gen_field = 11;
switch gen_field
case 1 % attract to location
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.1; s(1).k = 1;
case 2 % attract to position between two attractors
   x = [9 1];
   s(1).x = [1 5]; s(1).w = 0.1; s(1).k = 1;
   s(2).x = [1 1]; s(2).w = 0.1; s(2).k = 1;
case 3 % attract to position between two attractors, different initial pos
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.1; s(1).k = 1;
   s(2).x = [1 1]; s(2).w = 0.1; s(2).k = 1;
case 4 % attract to location around obstacle
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.1; s(1).k = 1;
   r(1).x = [8 8]; r(1).w = 0.08; r(1).k = 1;
case 5 % divergent case
   x = [9 9];
   s(1).x = [3 5]; s(1).w = 0.1; s(1).k = 1;
   r(1).x = [7 9]; r(1).w = 0.11; r(1).k = 1;
case 6 % navigate between two obstacles, cone repellors
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.11; s(1).k = 1;
   r(1).x = [3 5]; r(1).w = 0.03; r(1).k = 1; 
   r(2).x = [6 9]; r(2).w = 0.03; r(2).k = 1;
case 7 % navigate around three obstacles, cone repellors
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.11; s(1).k = 1;
   r(1).x = [3 5]; r(1).w = 0.03; r(1).k = 1; 
   r(2).x = [6 8]; r(2).w = 0.03; r(2).k = 1;
   r(3).x = [2 8]; r(3).w = 0.03; r(3).k = 1; 
case 8 % navigate between three obstacles, exponential repellors
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.11; s(1).k = 1;
   r(1).x = [3 5]; r(1).w = 0.5; r(1).k = 2; 
   r(2).x = [6 8]; r(2).w = 0.5; r(2).k = 2;
   r(3).x = [2 8]; r(3).w = 0.5; r(3).k = 2; 
case 9 % navigate between three obstacles, exponential repellors, too small weights
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.11; s(1).k = 1;
   r(1).x = [3 5]; r(1).w = 0.2; r(1).k = 2; 
   r(2).x = [6 8]; r(2).w = 0.2; r(2).k = 2;
   r(3).x = [2 8]; r(3).w = 0.2; r(3).k = 2; 
case 10 % navigate between three obstacles, exponential repellors, small weights
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.11; s(1).k = 1;
   r(1).x = [3 5]; r(1).w = 0.3; r(1).k = 2; 
   r(2).x = [6 8]; r(2).w = 0.3; r(2).k = 2;
   r(3).x = [2 8]; r(3).w = 0.3; r(3).k = 2; 
case 11 % navigate between three obstacles, exponential repellors, large weights
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.11; s(1).k = 1;
   r(1).x = [3 5]; r(1).w = 0.6; r(1).k = 2; 
   r(2).x = [6 8]; r(2).w = 0.6; r(2).k = 2;
   r(3).x = [2 8]; r(3).w = 0.6; r(3).k = 2; 
case 12 % local minima
   x = [9 9];
   s(1).x = [1 5]; s(1).w = 0.11; s(1).k = 1;
   r(1).x = [5 5]; r(1).w = 0.6; r(1).k = 2; 
   r(2).x = [2 6.5]; r(2).w = 0.8; r(2).k = 2;
   r(3).x = [4 9]; r(3).w = 0.6; r(3).k = 2; 
end



% display attractor/repellor configuration
Z = [];
minZ = 0;
scale = 10;
for i=1:100
    for j=1:100
        pos = [j/scale i/scale];
        z = 0;
        
        % if a sink node exists, add its strength to the Z
        if (exist('s'))
            % scan over all sink nodes
            for p = 1:size(s,2)
                if (s(p).k == 1) 
                    z = z + s(p).w * ( norm(s(p).x - pos) );
                elseif (s(p).k == 2)
                    z = z + exp(-norm((s(p).x-pos))/s(p).w);
                end
            end
        end
        
        % scan over all repellor nodes, and add their strengths to Z
        if (exist('r'))
            for p = 1:size(r,2)
                if (r(p).k == 1) 
                    z = z - r(p).w * ( norm(r(p).x - pos) );
                elseif (r(p).k == 2)
                    z = z + exp(-norm((pos-r(p).x))/r(p).w);
                end
            end
        end
        
        Z(i,j) = z;
        
        if z < minZ
           minZ = z; 
        end
    end
end


surfc(Z);
hold on;


% Display plot 2
plot3(x(1,1)*scale,x(1,2)*scale, minZ, 'k.','MarkerSize',20);
plot3(x(1,1)*scale, x(1,2)*scale, Z(round(x(1,2)*scale), round(x(1,1)*scale))+.07,'k.','MarkerSize',100);
path = x;
if (exist('s'))
   for i = 1:size(s,2)
      plot3(s(i).x(1,1)*scale,s(i).x(1,2)*scale,minZ,'b.','MarkerSize',20);
   end
end
if (exist('r'))
   for i = 1:size(r,2)
      plot3(r(i).x(1,1)*scale,r(i).x(1,2)*scale,minZ,'r.','MarkerSize',20);
   end
end


% iteration loop: update robot position over time
for t = 1:1000
   
   % initialize vector accumulator
   dx = [0 0];

   % accumulate vector sum over attractors
   if (exist('s'))
      for i = 1:size(s,2)
         if (s(i).k == 1) 
            dx = dx + s(i).w*(s(i).x-x)/norm((s(i).x-x));
         elseif (s(i).k == 2)
            dx = dx + (s(i).x-x)*exp(-norm((s(i).x-x))/s(i).w);
         end
      end
   end

   % accumulate vector sum over repellors
   if (exist('r'))
      for i = 1:size(r,2)
         if (r(i).k == 1) 
            dx = dx + r(i).w*(x-r(i).x)/norm((x-r(i).x));
         elseif (r(i).k == 2)
            dx = dx + (x-r(i).x)*exp(-norm((x-r(i).x))/r(i).w);
         end
      end
   end

   % integrate change in robot position over time (dx means dx/dt) as 
   x = x + dx;
   path = [path; x];

   % update display 
   if image_quality == 0
        plot3(x(1,1)*scale,x(1,2)*scale,minZ,'k.');
        plot3(path(t,1)*scale, path(t,2)*scale, Z(round(path(t,2)*scale), round(path(t,1)*scale))+.07,'k.','MarkerSize',100);
        plot3(x(1,1)*scale, x(1,2)*scale, Z(round(x(1,2)*scale), round(x(1,1)*scale))+.06,'w.','MarkerSize',97);
   else
        hold off;
        surfc(Z);
        hold on;
        
        if (exist('s'))
            for i = 1:size(s,2)
                plot3(s(i).x(1,1)*scale,s(i).x(1,2)*scale,minZ,'b.','MarkerSize',20);
            end
        end
        if (exist('r'))
            for i = 1:size(r,2)
                plot3(r(i).x(1,1)*scale,r(i).x(1,2)*scale,minZ,'r.','MarkerSize',20);
            end
        end
        
        for i = 1:size(path,1)
            plot3(path(i,1)*scale,path(i,2)*scale,minZ,'k.');
            plot3(path(i,1)*scale, path(i,2)*scale, Z(round(path(i,2)*scale), round(path(i,1)*scale))+.01,'k.','MarkerSize',20);
        end
        
        plot3(x(1,1)*scale,x(1,2)*scale,minZ,'k.');
        plot3(x(1,1)*scale, x(1,2)*scale, Z(round(x(1,2)*scale), round(x(1,1)*scale))+.04,'k.','MarkerSize',100);
   end
   title(sprintf('Iteration: %d',t));
   refresh;
   drawnow;
   
   % pause at a some point in time
   %if (mod(t,500) == 0) input('continue'); end

end




    
