function buttonupfcn2D(hZoom, cpMulAxes)
%MOUSEBTNUPFCN Mouse button up function

% Copyright 2003-2004 The MathWorks, Inc.

% This code originates from simulink zoom. 

% This constant specifies the number of pixels the mouse
% must move in order to do a rbbox zoom.
POINT_MODE_MAX_PIXELS = 5; % pixels

% Get necessary handles
hFig = get(hZoom,'FigureHandle');
hLines     = get(hZoom,'LineHandles');
currentAxes = get(hZoom,'CurrentAxes');

% Get net mouse movement in pixels
orig_units = get(hFig,'Units');
set(hFig,'Units','Pixels');
fp = get(hFig,'CurrentPoint');
set(hFig,'Units',orig_units);
orig_fp = get(hZoom,'MousePoint');
dpixel = abs(orig_fp-fp);

% The first point of line 1 is always the zoom origin.
XDat   = get(hLines(1), 'XData');
YDat   = get(hLines(1), 'YData');
origin = [XDat(1), YDat(1)];

% Loop through all the currentAxes and zoom-in each of them
for k = 1:length(currentAxes),
    cAx = currentAxes(k);

    isPointMode = false;
    
    % cpMulAxes is the zoom origin for multiple axes if any.
    if k > 1
        origin = cpMulAxes(k-1,:);
    end
    
    % Get the current limits.
    currentXLim = get(cAx, 'XLim');
    newXLim = currentXLim;
    currentYLim = get(cAx, 'YLim');
    newYLim = currentYLim;
    
    % Perform zoom operation based on zoom mode.
    switch(get(hZoom,'Constraint')),
        case 'none',
            %
            % Both x and y zoom.
            % RBBOX - lines:
            % 
            %          2
            %    o-------------
            %    |            |
            %  1 |            | 4
            %    |            |
            %    --------------
            %          3
            %
            
            % Determine the end point of zoom operation.
            
            % Get current point.
            cp = get(cAx, 'CurrentPoint'); cp = cp(1,1:2);
            xcp = cp(1);
            ycp = cp(2);
            
            % Uncomment to clip rbbox zoom to current axes limits
            %if xcp > currentXLim(2),
            %    xcp = currentXLim(2);
            %end
            %if xcp < currentXLim(1),
            %    xcp = currentXLim(1);
            %end
            %if ycp > currentYLim(2),
            %    ycp = currentYLim(2);
            %end
            %if ycp < currentYLim(1),
            %    ycp = currentYLim(1);
            %end
            
            endPt = [xcp ycp];
            
            % Determine the mode: POINT or RBBOX.
            if (dpixel(1) <= POINT_MODE_MAX_PIXELS) ...
                 && (dpixel(2) <= POINT_MODE_MAX_PIXELS)
                isPointMode = true;
            end
            newXLim(k,:) = localGetNewXLim(cAx,k,isPointMode,xcp,origin,endPt);
            newYLim(k,:) = localGetNewYLim(cAx,k,isPointMode,ycp,origin,endPt);

        case 'horizontal',
            % x only zoom.
            % RBBOX - lines (only 1-3 used):
            %   
            %    |     1      |
            %  2 o------------| 3 
            %    |            |
            %             
            %
            
            % Determine the end point of zoom operation.
            cp = get(cAx, 'CurrentPoint'); cp = cp(1,1:2);
            xcp = cp(1);
            
            % Uncomment to clip rbbox zoom to current axes limits
            % if xcp > currentXLim(2),
            %    xcp = currentXLim(2);
            % end
            % if xcp < currentXLim(1),
            %    xcp = currentXLim(1);
            % end
            
            endPt = [xcp origin(2)];
            
            % Determine mode: POINT or RBBOX.
            if dpixel(1)  <= POINT_MODE_MAX_PIXELS
                isPointMode = true;
            end

            newXLim(k,:) = localGetNewXLim(cAx,k,isPointMode,xcp,origin,endPt);
            newYLim(k,:) = currentYLim;
            
        case 'vertical',
            % y only zoom.
            % RBBOX - lines (only 1-3 used):
            %    2
            %  --o--  
            %    |
            %  1 |
            %    |
            %  -----           
            %    3
            %
            
            % Determine the end point of zoom operation.
            
            % End pt is the 2nd point of line 1.
            cp = get(cAx, 'CurrentPoint'); cp = cp(1,1:2);
            ycp = cp(2);
            
            % Uncomment to clip rbbox zoom to current axes limits
            % if ycp > currentYLim(2),
            %    ycp = currentYLim(2);
            % end
            % if ycp < currentYLim(1),
            %    ycp = currentYLim(1);
            % end
            
            endPt = [origin(1) ycp];
            
            % Determine mode: POINT or RBBOX.
            if dpixel(2) <= POINT_MODE_MAX_PIXELS
                isPointMode = true;
            end

            newYLim(k,:) = localGetNewYLim(cAx,k,isPointMode,ycp,origin,endPt);
            newXLim(k,:) = currentXLim; 
          
    end % switch
    
    % Actual zoom operation
    axis(cAx,[newXLim(k,:),newYLim(k,:)]);
        
