function fsurfht(fun,xlim,ylim,p1,p2,p3,p4,p5);
%FSURFHT Interactive contour plot of a function.
%   FSURFHT(FUN,XLIM,YLIM) is an interactive contour plot of the function
%   specified by the text variable FUN.  The x-axis limits are specified 
%   by XLIMS = [XMIN XMAX] and the y-axis limits specified by YLIMS.
%   FSURFHT(FUN,XLIM,YLIM,P1,P2,P3,P4,P5) allows for five optional parameters
%   that you can supply to the function FUN. The first two arguments of FUN
%   are the x-axis variable and y-axis variable, respectively. 
%
%   There are vertical and horizontal reference lines on the plot whose 
%   intersection defines the current x-value and y-value. You can drag
%   these dotted white reference lines and watch the calculated z-values (at
%   the top of the plot) update simultaneously. Alternatively, you can get a 
%   specific z-value by typing the x-value and y-value into editable text
%   fields on the x-axis and y-axis respectively. 

%   B.A. Jones 5-23-93
%   Copyright (c) 1993-96 by The MathWorks, Inc.
%   $Revision: 2.3 $  $Date: 1996/02/13 23:09:18 $

if nargin > 2 
    action = 'start';
else
    action = fun;
end

%On recursive calls get all necessary handles and data.
if ~strcmp(action,'start')   
   
   f = get(gcf,'Userdata');

   x_field          = f(1);
   y_field          = f(2);
   z_field          = f(3);
   xtext            = f(4);
   ytext            = f(5);
   ztext            = f(6);
   response_surface = f(7);
   extra_parameters = f(8);
   surf_axes        = f(9);
   
   xgrid = get(xtext,'UserData');
   ygrid = get(ytext,'UserData');
   zgrid = get(ztext,'UserData');
   p     = get(extra_parameters,'UserData');
   fun   = get(response_surface,'String');
   h     = get(surf_axes,'UserData');
    
   vwitnessline = h(1);
   hwitnessline = h(2);

    xrange = get(surf_axes,'XLim');
    yrange = get(surf_axes,'YLim');

    newx = str2num(get(x_field,'String'));  
    newy = str2num(get(y_field,'String'));  
   [junk, extra] = size(p);   
   
end

if strcmp(action,'start'),

% Create intial parameter values 

if nargin == 4,  p = p1; end
if nargin == 5,  p = [p1 p2]; end
if nargin == 6,  p = [p1 p2 p3]; end
if nargin == 7,  p = [p1 p2 p3 p4]; end
if nargin == 8,  p = [p1 p2 p3 p4 p5]; end


extra = nargin - 3;

% Set positions of graphic objects
axisp   = [.20 .15 .79 .74];
fcolor  = [0.5 0.5 0.5];

xfieldp = [0.53 0.01 0.13 0.04];
yfieldp = [0.02 0.50 .13 0.04];
zfieldp = xfieldp + [0 0.89 0 0];

surf_fig = figure;
set(surf_fig,'Units','Normalized','Color','k','UserData','surf_fig');

gray_axes = axes;
set(gray_axes,'XTick',[],'YTick',[],'Units','Normalized','Position',[0 0 1 1]);
set(gray_axes,'Color',fcolor,'UserData','gray_axes');
set(gray_axes,'ButtonDownFcn','fsurfht(''stray_click'')');
surf_axes = axes;

set(surf_fig,'CurrentAxes',surf_axes);

% Set axis limits and data
yvertical = [ylim(1) ylim(2)]';
xvertical = ones(size(yvertical)) * (xlim(1) + xlim(2))/2;
newx  = xvertical(1);
newy  = (ylim(1) + ylim(2))/2;

xvalues       = linspace(xlim(1),xlim(2),50);
yvalues       = linspace(ylim(1),ylim(2),50);
[xgrid ygrid] = meshgrid(xvalues,yvalues);
evalstr       = [fun, '(xgrid,ygrid'];
params = ')';
for i = extra:-1:1,
   number = num2str(i);
   params = [',','p',number,params];
end
evalstr = [evalstr,params];

zgrid         = eval(evalstr);

