Code covered by the BSD License  

Highlights from
imPixelLine and imCircle

imPixelLine and imCircle

by

 

15 Dec 2006 (Updated )

pixel by pixel version of imline and circle version of imrect

im_circle.m
function h_group = im_circle(h_parent, cen, r)
%im_circle Create draggable rectangle.
%   H = im_circle(HPARENT, CEN, R) creates a draggable circle with radius r
%   on the object specified by HPARENT.  
%   The function returns H, a handle to the rectangle,
%   which is an hggroup object.  HPARENT specifies the hggroup's parent, which
%   is typically an axes object, but can also be any other object that can be
%   the parent of an hggroup. CEN is a two-element vector that specifies
%   the initial location of the center. CEN has the form [XCEN,YCEN].
%   R is scalar that specifies the radius.
%
%   A draggable circle can be dragged interactively using the mouse.  When
%   the circle occupies a small number of screen pixels, its appearance
%   changes to aid visibility.
%
%   The draggable circle has a context menu associated with it that allows
%   you to copy the current position to the clipboard and change the color
%   used to display the circle.
%
%   API Function Syntaxes
%   ---------------------
%   A draggable circle contains a structure of function handles, called
%   an API, that can be used to manipulate it.  To retrieve this
%   structure from the draggable circle, use the IPTGETAPI function.
%
%       API = IPTGETAPI(H)
%
%   Functions in the API, listed in the order of the structure fields, include:
%
%   setPosition
%
%       Sets the draggable circle to a new position.
%
%           api.setPosition(new_position)
%
%       where new_position is a four-element position vector.
%
%   getPosition
%
%       Returns the current position of the draggable circle.
%
%           position = api.getPosition()
%
%   delete
%
%       Deletes the draggable circle associated with the API.
%
%           api.delete()
%
%   setColor
%
%       Sets the color used to draw the draggable circle.
%
%           api.setColor(new_color)
%
%       where new_color is a three-element vector specifying an RGB
%       value.
%
%   addNewPositionCallback
%
%       Adds the function handle FCN to the list of new-position callback
%       functions.
%
%           id = api.addNewPositionCallback(fcn)
%
%       Whenever the draggable circle changes its position, each
%       function in the list is called with the syntax:
%
%           fcn(position)
%
%       The return value, id, is used only with
%       removeNewPositionCallback.
%
%   removeNewPositionCallback
%
%       Removes the corresponding function from the new-position callback
%       list.
%
%           api.removeNewPositionCallback(id)
%
%       where id is the identifier returned by
%       api.addNewPositionCallback.
%
%   setDragConstraintFcn
%
%       Sets the drag constraint function to be the specified function
%       handle, fcn.
%
%           api.setDragConstraintFcn(fcn)
%
%       Whenever the draggable circle is moved because of a mouse drag,
%       the constraint function is called using the syntax:
%
%           constrained_position = fcn(new_position)
%
%       where new_position is a four-element position vector. This allows a
%       client, for example, to control where the circle may be dragged.
%
%   getDragConstraintFcn
%
%       Returns a function handle to the current drag constraint function.
%
%           fcn = api.getDragConstraintFcn()
%   
%   Remarks
%   -------
%   If you use im_circle with an axis that contains an image object, 
%   and do not specify a drag constraint function, users can drag
%   the point outside the extent of the image and lose the point.
%   When used with an axis created by the PLOT function, the axis
%   limits automatically expand to accommodate the movement of
%   the point.    
%    
%   Examples
%   --------
%       % Display updated position in the title. Specify a drag
%       % constraint function using makeConstainToRectFcn to keep 
%       % the circle inside the original xlim and ylim ranges.    
%       figure, imshow('cameraman.tif');
%       h = im_circle(gca, [110,60], 30);
%       api = iptgetapi(h);
%       api.addNewPositionCallback(@(p) title(mat2str(p)));
%       % IMPORTANT: use 'imline' here since makeConstrainToRectFcn can
%       % only recognize one of the imline, imrect, impoint !!!
%       fcn = makeConstrainToRectFcn('imrect',get(gca,'XLim'),get(gca,'YLim'));
%       api.setDragConstraintFcn(fcn);
%
%       % Use a custom color for displaying the circle.
%       figure, imshow('cameraman.tif')
%       h = im_circle(gca, [110,60], 30);
%       api = iptgetapi(h);
%       api.setColor([1 0 0]);
%
%       % When the circle position occupies only a few pixels on the
%       % screen, the circle is drawn in a different style to increase
%       % its visibility.
%       figure, imshow cameraman.tif
%       h = im_circle(gca, [110,60], 30);
%
%   See also  IMLINE, IMPOINT, IPTGETAPI, makeConstrainToRectFcn.

  
  iptchecknargin(3, 3, nargin, mfilename);
  if ~ishandle(h_parent)
    error('Images:im_circle:invalidHandle', ...
          'HPARENT must be a valid graphics handle.');
  end
  if strcmp(get(h_parent, 'type'), 'axes')
    h_axes = h_parent;
  else
    h_axes = ancestor(h_parent, 'axes');
    if isempty(h_axes)
      error('Images:im_circle:noAxesAncestor', ...
            'HPARENT must be a descendent of an axes object.');
    end
  end

  try
    h_group = hggroup('ButtonDownFcn', @startDrag, 'Parent', h_parent, ...
                      'HitTest', 'on');
  catch
    error('Images:im_circle:failureToParent', ...
          'HPARENT must be able to have an hggroup object as a child.');
  end

  draw_api = defaultCircle(h_group);
  
  % constraint_function is used by dragMotion() to give a client the opportunity
  % to constrain where the circle can be dragged.
  drag_constraint_function = identityFcn;

  % new_position_callback_functions is used by sendNewPosition() to
  % notify interested clients whenever the circle position changes.
  new_position_callback_functions = makeList;
    
  % Pattern for set associated with callbacks that get called as a
  % result of the set.
  insideSetPosition = false;
  insideSetRadius   = false;
    
  h_fig = iptancestor(h_axes, 'figure');
  cmenu = uicontextmenu('Parent', h_fig);
  set(h_group, 'UIContextMenu', cmenu);
  uimenu(cmenu, ...
         'Label', 'Copy Position', ...
         'Callback', @copyPosition');
  set_color_menu = uimenu(cmenu, ...
                          'Label', 'Set Circle Color');
  color_choices = getColorChoices;
  for k = 1:numel(color_choices)
    uimenu(set_color_menu, 'Label', color_choices(k).Label, ...
           'Callback', @(varargin) setColor(color_choices(k).Color));
  end
  setColor(color_choices(1).Color);
  
  % Բģ뾶
  center = cen;
  radius = r;
  position = [cen(1)-r,cen(2)-r,2*r,2*r];
  
  
  api.setCenter                  = @setCenter;
  api.getCenter                  = @getCenter;
  api.setRadius                  = @setRadius;
  api.getRadius                  = @getRadius;
  api.delete                     = @deleteRect;
  api.setColor                   = @setColor;
  api.addNewPositionCallback     = @addNewPositionCallback;
  api.removeNewPositionCallback  = @removeNewPositionCallback;
  api.getDragConstraintFcn       = @getDragConstraintFcn;
  api.setDragConstraintFcn       = @setDragConstraintFcn;  
  
  api.setDragConstraintCallback  = @setDragConstraintFcn; 
  
  setappdata(h_group, 'API', api);

  % Make the pointer be a fleur when it is over the rect.  Store the same pointer
  % behavior in the hggroup and all its children.
  pointer_fcn = @(varargin) set(h_fig, 'Pointer', 'fleur');
  iptSetPointerBehavior(findobj(h_group), pointer_fcn);
  
  updateView(center, radius);
  
  % Create update function that knows how to get the position it needs when it
  % will be called from HG contexts where it may not have access to the position
  % otherwise.
  update_fcn = @(varargin) updateView(api.getCenter(), api.getRadius());
  
  updateAncestorListeners(h_group,update_fcn);
  
  % Install a pointer manager in the figure and enable it.
  iptPointerManager(h_fig);

  %---------------------------------
  function setCenter(new_center)
  
    % Pattern to break recursion
    if insideSetPosition
        return
    else
        insideSetPosition = true;
    end     

    center = new_center;
    position = [...
      center(1)-radius,center(2)-radius,2*radius,2*radius];
    updateView(center, radius);
    sendNewPosition;
    
    % Pattern to break recursion
    insideSetPosition = false;
    
  end

  %-------------------------
  function cen = getCenter
    cen = center;
  end

  %-------------------
  function setRadius(r)
    
    % Pattern to break recursion
    if insideSetRadius
        return
    else
        insideSetPosition = true;
    end
    
    radius = r;
    position = [...
    center(1)-radius,center(2)-radius,2*radius,2*radius];
    updateView(center, radius);
    sendNewPosition;
    
    % Pattern to break recursion
    insideSetPosition = false;

  end

  %---------------------
  function r = getRadius
    r = radius;
  end

  %----------------------------------------
  function id = addNewPositionCallback(fun)
    id = new_position_callback_functions.appendItem(fun);
  end

  %-------------------------------------
  function removeNewPositionCallback(id)
    new_position_callback_functions.removeItem(id);
  end

  %---------------------------------
  function setDragConstraintFcn(fun)
    drag_constraint_function = fun;
  end

  %---------------------------------
  function fh = getDragConstraintFcn
    fh = drag_constraint_function;
  end

  %----------------------------
  function deleteRect(varargin) %#ok varargin needed by HG caller
    if ishandle(h_group)
      delete(h_group);
    end
  end

  %-----------------------
  function updateView(cen, r)
    draw_api.updateView(cen, r);
  end

  %-----------------------
  function setColor(color)
    draw_api.setColor(color);
  end
  
  %------------------------------
  function copyPosition(varargin) %#ok varargin needed by HG caller
  
    clipboard('copy', position);
  
  end

  %---------------------------------
  function sendNewPosition(varargin) %#ok varargin needed by HG caller

    list = new_position_callback_functions.getList();
    for k = 1:numel(list)
      fun = list{k};
      fun(position);
    end

  end

  %--------------------------------
  function startDrag(src, varargin) %#ok varargin needed by HG caller
      
    if strcmp(get(h_fig, 'SelectionType'), 'normal')
        start_position = position;
        
        % Get the mouse location in data space.
        [start_x,start_y] = getCurrentPoint(h_axes);
        
        % Disable the figure's pointer manager until the drag is completed.
        iptPointerManager(h_fig, 'disable');

        drag_motion_callback_id = iptaddcallback(h_fig, ...
                                                 'WindowButtonMotionFcn', ...
                                                 @dragMotion);
        
        drag_up_callback_id = iptaddcallback(h_fig, ...
                                             'WindowButtonUpFcn', ...
                                             @stopDrag);
    end
    
    %----------------------------
    function dragMotion(varargin) %#ok varargin needed by HG caller
    
      if ~ishandle(h_axes)
          return;
      end

      [new_x,new_y] = getCurrentPoint(h_axes);      
      delta_x = new_x - start_x;
      delta_y = new_y - start_y;
      candidate_position = start_position + [delta_x delta_y 0 0]; 
      
      new_position = drag_constraint_function(candidate_position);
      
      new_radius = new_position(4)/2;
      new_center = [new_position(1)+new_radius,new_position(2)+new_radius];
      setCenter(new_center);
    
    end

    
    %--------------------------
    function stopDrag(varargin) %#ok varargin needed by HG caller
      dragMotion();

      iptremovecallback(h_fig, 'WindowButtonMotionFcn', ...
                        drag_motion_callback_id);
      iptremovecallback(h_fig, 'WindowButtonUpFcn', ...
                        drag_up_callback_id);
      
      % Enable the figure's pointer manager.
      iptPointerManager(h_fig, 'enable');
      
    end % stopDrag

    
  end % startDrag

  
end % im_circle

Contact us