function handle = arrowhead(x,y,clr,Asize,head) % arrowhead Draw an arrowhead % This program was written to place arrowheads on trajectories % calculated using one of MATLAB's ode solvers. However, the program % does not require the solvers, it only requires two points as shown % in the figures below. % (x2,y2) (x2,y2) % head=1 o head=2 o % /|\ /|\ % / | \ / | \ % / | \ / o \ % / | \ / / . \ \ % o----o----o o/ . \o % . . % . . % (x1,y1) o (x1,y1) o % (x2,y2) (x2,y2) % head=3 o head=4 o % /|\ /|\ % / | \ / | \ % / | \ / | \ % / _-o-_ \ / | \ % o . o o_ | _o % . -o- % . . % (x1,y1) o (x1,y1) o % The program draws the arrowhead, and does not draw the shaft. Also, % the point (x1,y1) is only used to determine the direction of the % arrowhead, and has no affect on the size of the arrowhead. % arrowhead(x,y,color,Asize,head) % required arguments: the values of x=[x1 x2] and y=[y1 y2] % optional arguments: % color: a string, using the same format as for the plot command % Asize = [Asize(1) Asize(2)]: this rescales the arrowhead % Asize(1) = the length in changed by this factor (default=1) % Asize(2) = the width in changed by this factor (default=1) % head: an integer, this specifies the shape of the arrow head % head = 1 straight back (the default) % head = 2 slanted back % head = 3 curved back % head = 4 bowed-out back % EXAMPLES: The figures produced by the following commands are % on the MATLAB web-site (where you downloaded this program) % Examples involving an ODE solver: % [t,y] = ode45(@rhs,[0 100],[0 1]); % hold on % plot(y(:,1),y(:,2)) % i=3; ii=i+2; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)]); % i=16; ii=i+1; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],'r'); % i=65; ii=i+1; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],'m',[1.3 1.1],2); % i=72; ii=i+2; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],[],[1.1 1],3); % i=80; ii=i+1; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],'k',[],3); % i=100; ii=i+1; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],'g',[],4); % Examples involving an ODE solver and log coordinates % [t,y] = ode45(@rhs,[0 100],[0 1]); % loglog(y(:,1),y(:,2)) % hold on % i=3; ii=i+2; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)]); % i=16; ii=i+1; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],'r'); % i=65; ii=i+1; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],'m',[1.3 1.1],2); % i=72; ii=i+2; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],[],[1.1 1],3); % i=80; ii=i+2; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],'k',[],3); % i=100; ii=i+1; arrowhead([y(i,1) y(ii,1)],[y(i,2) y(ii,2)],'g',[],4); % Examples not involving an ODE solver: % axis([-6 6 0 0.4]); % arrowhead([-6 -3.3],[0.3 0.3],[],[3 3]); % arrowhead([-6 -0.7],[0.3 0.3],'r',[3 3],3); % arrowhead([-6 1.8],[0.3 0.3],'k',[3 3],2); % arrowhead([-6 5.3],[0.3 0.3],'m',[3 3],4); % arrowhead([6 -5.8],[0.1 0.1],'m',[3 3]); % arrowhead([6 -3],[0.1 0.1],'y',[3 3],3); % arrowhead([6 -0.5],[0.1 0.1],'c',[3 3],2); % arrowhead([6 2.5],[0.1 0.1],'g',[3 3],4); % As indicated in the above four figures, the arrowhead is centered on the % line through (x1,y1), (x2,y2), with the front of the arrowhead at (x2,y2). % In the above ODE examples these points are from the computed solution. % In this context, (x1,y1) is the solution at time t1, while (x2,y2) is the % solution at time t2, where t1 < t2. depending on how picky you are about % the arrowhead being centered on the solution curve, you can adjust t1 to % rotate the arrowhead's direction. % the default length and width of the arrowhead are determined by the height % and width of the currently active plot, or subplot, window. by default % the width of the arrowhead is 1/50 of the figure's smallest dimension % (width/length), and the length of the arrowhead is 2.8 times the width. these % values can be adjusted using the asize argument. if this is done, it is likely % that values between 0.2 and 4.0 will suffice, but any positive value can be % used. also, the code calculates the arrowhead placement using figure (screen) % coordinates, and then converts this to axis coordinates. this means that it % should not be necessary to use the pbaspect or daspect commands. % copyright(c) 2009 version 1.1 % mark h. holmes % revision history: % % 01/31/09 - major rewrite of the code (v 1.1) % now works with log and semilog coordinates; % added another arrowhead type; % fixed a couple of errors. % 10/02/08 - first release (v 1.0) handle = []; % errors if nargin < 2 error('You need to specify two points'); end if (length(x) ~= 2) || (length(y) ~= 2), error('x and y vectors must each have two components'); end if (x(1) == x(2)) && (y(1) == y(2)), error('The two points are equal - cannot determine direction!'); end % set the defaults if nargin <= 2 clr = 'b'; end if nargin <= 3 Asize = [1 1]; end if nargin <= 4 head = 1; end % check if variables left empty if isempty(clr) clr = 'b'; end; if isempty(Asize) Asize = [1 1]; end; if isempty(head) head = 1; end % determine and remember the hold status, toggle if necessary if ishold, WasHold = 1; else WasHold = 0; hold on; end x1 = x(1); x2 = x(2); y1 = y(1); y2 = y(2); % get the axis dimensions Scales = get(gca,'Position'); xlog=strcmp(get(gca,'Xscale'), 'log'); ylog=strcmp(get(gca,'Yscale'), 'log'); % get ranges for axis Size = axis; a = Size(1); b= Size(2); c= Size(3); d=Size(4); % 2*Whead = width of arrow head Whead = min(Scales(3),Scales(4))/50; % Lhead = length of arrow head Lhead = 2.8*Whead; % user adjustment Whead = Asize(2)*Whead; Lhead = Asize(1)*Lhead; % estimate the figure to axis scaling v1 = 0.08*Scales(3); v2 = 0.08*Scales(4); v3 = 0.84*Scales(3); v4 = 0.84*Scales(4); % calculate the midpoint for the back of arrowhead if xlog==1 la=log10(a); lab=log10(b)-la; xv=[log10(x1)-la log10(x2)-la]/lab; else xv = [x1-a x2-a]/(b-a); end; XX = [v1 v1] + v3*xv; % XX = [X1 X2] if ylog==1 lc=log10(c); lcd=log10(d)-lc; yv=[log10(y1)-lc log10(y2)-lc]/lcd; else yv = [y1-c y2-c]/(d-c); end; YY = [v2 v2] + v4*yv; % YY = [Y1 Y2] Z3 = [XX(2) YY(2)] - Lhead * [XX(2)-XX(1) YY(2)-YY(1)]/norm([XX(2)-XX(1) YY(2)-YY(1)]); % Z3 = [X3 Y3]; % calculate the back two tips of the arrowhead if x1==x2 q = [ 1 0 ]; else q = [-(YY(2)-YY(1)) / (XX(2)-XX(1)) 1]/norm([-(YY(2)-YY(1)) / (XX(2)-XX(1)) 1]); end; ZA = Z3 + Whead * q; % ZA = [XA YA] ZB = Z3 - Whead * q; % ZB = [XB YB] if xlog==1 xx(1) = 10^(la + lab*(ZA(1)-v1)/v3); xx(2) = 10^(la + lab*(ZB(1)-v1)/v3); else xx = [a a] + (b-a)*[ZA(1)-v1 ZB(1)-v1]/v3; end; % xx = [xa xb] if ylog==1 yy(1) = 10^(lc + lcd*(ZA(2)-v2)/v4); yy(2) = 10^(lc + lcd*(ZB(2)-v2)/v4); y3 = 10^(lc + lcd*(Z3(2)-v2)/v4); else yy = [c c] + (d-c)*[ZA(2)-v2 ZB(2)-v2]/v4; y3 = c + (d-c)*(Z3(2)-v2)/v4; end; % yy = [ya yb] xa=xx(1); xb=xx(2); ya=yy(1); yb=yy(2); % the polygon forming the arrowhead if head==1 xd = [x2 xa xb]; yd = [y2 ya yb]; elseif head==2 LL=0.7*Lhead; Z4 = [XX(2) YY(2)] - LL * [XX(2)-XX(1) YY(2)-YY(1)]/norm([XX(2)-XX(1) YY(2)-YY(1)]); if xlog==1 x4 = 10^(la + lab*(Z4(1)-v1)/v3); else x4 = a + (b-a)*(Z4(1)-v1)/v3; end; if ylog==1 y4 = 10^(lc + lcd*(Z4(2)-v2)/v4); else y4 = c + (d-c)*(Z4(2)-v2)/v4; end; % Z4 = [X4 Y4] xd = [x2 xa x4 xb]; yd = [y2 ya y4 yb]; elseif head==3 beta = 2; gam = 0.25; Z2 = [XX(2) YY(2)]; Z23 = Z2 - Z3; nZB3 = norm(ZB-Z3); nn=6; for i=1:nn ZL = Z3 + (ZB-Z3)*(i-1)/(nn-1); fac = 1 - (norm(ZL-Z3)/nZB3)^beta; ZD = ZL + gam*fac*Z23; ZLL = Z3 - (ZB-Z3)*(i-1)/(nn-1); ZDD = ZLL + gam*fac*Z23; if xlog==1 xm = 10^(la + lab*(ZD(1)-v1)/v3); xmm = 10^(la + lab*(ZDD(1)-v1)/v3); else xm = a + (b-a)*(ZD(1)-v1)/v3; xmm = a + (b-a)*(ZDD(1)-v1)/v3; end; if ylog==1 ym = 10^(lc + lcd*(ZD(2)-v2)/v4); ymm = 10^(lc + lcd*(ZDD(2)-v2)/v4); else ym = c + (d-c)*(ZD(2)-v2)/v4; ymm = c + (d-c)*(ZDD(2)-v2)/v4; end; if i==1 xd = [xm]; yd=[ym]; else xd = [xmm xd xm]; yd=[ymm yd ym]; end; end; xd = [x2 xd]; yd = [y2 yd]; else beta = 2; gam = 0.2; Z2 = [XX(2) YY(2)]; Z23 = Z2 - Z3; nZB3 = norm(ZB-Z3); nn=6; for i=1:nn ZL = Z3 + (ZB-Z3)*(i-1)/(nn-1); fac = 1 - (norm(ZL-Z3)/nZB3)^beta; ZD = ZL - gam*fac*Z23; ZLL = Z3 - (ZB-Z3)*(i-1)/(nn-1); ZDD = ZLL - gam*fac*Z23; if xlog==1 xm = 10^(la + lab*(ZD(1)-v1)/v3); xmm = 10^(la + lab*(ZDD(1)-v1)/v3); else xm = a + (b-a)*(ZD(1)-v1)/v3; xmm = a + (b-a)*(ZDD(1)-v1)/v3; end; if ylog==1 ym = 10^(lc + lcd*(ZD(2)-v2)/v4); ymm = 10^(lc + lcd*(ZDD(2)-v2)/v4); else ym = c + (d-c)*(ZD(2)-v2)/v4; ymm = c + (d-c)*(ZDD(2)-v2)/v4; end; if i==1 xd = [xm]; yd=[ym]; else xd = [xmm xd xm]; yd=[ymm yd ym]; end; end; xd = [x2 xd]; yd = [y2 yd]; end % draw the arrowhead fill(xd,yd,clr,'EdgeColor',clr); % restore original axe ranges and hold status axis(Size); if ~WasHold, hold off end