-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patharrowh.m
More file actions
253 lines (229 loc) · 8.03 KB
/
arrowh.m
File metadata and controls
253 lines (229 loc) · 8.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
% ARROWH Draws a solid 2D arrow head in current plot.
%
% ARROWH(X,Y,COLOR,SIZE,LOCATION) draws a solid arrow head into
% the current plot to indicate a direction. X and Y must contain
% a pair of x and y coordinates ([x1 x2],[y1 y2]) of two points:
%
% The first point is only used to tell (in conjunction with the
% second one) the direction and orientation of the arrow -- it
% will point from the first towards the second.
%
% The head of the arrow will be located in the second point. An
% example of use is plot([0 2],[0 4]); ARROWH([0 1],[0 2],'b')
%
% You may also give two vectors of same length > 2. The routine
% will then choose two consecutive points from "about" the middle
% of each vectors. Useful if you don't want to worry each time
% about where to put the arrows on a trajectory. If x1 and x2
% are the vectors x1(t) and x2(t), simply put ARROWH(x1,x2,'r')
% to have the right direction indicated in your x2 = f(x1) phase
% plane.
%
% (x2,y2)
% --o
% \ |
% \|
%
%
% o
% (x1,y1)
%
% Please note that the following optional arguments need -- if
% you want to use them -- to be given in that exact order. You
% may pass on empty vectors "[]" to skip arguments you don't want
% to set (if you want to access "later" arguments...).
%
% The COLOR argument is quite the same as for plots, i.e. either
% a string like 'r' or an RGB value vector like [1 0 0]. If you
% only want the outlines of the head (in other words a non-solid
% arrow head), prefix the color string by 'e' or the color vector
% by 0, e.g. to get only a red outline use 'er' or [0 1 0 0].
%
% The SIZE argument allows you to tune the size of the arrows. If
% SIZE is a scalar, it scales the arrow proportionally. SIZE can
% also be a two element vector, where the first element is the
% overall scale (in percent), the second one controls the width
% of the arrow head (again, in percent).
%
% The LOCAITON argument can be used to tweak the position of the
% arrow head. If a time series of x and y coordinates are given,
% you can use this argument to place the arrow head for instance
% at 20% along the line. It can be a vector, if you want to have
% more than one arrow head drawn.
%
% Both SIZE and LOCATION arguments must also be given in percent,
% where 100 means standard size, 50 means half size, respectively
% 100 means end of the vector, 0 beginning of it. Note that those
% "locations" correspond to the cardinal position "inside" the
% vector, in other words the "index-wise" position.
%
% This little tool is mainely intended to be used for indicating
% "directions" on trajectories -- just give two consecutive times
% and the corresponding values of a flux and the proper direction
% of the trajectory will be shown on the plot. You may also pass
% on two solution vectors, as described above.
%
% Note, that the arrow heads only look good in the original axis
% settings (as in when the routine was actually started). If you
% zoom in afterwards, the triangle will get distorted.
%
% HANDLES = ARROWH(...) will give you a vector with the handles
% to the patches created by this function (if you want to modify
% them later on, for instance).
%
% Examples of use:
% x1 = [0:.2:2]; x2 = [0:.2:2]; plot(x1,x2); hold on;
% arrowh(x1,x2,'r',[],20); % passing entire vectors
% arrowh([0 1],[0 1],'eb',[300,75]); % passing 2 points
% arrowh([0 1],[0 1],'eb',[300,75],25); % head closer to (x1,y1)
% Author: Florian Knorn
% Email: [email protected]
% Version: 1.14
% Filedate: Jun 18th, 2008
%
% History: 1.14 - LOCATION now also works with lines
% 1.13 - Allow for non-solid arrow heads
% 1.12 - Return handle(s) of created patches
% 1.11 - Possibility to change width
% 1.10 - Buxfix
% 1.09 - Possibility to chose *several* locations
% 1.08 - Possibility to chose location
% 1.07 - Choice of color
% 1.06 - Bug fixes
% 1.00 - Release
%
% ToDos: - Keep proportions when zooming or resizing; has to
% be done with callback functions, I guess.
%
% Bugs: None discovered yet, those discovered were fixed
%
% Thanks: Thanks also to Oskar Vivero for using my humble
% little program in his great MIMO-Toolbox.
%
% If you have suggestions for this program, if it doesn't work
% for your "situation" or if you change something in it -- please
% send me an email! This is my very first "public" program and
% I'd like to improve it where I can -- your help is kindely
% appreciated! Thank you!
function handle = arrowh(x,y,clr,ArSize,Where)
%-- errors
if nargin < 2
error('Please give enough coordinates !');
end
if (length(x) < 2) || (length(y) < 2),
error('X and Y vectors must each have "length" >= 2 !');
end
if (x(1) == x(2)) && (y(1) == y(2)),
error('Points superimposed - cannot determine direction !');
end
if nargin <= 2
clr = 'b';
end
if nargin <= 3
ArSize = [100,100];
end
handle = [];
%-- check if variables left empty, deal width ArSize and Color
if isempty(clr)
clr = 'b'; nonsolid = false;
elseif ischar(clr)
if strncmp('e',clr,1) % for non-solid arrow heads
nonsolid = true; clr = clr(2);
else
nonsolid = false;
end
elseif isvector(clr)
if length(clr) == 4 && clr(1) == 0 % for non-solid arrow heads
nonsolid = true;
clr = clr(2:end);
else
nonsolid = false;
end
else
error('COLOR argument of wrong type (must be either char or vector)');
end
if nargin <= 4
if (length(x) == length(y)) && (length(x) == 2)
Where = 100;
else
Where = 50;
end
end
if isempty(ArSize)
ArSize = [100,100];
end
if length(ArSize) == 2
ArWidth = 0.75*ArSize(2)/100; % .75 to make arrows it a bit slimmer
else
ArWidth = 0.75;
end
ArSize = ArSize(1);
%-- determine and remember the hold status, toggle if necessary
if ishold,
WasHold = 1;
else
WasHold = 0;
hold on;
end
%-- start for-loop in case several arrows are wanted
for Loop = 1:length(Where),
%-- if vectors "longer" then 2 are given we're dealing with time series
if (length(x) == length(y)) && (length(x) > 2),
j = floor(length(x)*Where(Loop)/100); %-- determine that location
if j >= length(x), j = length(x) - 1; end
if j == 0, j = 1; end
x1 = x(j); x2 = x(j+1); y1 = y(j); y2 = y(j+1);
else %-- just two points given - take those
x1 = x(1); x2 = (1-Where/100)*x(1)+Where/100*x(2);
y1 = y(1); y2 = (1-Where/100)*y(1)+Where/100*y(2);
end
%-- get axe ranges and their norm
OriginalAxis = axis;
Xextend = abs(OriginalAxis(2)-OriginalAxis(1));
Yextend = abs(OriginalAxis(4)-OriginalAxis(3));
%-- determine angle for the rotation of the triangle
if x2 == x1, %-- line vertical, no need to calculate slope
if y2 > y1,
p = pi/2;
else
p= -pi/2;
end
else %-- line not vertical, go ahead and calculate slope
%-- using normed differences (looks better like that)
m = ( (y2 - y1)/Yextend ) / ( (x2 - x1)/Xextend );
if x2 > x1, %-- now calculate the resulting angle
p = atan(m);
else
p = atan(m) + pi;
end
end
%-- the arrow is made of a transformed "template triangle".
%-- it will be created, rotated, moved, resized and shifted.
%-- the template triangle (it points "east", centered in (0,0)):
xt = [1 -sin(pi/6) -sin(pi/6)];
yt = ArWidth*[0 cos(pi/6) -cos(pi/6)];
%-- rotate it by the angle determined above:
xd = []; yd = [];
for i=1:3
xd(i) = cos(p)*xt(i) - sin(p)*yt(i);
yd(i) = sin(p)*xt(i) + cos(p)*yt(i);
end
%-- move the triangle so that its "head" lays in (0,0):
xd = xd - cos(p);
yd = yd - sin(p);
%-- stretch/deform the triangle to look good on the current axes:
xd = xd*Xextend*ArSize/10000;
yd = yd*Yextend*ArSize/10000;
%-- move the triangle to the location where it's needed
xd = xd + x2;
yd = yd + y2;
%-- draw the actual triangle
handle(Loop) = patch(xd,yd,clr,'EdgeColor',clr);
if nonsolid, set(handle(Loop),'facecolor','none'); end
end % Loops
%-- restore original axe ranges and hold status
axis(OriginalAxis);
if ~WasHold,
hold off
end
%-- work done. good bye.