% Define graphics objects        
x_field=uicontrol('Style','edit','Position',xfieldp,...
         'Units','normalized','String',num2str(newx),...
         'BackgroundColor','white','Userdata',newx,...
         'CallBack','fsurfht(''editX'')');
         
y_field=uicontrol('Style','edit','Units','normalized','Position',yfieldp,...
         'BackgroundColor','white','Userdata',newy,...
         'String',num2str(newy),'CallBack','fsurfht(''editY'')');

z_field=uicontrol('Style','text','Units','normalized','Position',zfieldp,...
         'String',num2str(NaN));

xtext   =uicontrol('Style','text','Position',xfieldp + [0 0.04 0 0],...
        'Units','normalized','BackgroundColor',fcolor,...
        'ForegroundColor','white','String','X Value','UserData',xgrid);
        
ytext   =uicontrol('Style','text','Position',yfieldp + [0 0.04 0 0],...
        'Units','normalized','BackgroundColor',fcolor,...
        'ForegroundColor','white','String','Y Value','UserData',ygrid);

ztext   =uicontrol('Style','text','Position',zfieldp + [0 0.04 0 0],...
        'Units','normalized','BackgroundColor',fcolor,...
        'ForegroundColor','white','String','Z Value','UserData',zgrid);
          

response_surface=uicontrol('Style','text','Visible','off',...
        'String',fun,'UserData','response_surface');

extra_parameters=uicontrol('Style','text','Visible','off','UserData',p);
           
%   Create Interactive Contour Plot
set(gcf,'Units','Normalized','Color','k');

[contour_labels contour_handles]  = contour(xvalues,yvalues,zgrid);
clabel(contour_labels);
set(gca,'Color','k');
set(gca,'Position',axisp,'XLim',xlim,'YLim',ylim,'Box','on');
set(gca,'NextPlot','add','DrawMode','fast');

%   Evaluate Z-field and Create Witness Lines
evalstr = [fun, '(newx,newy'];
params = ')';
for i = extra:-1:1,
   number = num2str(i);
   params = [',','p',number,params];
end
evalstr = [evalstr,params];
newz    = eval(evalstr);
set(z_field,'String',num2str(newz));

xhorizontal = [xlim(1) xlim(2)]';
yhorizontal = newy * ones(size(xhorizontal));

vwitnessline = plot(xvertical,yvertical,'w-.','EraseMode','xor','UserData','vertical_reference');
hwitnessline = plot(xhorizontal,yhorizontal,'w-.','EraseMode','xor','UserData','horizontal_reference');

set(vwitnessline,'ButtonDownFcn','fsurfht(''down'',1)');
set(hwitnessline,'ButtonDownFcn','fsurfht(''down'',1)');

set(gcf,'Backingstore','off','WindowButtonMotionFcn','fsurfht(''motion'',0)');
set(gcf,'WindowButtonDownFcn','fsurfht(''down'')');

set(surf_fig,'Userdata',[x_field;y_field;z_field;xtext;ytext;ztext;...
    response_surface;extra_parameters;surf_axes]);
set(surf_axes,'UserData',[vwitnessline;hwitnessline]);

% End of initialization activities.
elseif strcmp(action,'motion'),
    if xlim == 0,
      cursorstate = get(gcf,'Pointer');
        cp = get(gca,'CurrentPoint');
        cx = cp(1,1);
        cy = cp(1,2);
        fuzzx = 0.01 * (xrange(2) - xrange(1));
        fuzzy = 0.01 * (yrange(2) - yrange(1));
        online = cy > yrange(1) & cy < yrange(2) & cx > xrange(1) & cx < xrange(2) &...
           ((cy > newy - fuzzy & cy < newy + fuzzy) | (cx > newx - fuzzx & cx < newx + fuzzx));
        if online & strcmp(cursorstate,'arrow'),
            set(gcf,'Pointer','crosshair');
        elseif ~online & strcmp(cursorstate,'crosshair'),
            set(gcf,'Pointer','arrow');
        end
    
    elseif xlim == 1
        cp = get(gca,'CurrentPoint');
        newx=cp(1,1);
        if newx > xrange(2)
            newx = xrange(2);
        end
        if newx < xrange(1)
            newx = xrange(1);
        end

        newy=cp(1,2);
        if newy > yrange(2)
            newy = yrange(2);
        end
        if newy < yrange(1)
            newy = yrange(1);
        end


     evalstr = [fun, '(newx,newy'];
     params = ')';
     for i = extra:-1:1,
        number = num2str(i);
        params = [',','p(:,',number,')',params];
     end
     evalstr = [evalstr,params];

     newz    = eval(evalstr);


     set(x_field,'String',num2str(newx));
     set(y_field,'String',num2str(newy));
     set(x_field,'UserData',newx);
     set(y_field,'UserData',newy);
     set(z_field,'String',num2str(newz));

     set(vwitnessline,'XData',newx*ones(size(yrange)),'YData',yrange);
     set(hwitnessline,'XData',xrange,'YData',newy*ones(size(xrange)));
     end

