image thumbnail
from Mouse LINe with minimal step, no chunks by Vassili Pastushenko
nonstop drawing/(removing via mouse click) lines

H=mlin(varargin)
function H=mlin(varargin)
% Mouse LINe(s) in current axes. GUI, data selection. Allows to set minimal step    
%Switches YDir temporarily to 'normal'. 
%
%Call:
%       H = mlin([col] [,diagstep])
%       H = mlin([diagstep][,col] )
%   Press mouse button within plot box and draw next line,
%   possibly visiting the area outside of plot box.
%
%    Release the button and continue, or delete all  at once or one-by-one 
%    lines by mouse click, or finish MLIN
%
%Input: 
%	 col= color/linewidth specificator for CLINE, e.g. '9r.' or 'b'...
%    default    col='k-4.'
%   diagstep, def. 100, defines  minimal distance between  neighboring points
%    as          (box diagonal length)/diagstep 
%
%Output:
%      H = Handle(s) to drawn lines 
%
%               DEMOs
%
%   1. Drawing in empty axes
%       cla
%        mlin                           %Black dot & line
%
%   2.   H=mlin('7hr',150)      % red hexa, smaller step
%     
%   3.  H=mlin('9b')             %Thick line
%
%   4. Drawing over a matrix image (screenshot example)
%    s=512;
%   imagesc(peaks(s)+randn(s))
%   colormap(bow('afm'))
%   set(gca,'FontSize',15);
%   title('Noisy peaks')
%   shg,pause(1)
%    H=mlin(200,'2k');
%    pause(2)
%   set(H,'color','r');

%   Vassili Pastushenko   Nov. 2007+ Jan. 2008 (minimal step)

CE=varargin;
%Check input for col and diagstep
    parsque         %parse queue

currax=gca;

%Axis limits for flow control
axis(axis);

xx=xlim;
yy=ylim;

        dX=diff(xx);
        dY=diff(yy);

%define step
step=norm([dX,dY])/diagstep;

Ydir=get(currax,'YDir');
VIS=get(currax,'visible');
set(currax,'YDir','normal','visible','off');
box=[xx(1)+1i*yy,xx(2)+1i*fliplr(yy),xx(1)+1i*yy(1)];
BOX=cline(box,'k'); %Shows where to start drawing


fi=gcf;

%Save Button 'Up' and 'Motion'  Fcn's
Button_move_old=get(fi,'WindowButtonMotionFcn');
Button_up_old=get(fi,'WindowButtonUpFcn');
%Button_down_old=get(fi,'WindowButtonDownFcn');


settex %SETs TEXts explaining actions of mouse click outside box
H=[]; %Output
h=[]; %dynamic handle
deciret=0; %DECIsion RETurn     

%Drawing loop for consecutive curves

while 1
set(htex,'string',decitex);
decide  % different actions after mouse click or button down
if  deciret   
      set(currax,'YDir',Ydir,'visible',VIS); %Recover original settings
      TOTAL=[ht,BOX];% Altogether objects to remove
          delete(TOTAL); %Remove texts and BOX
    
      
      return
end
        coun=1;  %Count of points sampled
        xy=[Inf Inf]; %placeholder to define dynamic handle h
        h=cline(xy,col);
        if auto
        set(h,'linewidth',1.5);
        end
        set(htex,'string',sectex); %We start drawing
        set(fi,'WindowButtonMotionFcn',@followpointer,'WindowButtonUpFcn',@stopmouse);
        uiwait
end

 
    function followpointer(obj,cas)
       currp=get(currax,'currentpoint');
        curp=currp(2:3);
        if norm(curp-xy(coun,:))>=step;
        coun=coun+1;
         xy(coun,:)=curp;
        set(h,'xdata',xy(:,1),'ydata',xy(:,2));
          
        end
       
    end


function  stopmouse(obj,cas)
 %recover WindowButtonFcn's Motion and Up
 set(fi,'WindowButtonMotionFcn',Button_move_old,'WindowButtonUpFcn',Button_up_old);
   xy(1,:)=[];
   falstart=numel(xy(:,1))<3;
   if ~falstart  
falstart=falstart|(prod(xx-xy(1,1))>0 |  prod(yy-xy(1,2))>0);
   end
if falstart
    delete(h);   
else
set(h,'XData',xy(:,1),'YData',xy(:,2)); 
     H(end+1)=h;
end
 uiresume
end   %stopmouse

    function decide
        waitforbuttonpress
        pont=get(currax,'CurrentPoint');
        turnon=prod(pont(3)-yy)<0&&prod(pont(1)-xx)<0;
        deletret=prod(pont(3)-yy)<0;
        deletlast=(pont(2)<xx(1))&deletret;        
        deciret=(pont(2)>xx(2))&deletret;
        
        if turnon||deciret
            if deciret
                    cheer(numel(H));
            end
             return
        end
 
        deletal=pont(3)<yy(1);
        Hhas=~isempty(H);
        
        if deletal&&Hhas
            delete(H);
            cheer(numel(H));
            H=[];
         end
                              
    if deletlast&&Hhas
        delete(H(end));
        cheer(1);
        H(end)=[];
    end
    end
   
    function settex

postx=mean(xx);
posty=yy(2)+.06*dY;

posrej=xx(1)-.08*dX;

posquitx=xx(2)+.08*dX;
posquity=yy(1)+.5*dY;


%Start drawing
decitex='\bfStart in box \rm or click your \bfdecision';
sectex='\bfDrawing \rmthe line';
htex=text(postx,posty,decitex,'color','k','backgroundcolor',.8*[1 1 1]);
hrej=text(posrej,yy(1)+.5*dY,{' ';'\bfReject last \rmand draw new'},'color','k',...
    'backgroundcolor','y','rotation',90);
hdel=text(postx,posty-1.16*dY,{'\bfDelete all \rmlines';' '},'color','k',...
    'backgroundcolor',[.8,.3 .3]);
hquit=text(posquitx,posquity,{'\bfFinish drawing';' '},'color','k',...
    'backgroundcolor',[.2 1 .2],'rotation',90);
ht=[htex,hrej,hquit,hdel];
set(ht,'FontSize',20,'HorizontalAlignment','Center');
    end


 function parsque
NAR=numel(CE);
if NAR>2
    cheer(2)
    error('Too many inputs: ');
end
%Defaults
    col='-k.5';
    diagstep=100;
    auto=true; %allows to set default line width
    %Parse queue
for i=1:NAR
    locv=CE{i};
    locid=class(locv);
    if strmatch(locid,'double','exact')
        diagstep=locv;
        
    end
    if strmatch(locid,'char','exact')
        col=locv;
        auto=false;
    end
end  %end for
end %end parsque

function cheer(N)
if nargin<1
    N=3;  
end
s=[];
M=round(1000*unifrnd(.6,1,1,N));
for i=1:N
    wid=M(i);
x=(0:wid)';
s=[s;sin((pi/wid)*x).^3.*sin(2*(x+x.^2/M(i)))];
end
sound(s/2);
 end
end

Contact us at files@mathworks.com