function [x, y] = arrowsafe(x0, y0, theLength, theAngle, theHeadSize) % arrowsafe -- Intelligent, oriented arrows. % arrowsafe('demo') demonstrates itself with arrows centered % on the origin, each one-unit long. % arrowsafe(N) demonstrates itself with N arrows. % arrowsafe(x0, y0, theLength, theAngle, theHeadSize) draws % arrows that start at (x0, y0), with theLength (in y-axis units), % theAngle (degrees, counter-clockwise from +x), and theHeadSize % (in y-axis units). The variables should be the same size, but % any can be a scalar, just so long as the x0 and/or y0 array is % the full size. The "ResizeFcn" of the figure is set to update % the arrows automatically. The "Tag" is the mfilename. % h = arrowsafe(...) draws the arrows and returns the handle. % [x, y] = arrowsafe(...) returns the (x, y) data for the % arrows, one column per arrow, but does not draw them. % arrowsafe (no argument) redraws existing arrows. This is % useful whenever the window is resized or the x or y limits % change. (Recall that printing causes the "ResizeFcn" to % be called twice.) % % % Calls: none % Note: this routine leaves the axes in "manual" mode. Use % "axis auto" to revert to automatic axis limits. % Copyright (C) 2000 Dr. Charles R. Denham, ZYDECO. % All Rights Reserved. % Disclosure without explicit written consent from the % copyright owner does not constitute publication. % Version of 12-Jan-2000 14:22:59. % Updated 22-Aug-2001 08:46:00. RCF = 180 / pi; % Resize. if nargin < 1 oldGCA = gca; h = findobj(gcf, 'Type', 'line', 'Tag', mfilename); for i = 1:length(h) p = get(h(i), 'Parent'); axes(p) u = get(h(i), 'UserData'); [xx, yy] = feval(mfilename, u(:, 1), u(:, 2), ... u(:, 3), u(:, 4), u(:, 5)); set(h(i), 'XData', xx(:), 'YData', yy(:)); end axes(oldGCA) return end % Demonstration. if nargin == 1 if isequal(x0, 'demo') help(mfilename) x0 = 16; elseif ischar(x0) x0 = eval(x0); end theName = [mfilename ' demo']; f = findobj('Type', 'figure', 'Name', theName); if ~any(f) f = figure('Name', theName); end figure(max(f)) delete(get(f, 'Children')) n = max(1, round(x0)); x0 = zeros(1, n); ang = linspace(0, 360, length(x0)+1); ang(end) = []; h = feval(mfilename, x0, 0, 1, ang); set(gca, 'Xlim', [-n n], 'YLim', [-2 2]) feval(mfilename) set(gcf, 'WindowButtonDownFcn', ... ['if zoomsafe(''down''), ' mfilename ', end']) if nargout > 0, x = h; end return end % Initialize. if nargin > 1 if nargout == 2, x = []; y = []; end if length(x0) == 1 x0 = x0 * ones(size(y0)); elseif length(y0) == 1 y0 = y0 * ones(size(x0)); end x0 = reshape(x0, [1 prod(size(x0))]); y0 = reshape(y0, size(x0)); if nargin < 3, theLength = 1; end if nargin < 4, theAngle = 0; end if nargin < 5, theHeadSize = 0.1 .* theLength; end if length(theLength) == 1 theLength = theLength * ones(size(x0)); end if length(theAngle) == 1 theAngle = theAngle * ones(size(x0)); end if length(theHeadSize) == 1 theHeadSize = theHeadSize * ones(size(x0)); end theLength = reshape(theLength, size(x0)); theAngle = reshape(theAngle, size(x0)); theHeadSize = reshape(theHeadSize, size(x0)); axes(gca) oldUnits = get(gca, 'Units'); set(gca, 'Units', 'pixels') thePosition = get(gca, 'Position'); set(gca, 'Units', oldUnits) theWidth = thePosition(3); % pixels. theHeight = thePosition(4); % pixels. axis('manual') dx = diff(get(gca, 'XLim')); dy = diff(get(gca, 'YLim')); dydx = dy / dx; % Not used. dxdp = dx / theWidth; % sci/pixel. dydp = dy / theHeight; % sci/pixel. scale = dxdp / dydp; xa = [-10; -20; 0; -20; -10]/20; % Arrowhead. ya = [0; 10; 0; -10; 0]/20; m = length(xa); n = prod(size(x0)); repeats = [m 1]; ang = repmat(theAngle, repeats); len = repmat(theLength, repeats); head = repmat(theHeadSize, repeats); xa = repmat(xa, [1 n]); ya = repmat(ya, [1 n]); xa = xa .* head; ya = ya .* head; xa = xa + len; za = xa + sqrt(-1) * ya; za = [zeros(1, n); za]; ang = repmat(theAngle, [size(za, 1) 1]); len = repmat(theLength, [size(za, 1) 1]); head = repmat(theHeadSize, [size(za, 1) 1]); xx0 = repmat(x0, [size(za, 1) 1]); yy0 = repmat(y0, [size(za, 1) 1]); za = exp(sqrt(-1) * ang / RCF) .* za; xx = real(za) + xx0; yy = imag(za) + yy0; nans = zeros(1, n) + NaN; xx = [xx; nans]; yy = [yy; nans]; zz = xx + sqrt(-1) .* yy; xx0 = repmat(x0, [size(zz, 1) 1]); yy0 = repmat(x0, [size(zz, 1) 1]); xx = xx0 + real(zz) * scale; yy = yy0 + imag(zz); parameters = [x0(:) y0(:) theLength(:) theAngle(:) theHeadSize(:)]; if nargout < 2 h = line(xx(:), yy(:), ... 'Tag', mfilename, ... 'UserData', parameters); if nargout > 1, x = h; end elseif nargout == 2 x = xx; y = yy; end set(gcf, 'ResizeFcn', mfilename) if nargout == 1, x = h; end end