Get curve sketch (pen tool) from user in MATLAB figure

Alec Jacobson

March 01, 2012

weblog/

Here's a little function that asks the user for a curve drawn on the current figure's current axis. Similar to a pen/pencil tool in Photoshop etc. Save this in a file called get_pencil_curve.m:
function P = get_pencil_curve(f)
  % GET_PENCIL_CURVE Get a curve (sequence of points) from the user by dragging
  % on the current plot window
  %
  % P = get_pencil_curve()
  % P = get_pencil_curve(f)
  % 
  % Inputs:
  %   f  figure id
  % Outputs:
  %   P  #P by 2 list of point positions
  %
  %

  % Get the input figure or get current one (creates new one if none exist)
  if nargin == 0 || isempty(f)
    f = gcf;
  end
  figure(f);

  % get axes of current figure (creates on if doesn't exist)
  a = gca;

  % set equal axis 
  axis equal;
  % freeze axis
  axis manual;
  % set view to XY plane
  view(2);

  set(gcf,'windowbuttondownfcn',@ondown);
  set(gcf,'keypressfcn',        @onkeypress);
  % living variables
  P = [];
  p = [];

  % loop until mouse up or ESC is pressed
  done = false;
  while(~done)
    drawnow;
  end

  % We've been also gathering Z coordinate, drop it
  P = P(:,1:2);

  % Callback for mouse press
  function ondown(src,ev)
    % Tell window that we'll handle drag and up events
    set(gcf,'windowbuttonmotionfcn', @ondrag);
    set(gcf,'windowbuttonupfcn',     @onup);
    append_current_point();
  end

  % Callback for mouse drag
  function ondrag(src,ev)
    append_current_point();
  end

  % Callback for mouse release
  function onup(src,ev)
    % Tell window to handle down, drag and up events itself
    finish();
  end

  function onkeypress(src,ev)
    % escape character id
    ESC = char(27);
    switch ev.Character
    case ESC
      finish();
    otherwise
      error(['Unknown key: ' ev.Character]);
    end
  end

  function append_current_point()
    % get current mouse position
    cp = get(gca,'currentpoint');
    % append to running list
    P = [P;cp(1,:)];
    if isempty(p)
      % init plot
      hold on;
      p = plot(P(:,1),P(:,2));
      hold off;
    else
      % update plot
      set(p,'Xdata',P(:,1),'Ydata',P(:,2));
    end
  end

  function finish()
    done = true;
    set(gcf,'windowbuttonmotionfcn','');
    set(gcf,'windowbuttonupfcn','');
    set(gcf,'windowbuttondownfcn','');
    set(gcf,'keypressfcn','');
  end

end
Here I'm using the function ask the user to draw a curve (blue) and then immediately simplify it (red), then mesh the interior (green). matlab mesh sketch