elseif strcmp(action,'down'),
    set(gcf,'Pointer','crosshair');
    cp = get(gca,'CurrentPoint');
    newx=cp(1,1);
    if newx > xrange(2)
       newx = xrange(2);
    end
    if newx < xrange(1)
       newx = xrange(1);
    end

    newy=cp(1,2);
    if newy > yrange(2)
       newy = yrange(2);
    end
    if newy < yrange(1)
       newy = yrange(1);
    end

    evalstr = [fun, '(newx,newy'];
    params = ')';
    for i = extra:-1:1,
       number = num2str(i);
       params = [',','p(:,',number,')',params];
    end
    evalstr = [evalstr,params];

    newz    = eval(evalstr);


    set(x_field,'String',num2str(newx));
    set(y_field,'String',num2str(newy));
    set(x_field,'UserData',newx);
    set(y_field,'UserData',newy);
    set(z_field,'String',num2str(newz));

    set(vwitnessline,'XData',newx*ones(size(yrange)),'YData',yrange);
    set(hwitnessline,'XData',xrange,'YData',newy*ones(size(xrange)));
   
    set(gcf,'WindowButtonMotionFcn','fsurfht(''motion'',1)');
    set(gcf,'WindowButtonUpFcn','fsurfht(''up'')');

elseif strcmp(action,'up'),
    set(gcf,'WindowButtonMotionFcn','fsurfht(''motion'',0)');
    set(gcf,'WindowButtonUpFcn','');
    
elseif strcmp(action,'editX'),    
    if isempty(newx) 
      newx = get(x_field,'Userdata');
      set(x_field,'String',num2str(newx));
       return;
   end
   if newx > xrange(2)
        newx = xrange(2);
        set(x_field,'String',num2str(newx));
    end
    if newx < xrange(1)
        newx = xrange(1);
        set(x_field,'String',num2str(newx));
    end

    evalstr = [fun, '(newx,newy'];
    params = ')';
    for i = extra:-1:1,
       number = num2str(i);
       params = [',','p(:,',number,')',params];
    end
    evalstr = [evalstr,params];

    newz    = eval(evalstr);

    set(x_field,'Userdata',newx);
    set(z_field,'String',num2str(newz));
    set(vwitnessline,'XData',newx*ones(size(yrange)));

elseif strcmp(action,'editY'),
    if isempty(newy) 
      newy = get(y_field,'Userdata');
      set(y_field,'String',num2str(newy));
       return;
   end
    if newy > yrange(2)
        newy =  yrange(2);
        set(y_field,'String',num2str(newy));
    end
    if newy <  yrange(1)
        newy =  yrange(1);
        set(y_field,'String',num2str(newy));
    end

    evalstr  = [fun, '(newx,newy'];
    params = ')';
    for i = extra:-1:1,
       number = num2str(i);
       params = [',','p(:,',number,')',params];
    end

    evalstr = [evalstr,params];
    newz     = eval(evalstr);
    set(y_field,'Userdata',newy);
    set(z_field,'String',num2str(newz));
    set(hwitnessline,'XData',xrange,'YData',newy*ones(size(xrange)));

elseif strcmp(action,'stray_click'),
   set(gcf,'CurrentAxes',surf_axes);

end     % End of long "case" statement.