end % for

% Delete the RBBOX lines.
if ishandle(hLines)
    scribefiglisten(hFig,'off');
    delete(hLines);
    scribefiglisten(hFig,'on');
end

% Call drawnow to flush axes update since the next line, create2Dundo,
% will take a long time when called for the first time (class loading).
drawnow expose
    
if length(currentAxes)==1
    % This runs slow the first time due to UDD class loading 
    create2Dundo(hZoom,cAx,[currentXLim,currentYLim],[newXLim(k,:),newYLim(k,:)]);
end

%----------------------------------------------------%
function [newXLim] = localGetNewXLim(hAxes,k,isPointMode,xcp,origin,endPt)
% ToDo: clean up input arguments

% Calculate the new X-Limits.
if ~isPointMode % Bounding Box Mode.
    x_lim = [origin(1) endPt(1)];
    if x_lim(1) > x_lim(2),
           x_lim = x_lim([2 1]);
    end
else % Point Mode.
    % Divide the vertical into 5 divisions.
    x_lim = get(hAxes, 'XLim'); 
    if strcmp(get(hAxes, 'XScale'), 'log'),
         diff_log = diff(log10(x_lim))/5;                    
         xcp_log = log10(xcp);
         xmin = 10.^(xcp_log-diff_log);
         xmax = 10.^(xcp_log+diff_log);
         x_lim = [xmin,xmax];                    
     else
         XDiff = (x_lim(2) - x_lim(1)) / 5;
         x_lim = [xcp - XDiff, xcp + XDiff];
     end
end  
            
% Set new Xlimits.
% NOTE: Check that the limits aren't equal.  This happens
%   at very small limits.  In this case, we do nothing.
%
if abs(x_lim(1) - x_lim(2)) > 1e-10*(abs(x_lim(1)) + abs(x_lim(2)))
     newXLim(k,:) = x_lim;                
else
     newXLim = xlim(hAxes);
end


%----------------------------------------------------%
function [newYLim] = localGetNewYLim(hAxes,k,isPointMode,ycp,origin,endPt)
% ToDo: clean up input arguments

% Calculate the new Y-Limits.
if ~isPointMode % Bounding Box Mode.
    y_lim = [origin(2) endPt(2)];
    if y_lim(1) > y_lim(2),
           y_lim = y_lim([2 1]);
    end
else % Point Mode.
    % Divide the vertical into 5 divisions.
    y_lim = get(hAxes, 'YLim'); 
    if strcmp(get(hAxes, 'YScale'), 'log'),
        diff_log = diff(log10(y_lim))/5;                    
        ycp_log = log10(ycp);
        ymin = 10.^(ycp_log-diff_log);
        ymax = 10.^(ycp_log+diff_log);
        y_lim = [ymin,ymax];                    
     else
         YDiff = (y_lim(2) - y_lim(1)) / 5;
         y_lim = [ycp - YDiff, ycp + YDiff];
     end
end  
            
% Set new Ylimits.
% NOTE: Check that the limits aren't equal.  This happens
%   at very small limits.  In this case, we do nothing.
%
if abs(y_lim(1) - y_lim(2)) > 1e-10*(abs(y_lim(1)) + abs(y_lim(2)))
     newYLim(k,:) = y_lim;                
else
     newYLim = ylim(hAxes);
end

