1 |
function [x, y] = arrowsafe(x0, y0, theLength, theAngle, theHeadSize) |
---|
2 |
|
---|
3 |
% arrowsafe -- Intelligent, oriented arrows. |
---|
4 |
% arrowsafe('demo') demonstrates itself with arrows centered |
---|
5 |
% on the origin, each one-unit long. |
---|
6 |
% arrowsafe(N) demonstrates itself with N arrows. |
---|
7 |
% arrowsafe(x0, y0, theLength, theAngle, theHeadSize) draws |
---|
8 |
% arrows that start at (x0, y0), with theLength (in y-axis units), |
---|
9 |
% theAngle (degrees, counter-clockwise from +x), and theHeadSize |
---|
10 |
% (in y-axis units). The variables should be the same size, but |
---|
11 |
% any can be a scalar, just so long as the x0 and/or y0 array is |
---|
12 |
% the full size. The "ResizeFcn" of the figure is set to update |
---|
13 |
% the arrows automatically. The "Tag" is the mfilename. |
---|
14 |
% h = arrowsafe(...) draws the arrows and returns the handle. |
---|
15 |
% [x, y] = arrowsafe(...) returns the (x, y) data for the |
---|
16 |
% arrows, one column per arrow, but does not draw them. |
---|
17 |
% arrowsafe (no argument) redraws existing arrows. This is |
---|
18 |
% useful whenever the window is resized or the x or y limits |
---|
19 |
% change. (Recall that printing causes the "ResizeFcn" to |
---|
20 |
% be called twice.) |
---|
21 |
% |
---|
22 |
% |
---|
23 |
% Calls: none |
---|
24 |
% Note: this routine leaves the axes in "manual" mode. Use |
---|
25 |
% "axis auto" to revert to automatic axis limits. |
---|
26 |
|
---|
27 |
% Copyright (C) 2000 Dr. Charles R. Denham, ZYDECO. |
---|
28 |
% All Rights Reserved. |
---|
29 |
% Disclosure without explicit written consent from the |
---|
30 |
% copyright owner does not constitute publication. |
---|
31 |
|
---|
32 |
% Version of 12-Jan-2000 14:22:59. |
---|
33 |
% Updated 22-Aug-2001 08:46:00. |
---|
34 |
|
---|
35 |
RCF = 180 / pi; |
---|
36 |
|
---|
37 |
% Resize. |
---|
38 |
|
---|
39 |
if nargin < 1 |
---|
40 |
oldGCA = gca; |
---|
41 |
h = findobj(gcf, 'Type', 'line', 'Tag', mfilename); |
---|
42 |
for i = 1:length(h) |
---|
43 |
p = get(h(i), 'Parent'); |
---|
44 |
axes(p) |
---|
45 |
u = get(h(i), 'UserData'); |
---|
46 |
[xx, yy] = feval(mfilename, u(:, 1), u(:, 2), ... |
---|
47 |
u(:, 3), u(:, 4), u(:, 5)); |
---|
48 |
set(h(i), 'XData', xx(:), 'YData', yy(:)); |
---|
49 |
end |
---|
50 |
axes(oldGCA) |
---|
51 |
return |
---|
52 |
end |
---|
53 |
|
---|
54 |
% Demonstration. |
---|
55 |
|
---|
56 |
if nargin == 1 |
---|
57 |
if isequal(x0, 'demo') |
---|
58 |
help(mfilename) |
---|
59 |
x0 = 16; |
---|
60 |
elseif ischar(x0) |
---|
61 |
x0 = eval(x0); |
---|
62 |
end |
---|
63 |
theName = [mfilename ' demo']; |
---|
64 |
f = findobj('Type', 'figure', 'Name', theName); |
---|
65 |
if ~any(f) |
---|
66 |
f = figure('Name', theName); |
---|
67 |
end |
---|
68 |
figure(max(f)) |
---|
69 |
delete(get(f, 'Children')) |
---|
70 |
n = max(1, round(x0)); |
---|
71 |
x0 = zeros(1, n); |
---|
72 |
ang = linspace(0, 360, length(x0)+1); |
---|
73 |
ang(end) = []; |
---|
74 |
h = feval(mfilename, x0, 0, 1, ang); |
---|
75 |
set(gca, 'Xlim', [-n n], 'YLim', [-2 2]) |
---|
76 |
feval(mfilename) |
---|
77 |
set(gcf, 'WindowButtonDownFcn', ... |
---|
78 |
['if zoomsafe(''down''), ' mfilename ', end']) |
---|
79 |
if nargout > 0, x = h; end |
---|
80 |
return |
---|
81 |
end |
---|
82 |
|
---|
83 |
% Initialize. |
---|
84 |
|
---|
85 |
if nargin > 1 |
---|
86 |
if nargout == 2, x = []; y = []; end |
---|
87 |
if length(x0) == 1 |
---|
88 |
x0 = x0 * ones(size(y0)); |
---|
89 |
elseif length(y0) == 1 |
---|
90 |
y0 = y0 * ones(size(x0)); |
---|
91 |
end |
---|
92 |
x0 = reshape(x0, [1 prod(size(x0))]); |
---|
93 |
y0 = reshape(y0, size(x0)); |
---|
94 |
if nargin < 3, theLength = 1; end |
---|
95 |
if nargin < 4, theAngle = 0; end |
---|
96 |
if nargin < 5, theHeadSize = 0.1 .* theLength; end |
---|
97 |
if length(theLength) == 1 |
---|
98 |
theLength = theLength * ones(size(x0)); |
---|
99 |
end |
---|
100 |
if length(theAngle) == 1 |
---|
101 |
theAngle = theAngle * ones(size(x0)); |
---|
102 |
end |
---|
103 |
if length(theHeadSize) == 1 |
---|
104 |
theHeadSize = theHeadSize * ones(size(x0)); |
---|
105 |
end |
---|
106 |
|
---|
107 |
theLength = reshape(theLength, size(x0)); |
---|
108 |
theAngle = reshape(theAngle, size(x0)); |
---|
109 |
theHeadSize = reshape(theHeadSize, size(x0)); |
---|
110 |
|
---|
111 |
axes(gca) |
---|
112 |
oldUnits = get(gca, 'Units'); |
---|
113 |
set(gca, 'Units', 'pixels') |
---|
114 |
thePosition = get(gca, 'Position'); |
---|
115 |
set(gca, 'Units', oldUnits) |
---|
116 |
theWidth = thePosition(3); % pixels. |
---|
117 |
theHeight = thePosition(4); % pixels. |
---|
118 |
|
---|
119 |
axis('manual') |
---|
120 |
dx = diff(get(gca, 'XLim')); |
---|
121 |
dy = diff(get(gca, 'YLim')); |
---|
122 |
dydx = dy / dx; % Not used. |
---|
123 |
dxdp = dx / theWidth; % sci/pixel. |
---|
124 |
dydp = dy / theHeight; % sci/pixel. |
---|
125 |
scale = dxdp / dydp; |
---|
126 |
|
---|
127 |
xa = [-10; -20; 0; -20; -10]/20; % Arrowhead. |
---|
128 |
ya = [0; 10; 0; -10; 0]/20; |
---|
129 |
|
---|
130 |
m = length(xa); |
---|
131 |
n = prod(size(x0)); |
---|
132 |
repeats = [m 1]; |
---|
133 |
|
---|
134 |
ang = repmat(theAngle, repeats); |
---|
135 |
len = repmat(theLength, repeats); |
---|
136 |
head = repmat(theHeadSize, repeats); |
---|
137 |
|
---|
138 |
xa = repmat(xa, [1 n]); |
---|
139 |
ya = repmat(ya, [1 n]); |
---|
140 |
|
---|
141 |
xa = xa .* head; |
---|
142 |
ya = ya .* head; |
---|
143 |
|
---|
144 |
xa = xa + len; |
---|
145 |
|
---|
146 |
za = xa + sqrt(-1) * ya; |
---|
147 |
|
---|
148 |
za = [zeros(1, n); za]; |
---|
149 |
|
---|
150 |
ang = repmat(theAngle, [size(za, 1) 1]); |
---|
151 |
len = repmat(theLength, [size(za, 1) 1]); |
---|
152 |
head = repmat(theHeadSize, [size(za, 1) 1]); |
---|
153 |
xx0 = repmat(x0, [size(za, 1) 1]); |
---|
154 |
yy0 = repmat(y0, [size(za, 1) 1]); |
---|
155 |
|
---|
156 |
za = exp(sqrt(-1) * ang / RCF) .* za; |
---|
157 |
|
---|
158 |
xx = real(za) + xx0; |
---|
159 |
yy = imag(za) + yy0; |
---|
160 |
|
---|
161 |
nans = zeros(1, n) + NaN; |
---|
162 |
|
---|
163 |
xx = [xx; nans]; |
---|
164 |
yy = [yy; nans]; |
---|
165 |
|
---|
166 |
zz = xx + sqrt(-1) .* yy; |
---|
167 |
|
---|
168 |
xx0 = repmat(x0, [size(zz, 1) 1]); |
---|
169 |
yy0 = repmat(x0, [size(zz, 1) 1]); |
---|
170 |
|
---|
171 |
xx = xx0 + real(zz) * scale; |
---|
172 |
yy = yy0 + imag(zz); |
---|
173 |
|
---|
174 |
parameters = [x0(:) y0(:) theLength(:) theAngle(:) theHeadSize(:)]; |
---|
175 |
|
---|
176 |
if nargout < 2 |
---|
177 |
h = line(xx(:), yy(:), ... |
---|
178 |
'Tag', mfilename, ... |
---|
179 |
'UserData', parameters); |
---|
180 |
if nargout > 1, x = h; end |
---|
181 |
elseif nargout == 2 |
---|
182 |
x = xx; |
---|
183 |
y = yy; |
---|
184 |
end |
---|
185 |
set(gcf, 'ResizeFcn', mfilename) |
---|
186 |
|
---|
187 |
if nargout == 1, x = h; end |
---|
188 |
end |
---|