function surfht(x,y,Z);
%SURFHT Interactive contour plot of a data grid.
%   SURFHT(Z) is an interactive contour plot of the matrix Z treating the
%   values in Z as height above the plane. The x-values are the column 
%   indices of Z while the y-values are the row indices of Z.
%   SURFHT(x,y,Z), where x and y are vectors specify the x and y-axes on the
%   contour plot. The length of x and y must match the number of rows in Z.
%
%   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 interpolated z-values
%   (at the top of the plot) update simultaneously. Alternatively, you can 
%   get a specific interpolated 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:37:40 $

if ~isstr(x) 
    action = 'start';
else
    action = x;
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);
   surf_axes        = f(7);
   
   xgrid = get(xtext,'UserData');
   ygrid = get(ytext,'UserData');
   zgrid = get(ztext,'UserData');
   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'));  
end

if strcmp(action,'start'),

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

xfieldp = [0.53 .00 .13 .05];
yfieldp = [0.02 .50 .13 .05];
zfieldp = xfieldp + [0 .90 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','surfht(''stray_click'')');

surf_axes = axes;
set(surf_axes,'UserData','surf_axes');
set(surf_fig,'CurrentAxes',surf_axes);

% Set axis limits and data
if nargin == 1
    [m, n] = size(x);
   Z = x;
   x = 1:m;
   y = 1:n;
   xrange = [1 m];
   yrange = [1 n];
else
   xrange        = [x(1) x(length(x))];
    yrange        = [y(1) y(length(y))];
end
[xgrid ygrid] = meshgrid(x,y);

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

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

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

ztext   =uicontrol('Style','text','Position',zfieldp + [0 0.05 0 0],...
        'Units','normalized','BackgroundColor',fcolor,...
        'ForegroundColor','white','String','Z Value','UserData',Z);
         
%   Create Interactive Contour Plot
set(gcf,'Units','Normalized','Color','k');

[contour_labels contour_handles]  = contour(x,y,Z);
clabel(contour_labels);
set(gca,'Color','k');
set(gca,'Position',axisp,'XLim',xrange,'YLim',yrange,'Box','on');
set(gca,'NextPlot','add','DrawMode','fast');

%   Create Witness Lines
yvertical = [yrange(1) yrange(2)]';
xvertical = ones(size(yvertical)) * (xrange(1) + xrange(2))/2;
newx  = xvertical(1);
newy  = (yrange(1) + yrange(2))/2;
set(x_field,'String',num2str(newx));
set(y_field,'String',num2str(newy));

newz    = interp2(xgrid,ygrid,Z,newx,newy);
set(z_field,'String',num2str(newz));



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


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

set(vwitnessline,'ButtonDownFcn','surfht(''down'')');
set(hwitnessline,'ButtonDownFcn','surfht(''down'')');

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

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

% End of initialization activities.
elseif strcmp(action,'motion'),
    if y == 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 y == 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

        newz    = interp2(xgrid,ygrid,zgrid,newx,newy);

        set(x_field,'String',num2str(newx));
        set(x_field,'Userdata',newx);
        set(y_field,'String',num2str(newy));
        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

    newz    = interp2(xgrid,ygrid,zgrid,newx,newy);

    set(x_field,'String',num2str(newx));
    set(x_field,'Userdata',newx);
    set(y_field,'String',num2str(newy));
    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','surfht(''motion'',1)');
    set(gcf,'WindowButtonUpFcn','surfht(''up'')');

elseif strcmp(action,'up'),
    set(gcf,'WindowButtonMotionFcn','surfht(''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

    newz    = interp2(xgrid,ygrid,zgrid,newx,newy);
 
    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

    newz    = interp2(xgrid,ygrid,zgrid,newx,newy);
    set(z_field,'String',num2str(newz));

    set(hwitnessline,'XData',xrange,'YData',newy*ones(size(xrange)));
    set(y_field,'Userdata',newy);
elseif strcmp(action,'stray_click'),
   set(gcf,'CurrentAxes',surf_axes);
end     % End of long "case" statement.
