Mercurial > hg > camir-aes2014
comparison toolboxes/FullBNT-1.0.7/GraphViz/arrow.m @ 0:e9a9cd732c1e tip
first hg version after svn
author | wolffd |
---|---|
date | Tue, 10 Feb 2015 15:05:51 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:e9a9cd732c1e |
---|---|
1 function [h,yy,zz] = arrow(varargin) | |
2 % ARROW Draw a line with an arrowhead. | |
3 % | |
4 % ARROW(Start,Stop) draws a line with an arrow from Start to Stop (points | |
5 % should be vectors of length 2 or 3, or matrices with 2 or 3 | |
6 % columns), and returns the graphics handle of the arrow(s). | |
7 % | |
8 % ARROW uses the mouse (click-drag) to create an arrow. | |
9 % | |
10 % ARROW DEMO & ARROW DEMO2 show 3-D & 2-D demos of the capabilities of ARROW. | |
11 % | |
12 % ARROW may be called with a normal argument list or a property-based list. | |
13 % ARROW(Start,Stop,Length,BaseAngle,TipAngle,Width,Page,CrossDir) is | |
14 % the full normal argument list, where all but the Start and Stop | |
15 % points are optional. If you need to specify a later argument (e.g., | |
16 % Page) but want default values of earlier ones (e.g., TipAngle), | |
17 % pass an empty matrix for the earlier ones (e.g., TipAngle=[]). | |
18 % | |
19 % ARROW('Property1',PropVal1,'Property2',PropVal2,...) creates arrows with the | |
20 % given properties, using default values for any unspecified or given as | |
21 % 'default' or NaN. Some properties used for line and patch objects are | |
22 % used in a modified fashion, others are passed directly to LINE, PATCH, | |
23 % or SET. For a detailed properties explanation, call ARROW PROPERTIES. | |
24 % | |
25 % Start The starting points. B | |
26 % Stop The end points. /|\ ^ | |
27 % Length Length of the arrowhead in pixels. /|||\ | | |
28 % BaseAngle Base angle in degrees (ADE). //|||\\ L| | |
29 % TipAngle Tip angle in degrees (ABC). ///|||\\\ e| | |
30 % Width Width of the base in pixels. ////|||\\\\ n| | |
31 % Page Use hardcopy proportions. /////|D|\\\\\ g| | |
32 % CrossDir Vector || to arrowhead plane. //// ||| \\\\ t| | |
33 % NormalDir Vector out of arrowhead plane. /// ||| \\\ h| | |
34 % Ends Which end has an arrowhead. //<----->|| \\ | | |
35 % ObjectHandles Vector of handles to update. / base ||| \ V | |
36 % E angle||<-------->C | |
37 % ARROW(H,'Prop1',PropVal1,...), where H is a |||tipangle | |
38 % vector of handles to previously-created arrows ||| | |
39 % and/or line objects, will update the previously- ||| | |
40 % created arrows according to the current view -->|A|<-- width | |
41 % and any specified properties, and will convert | |
42 % two-point line objects to corresponding arrows. ARROW(H) will update | |
43 % the arrows if the current view has changed. Root, figure, or axes | |
44 % handles included in H are replaced by all descendant Arrow objects. | |
45 % | |
46 % A property list can follow any specified normal argument list, e.g., | |
47 % ARROW([1 2 3],[0 0 0],36,'BaseAngle',60) creates an arrow from (1,2,3) to | |
48 % the origin, with an arrowhead of length 36 pixels and 60-degree base angle. | |
49 % | |
50 % The basic arguments or properties can generally be vectorized to create | |
51 % multiple arrows with the same call. This is done by passing a property | |
52 % with one row per arrow, or, if all arrows are to have the same property | |
53 % value, just one row may be specified. | |
54 % | |
55 % You may want to execute AXIS(AXIS) before calling ARROW so it doesn't change | |
56 % the axes on you; ARROW determines the sizes of arrow components BEFORE the | |
57 % arrow is plotted, so if ARROW changes axis limits, arrows may be malformed. | |
58 % | |
59 % This version of ARROW uses features of MATLAB 5 and is incompatible with | |
60 % earlier MATLAB versions (ARROW for MATLAB 4.2c is available separately); | |
61 % some problems with perspective plots still exist. | |
62 | |
63 % Copyright (c)1995-1997, Erik A. Johnson <johnsone@uiuc.edu>, 8/14/97 | |
64 | |
65 % Revision history: | |
66 % 8/14/97 EAJ Added workaround for MATLAB 5.1 scalar logical transpose bug. | |
67 % 7/21/97 EAJ Fixed a few misc bugs. | |
68 % 7/14/97 EAJ Make arrow([],'Prop',...) do nothing (no old handles) | |
69 % 6/23/97 EAJ MATLAB 5 compatible version, release. | |
70 % 5/27/97 EAJ Added Line Arrows back in. Corrected a few bugs. | |
71 % 5/26/97 EAJ Changed missing Start/Stop to mouse-selected arrows. | |
72 % 5/19/97 EAJ MATLAB 5 compatible version, beta. | |
73 % 4/13/97 EAJ MATLAB 5 compatible version, alpha. | |
74 % 1/31/97 EAJ Fixed bug with multiple arrows and unspecified Z coords. | |
75 % 12/05/96 EAJ Fixed one more bug with log plots and NormalDir specified | |
76 % 10/24/96 EAJ Fixed bug with log plots and NormalDir specified | |
77 % 11/13/95 EAJ Corrected handling for 'reverse' axis directions | |
78 % 10/06/95 EAJ Corrected occasional conflict with SUBPLOT | |
79 % 4/24/95 EAJ A major rewrite. | |
80 % Fall 94 EAJ Original code. | |
81 | |
82 % Things to be done: | |
83 % - segment parsing, computing, and plotting into separate subfunctions | |
84 % - change computing from Xform to Camera paradigms | |
85 % + this will help especially with 3-D perspective plots | |
86 % + if the WarpToFill section works right, remove warning code | |
87 % + when perpsective works properly, remove perspective warning code | |
88 % - add cell property values and struct property name/values (like get/set) | |
89 % - get rid of NaN as the "default" data label | |
90 % + perhaps change userdata to a struct and don't include (or leave | |
91 % empty) the values specified as default; or use a cell containing | |
92 % an empty matrix for a default value | |
93 % - add functionality of GET to retrieve current values of ARROW properties | |
94 | |
95 % Many thanks to Keith Rogers <kerog@ai.mit.edu> for his many excellent | |
96 % suggestions and beta testing. Check out his shareware package MATDRAW. | |
97 % He has permission to distribute ARROW with MATDRAW. | |
98 | |
99 % global variable initialization | |
100 global ARROW_PERSP_WARN ARROW_STRETCH_WARN ARROW_AXLIMITS | |
101 if isempty(ARROW_PERSP_WARN ), ARROW_PERSP_WARN =1; end; | |
102 if isempty(ARROW_STRETCH_WARN), ARROW_STRETCH_WARN=1; end; | |
103 | |
104 % Handle callbacks | |
105 if (nargin>0 & isstr(varargin{1}) & strcmp(lower(varargin{1}),'callback')), | |
106 arrow_callback(varargin{2:end}); return; | |
107 end; | |
108 | |
109 % Are we doing the demo? | |
110 c = sprintf('\n'); | |
111 if (nargin==1 & isstr(varargin{1})), | |
112 arg1 = lower(varargin{1}); | |
113 if strncmp(arg1,'prop',4), arrow_props; | |
114 elseif strncmp(arg1,'demo',4) | |
115 clf reset | |
116 demo_info = arrow_demo; | |
117 if ~strncmp(arg1,'demo2',5), | |
118 hh=arrow_demo3(demo_info); | |
119 else, | |
120 hh=arrow_demo2(demo_info); | |
121 end; | |
122 if (nargout>=1), h=hh; end; | |
123 elseif strncmp(arg1,'fixlimits',3), | |
124 arrow_fixlimits(ARROW_AXLIMITS); | |
125 ARROW_AXLIMITS=[]; | |
126 elseif strncmp(arg1,'help',4), | |
127 disp(help(mfilename)); | |
128 else, | |
129 error([upper(mfilename) ' got an unknown single-argument string ''' deblank(arg1) '''.']); | |
130 end; | |
131 return; | |
132 end; | |
133 | |
134 % Check # of arguments | |
135 if (nargout>3), error([upper(mfilename) ' produces at most 3 output arguments.']); end; | |
136 | |
137 % find first property number | |
138 firstprop = nargin+1; | |
139 for k=1:length(varargin), if ~isnumeric(varargin{k}), firstprop=k; break; end; end; | |
140 lastnumeric = firstprop-1; | |
141 | |
142 % check property list | |
143 if (firstprop<=nargin), | |
144 for k=firstprop:2:nargin, | |
145 curarg = varargin{k}; | |
146 if ~isstr(curarg) | sum(size(curarg)>1)>1, | |
147 error([upper(mfilename) ' requires that a property name be a single string.']); | |
148 end; | |
149 end; | |
150 if (rem(nargin-firstprop,2)~=1), | |
151 error([upper(mfilename) ' requires that the property ''' ... | |
152 varargin{nargin} ''' be paired with a property value.']); | |
153 end; | |
154 end; | |
155 | |
156 % default output | |
157 if (nargout>0), h=[]; end; | |
158 if (nargout>1), yy=[]; end; | |
159 if (nargout>2), zz=[]; end; | |
160 | |
161 % set values to empty matrices | |
162 start = []; | |
163 stop = []; | |
164 len = []; | |
165 baseangle = []; | |
166 tipangle = []; | |
167 wid = []; | |
168 page = []; | |
169 crossdir = []; | |
170 ends = []; | |
171 ax = []; | |
172 oldh = []; | |
173 ispatch = []; | |
174 defstart = [NaN NaN NaN]; | |
175 defstop = [NaN NaN NaN]; | |
176 deflen = 16; | |
177 defbaseangle = 90; | |
178 deftipangle = 16; | |
179 defwid = 0; | |
180 defpage = 0; | |
181 defcrossdir = [NaN NaN NaN]; | |
182 defends = 1; | |
183 defoldh = []; | |
184 defispatch = 1; | |
185 | |
186 % The 'Tag' we'll put on our arrows | |
187 ArrowTag = 'Arrow'; | |
188 | |
189 % check for oldstyle arguments | |
190 if (firstprop==2), | |
191 % assume arg1 is a set of handles | |
192 oldh = varargin{1}(:); | |
193 if isempty(oldh), return; end; | |
194 elseif (firstprop>9), | |
195 error([upper(mfilename) ' takes at most 8 non-property arguments.']); | |
196 elseif (firstprop>2), | |
197 s = str2mat('start','stop','len','baseangle','tipangle','wid','page','crossdir'); | |
198 for k=1:firstprop-1, eval([deblank(s(k,:)) '=varargin{k};']); end; | |
199 end; | |
200 | |
201 % parse property pairs | |
202 extraprops={}; | |
203 for k=firstprop:2:nargin, | |
204 prop = varargin{k}; | |
205 val = varargin{k+1}; | |
206 prop = [lower(prop(:)') ' ']; | |
207 if strncmp(prop,'start' ,5), start = val; | |
208 elseif strncmp(prop,'stop' ,4), stop = val; | |
209 elseif strncmp(prop,'len' ,3), len = val(:); | |
210 elseif strncmp(prop,'base' ,4), baseangle = val(:); | |
211 elseif strncmp(prop,'tip' ,3), tipangle = val(:); | |
212 elseif strncmp(prop,'wid' ,3), wid = val(:); | |
213 elseif strncmp(prop,'page' ,4), page = val; | |
214 elseif strncmp(prop,'cross' ,5), crossdir = val; | |
215 elseif strncmp(prop,'norm' ,4), if (isstr(val)), crossdir=val; else, crossdir=val*sqrt(-1); end; | |
216 elseif strncmp(prop,'end' ,3), ends = val; | |
217 elseif strncmp(prop,'object',6), oldh = val(:); | |
218 elseif strncmp(prop,'handle',6), oldh = val(:); | |
219 elseif strncmp(prop,'type' ,4), ispatch = val; | |
220 elseif strncmp(prop,'userd' ,5), %ignore it | |
221 else, | |
222 % make sure it is a valid patch or line property | |
223 eval('get(0,[''DefaultPatch'' varargin{k}]);err=0;','err=1;'); errstr=lasterr; | |
224 if (err), eval('get(0,[''DefaultLine'' varargin{k}]);err=0;','err=1;'); end; | |
225 if (err), | |
226 errstr(1:max(find(errstr==setstr(13)|errstr==setstr(10)))) = ''; | |
227 error([upper(mfilename) ' got ' errstr]); | |
228 end; | |
229 extraprops={extraprops{:},varargin{k},val}; | |
230 end; | |
231 end; | |
232 | |
233 % Check if we got 'default' values | |
234 start = arrow_defcheck(start ,defstart ,'Start' ); | |
235 stop = arrow_defcheck(stop ,defstop ,'Stop' ); | |
236 len = arrow_defcheck(len ,deflen ,'Length' ); | |
237 baseangle = arrow_defcheck(baseangle,defbaseangle,'BaseAngle' ); | |
238 tipangle = arrow_defcheck(tipangle ,deftipangle ,'TipAngle' ); | |
239 wid = arrow_defcheck(wid ,defwid ,'Width' ); | |
240 crossdir = arrow_defcheck(crossdir ,defcrossdir ,'CrossDir' ); | |
241 page = arrow_defcheck(page ,defpage ,'Page' ); | |
242 ends = arrow_defcheck(ends ,defends ,'' ); | |
243 oldh = arrow_defcheck(oldh ,[] ,'ObjectHandles'); | |
244 ispatch = arrow_defcheck(ispatch ,defispatch ,'' ); | |
245 | |
246 % check transpose on arguments | |
247 [m,n]=size(start ); if any(m==[2 3])&(n==1|n>3), start = start'; end; | |
248 [m,n]=size(stop ); if any(m==[2 3])&(n==1|n>3), stop = stop'; end; | |
249 [m,n]=size(crossdir); if any(m==[2 3])&(n==1|n>3), crossdir = crossdir'; end; | |
250 | |
251 % convert strings to numbers | |
252 if ~isempty(ends) & isstr(ends), | |
253 endsorig = ends; | |
254 [m,n] = size(ends); | |
255 col = lower([ends(:,1:min(3,n)) ones(m,max(0,3-n))*' ']); | |
256 ends = NaN*ones(m,1); | |
257 oo = ones(1,m); | |
258 ii=find(all(col'==['non']'*oo)'); if ~isempty(ii), ends(ii)=ones(length(ii),1)*0; end; | |
259 ii=find(all(col'==['sto']'*oo)'); if ~isempty(ii), ends(ii)=ones(length(ii),1)*1; end; | |
260 ii=find(all(col'==['sta']'*oo)'); if ~isempty(ii), ends(ii)=ones(length(ii),1)*2; end; | |
261 ii=find(all(col'==['bot']'*oo)'); if ~isempty(ii), ends(ii)=ones(length(ii),1)*3; end; | |
262 if any(isnan(ends)), | |
263 ii = min(find(isnan(ends))); | |
264 error([upper(mfilename) ' does not recognize ' deblank(endsorig(ii,:)) ' as a valid Ends value.']); | |
265 end; | |
266 else, | |
267 ends = ends(:); | |
268 end; | |
269 if ~isempty(ispatch) & isstr(ispatch), | |
270 col = lower(ispatch(:,1)); | |
271 patchchar='p'; linechar='l'; defchar=' '; | |
272 mask = col~=patchchar & col~=linechar & col~=defchar; | |
273 if any(mask) | |
274 error([upper(mfilename) ' does not recognize ' deblank(ispatch(min(find(mask)),:)) ' as a valid Type value.']); | |
275 end; | |
276 ispatch = (col==patchchar)*1 + (col==linechar)*0 + (col==defchar)*defispatch; | |
277 else, | |
278 ispatch = ispatch(:); | |
279 end; | |
280 oldh = oldh(:); | |
281 | |
282 % check object handles | |
283 if ~all(ishandle(oldh)), error([upper(mfilename) ' got invalid object handles.']); end; | |
284 | |
285 % expand root, figure, and axes handles | |
286 if ~isempty(oldh), | |
287 ohtype = get(oldh,'Type'); | |
288 mask = strcmp(ohtype,'root') | strcmp(ohtype,'figure') | strcmp(ohtype,'axes'); | |
289 if any(mask), | |
290 oldh = num2cell(oldh); | |
291 for ii=find(mask)', | |
292 oldh(ii) = {findobj(oldh{ii},'Tag',ArrowTag)}; | |
293 end; | |
294 oldh = cat(1,oldh{:}); | |
295 if isempty(oldh), return; end; % no arrows to modify, so just leave | |
296 end; | |
297 end; | |
298 | |
299 % largest argument length | |
300 [mstart,junk]=size(start); [mstop,junk]=size(stop); [mcrossdir,junk]=size(crossdir); | |
301 argsizes = [length(oldh) mstart mstop ... | |
302 length(len) length(baseangle) length(tipangle) ... | |
303 length(wid) length(page) mcrossdir length(ends) ]; | |
304 args=['length(ObjectHandle) '; ... | |
305 '#rows(Start) '; ... | |
306 '#rows(Stop) '; ... | |
307 'length(Length) '; ... | |
308 'length(BaseAngle) '; ... | |
309 'length(TipAngle) '; ... | |
310 'length(Width) '; ... | |
311 'length(Page) '; ... | |
312 '#rows(CrossDir) '; ... | |
313 '#rows(Ends) ']; | |
314 if (any(imag(crossdir(:))~=0)), | |
315 args(9,:) = '#rows(NormalDir) '; | |
316 end; | |
317 if isempty(oldh), | |
318 narrows = max(argsizes); | |
319 else, | |
320 narrows = length(oldh); | |
321 end; | |
322 if (narrows<=0), narrows=1; end; | |
323 | |
324 % Check size of arguments | |
325 ii = find((argsizes~=0)&(argsizes~=1)&(argsizes~=narrows)); | |
326 if ~isempty(ii), | |
327 s = args(ii',:); | |
328 while ((size(s,2)>1)&((abs(s(:,size(s,2)))==0)|(abs(s(:,size(s,2)))==abs(' ')))), | |
329 s = s(:,1:size(s,2)-1); | |
330 end; | |
331 s = [ones(length(ii),1)*[upper(mfilename) ' requires that '] s ... | |
332 ones(length(ii),1)*[' equal the # of arrows (' num2str(narrows) ').' c]]; | |
333 s = s'; | |
334 s = s(:)'; | |
335 s = s(1:length(s)-1); | |
336 error(setstr(s)); | |
337 end; | |
338 | |
339 % check element length in Start, Stop, and CrossDir | |
340 if ~isempty(start), | |
341 [m,n] = size(start); | |
342 if (n==2), | |
343 start = [start NaN*ones(m,1)]; | |
344 elseif (n~=3), | |
345 error([upper(mfilename) ' requires 2- or 3-element Start points.']); | |
346 end; | |
347 end; | |
348 if ~isempty(stop), | |
349 [m,n] = size(stop); | |
350 if (n==2), | |
351 stop = [stop NaN*ones(m,1)]; | |
352 elseif (n~=3), | |
353 error([upper(mfilename) ' requires 2- or 3-element Stop points.']); | |
354 end; | |
355 end; | |
356 if ~isempty(crossdir), | |
357 [m,n] = size(crossdir); | |
358 if (n<3), | |
359 crossdir = [crossdir NaN*ones(m,3-n)]; | |
360 elseif (n~=3), | |
361 if (all(imag(crossdir(:))==0)), | |
362 error([upper(mfilename) ' requires 2- or 3-element CrossDir vectors.']); | |
363 else, | |
364 error([upper(mfilename) ' requires 2- or 3-element NormalDir vectors.']); | |
365 end; | |
366 end; | |
367 end; | |
368 | |
369 % fill empty arguments | |
370 if isempty(start ), start = [Inf Inf Inf]; end; | |
371 if isempty(stop ), stop = [Inf Inf Inf]; end; | |
372 if isempty(len ), len = Inf; end; | |
373 if isempty(baseangle ), baseangle = Inf; end; | |
374 if isempty(tipangle ), tipangle = Inf; end; | |
375 if isempty(wid ), wid = Inf; end; | |
376 if isempty(page ), page = Inf; end; | |
377 if isempty(crossdir ), crossdir = [Inf Inf Inf]; end; | |
378 if isempty(ends ), ends = Inf; end; | |
379 if isempty(ispatch ), ispatch = Inf; end; | |
380 | |
381 % expand single-column arguments | |
382 o = ones(narrows,1); | |
383 if (size(start ,1)==1), start = o * start ; end; | |
384 if (size(stop ,1)==1), stop = o * stop ; end; | |
385 if (length(len )==1), len = o * len ; end; | |
386 if (length(baseangle )==1), baseangle = o * baseangle ; end; | |
387 if (length(tipangle )==1), tipangle = o * tipangle ; end; | |
388 if (length(wid )==1), wid = o * wid ; end; | |
389 if (length(page )==1), page = o * page ; end; | |
390 if (size(crossdir ,1)==1), crossdir = o * crossdir ; end; | |
391 if (length(ends )==1), ends = o * ends ; end; | |
392 if (length(ispatch )==1), ispatch = o * ispatch ; end; | |
393 ax = o * gca; | |
394 | |
395 % if we've got handles, get the defaults from the handles | |
396 if ~isempty(oldh), | |
397 for k=1:narrows, | |
398 oh = oldh(k); | |
399 ud = get(oh,'UserData'); | |
400 ax(k) = get(oh,'Parent'); | |
401 ohtype = get(oh,'Type'); | |
402 if strcmp(get(oh,'Tag'),ArrowTag), % if it's an arrow already | |
403 if isinf(ispatch(k)), ispatch(k)=strcmp(ohtype,'patch'); end; | |
404 % arrow UserData format: [start' stop' len base tip wid page crossdir' ends] | |
405 start0 = ud(1:3); | |
406 stop0 = ud(4:6); | |
407 if (isinf(len(k))), len(k) = ud( 7); end; | |
408 if (isinf(baseangle(k))), baseangle(k) = ud( 8); end; | |
409 if (isinf(tipangle(k))), tipangle(k) = ud( 9); end; | |
410 if (isinf(wid(k))), wid(k) = ud(10); end; | |
411 if (isinf(page(k))), page(k) = ud(11); end; | |
412 if (isinf(crossdir(k,1))), crossdir(k,1) = ud(12); end; | |
413 if (isinf(crossdir(k,2))), crossdir(k,2) = ud(13); end; | |
414 if (isinf(crossdir(k,3))), crossdir(k,3) = ud(14); end; | |
415 if (isinf(ends(k))), ends(k) = ud(15); end; | |
416 elseif strcmp(ohtype,'line')|strcmp(ohtype,'patch'), % it's a non-arrow line or patch | |
417 convLineToPatch = 1; %set to make arrow patches when converting from lines. | |
418 if isinf(ispatch(k)), ispatch(k)=convLineToPatch|strcmp(ohtype,'patch'); end; | |
419 x=get(oh,'XData'); x=x(~isnan(x(:))); if isempty(x), x=NaN; end; | |
420 y=get(oh,'YData'); y=y(~isnan(y(:))); if isempty(y), y=NaN; end; | |
421 z=get(oh,'ZData'); z=z(~isnan(z(:))); if isempty(z), z=NaN; end; | |
422 start0 = [x(1) y(1) z(1) ]; | |
423 stop0 = [x(end) y(end) z(end)]; | |
424 else, | |
425 error([upper(mfilename) ' cannot convert ' ohtype ' objects.']); | |
426 end; | |
427 ii=find(isinf(start(k,:))); if ~isempty(ii), start(k,ii)=start0(ii); end; | |
428 ii=find(isinf(stop( k,:))); if ~isempty(ii), stop( k,ii)=stop0( ii); end; | |
429 end; | |
430 end; | |
431 | |
432 % convert Inf's to NaN's | |
433 start( isinf(start )) = NaN; | |
434 stop( isinf(stop )) = NaN; | |
435 len( isinf(len )) = NaN; | |
436 baseangle( isinf(baseangle)) = NaN; | |
437 tipangle( isinf(tipangle )) = NaN; | |
438 wid( isinf(wid )) = NaN; | |
439 page( isinf(page )) = NaN; | |
440 crossdir( isinf(crossdir )) = NaN; | |
441 ends( isinf(ends )) = NaN; | |
442 ispatch( isinf(ispatch )) = NaN; | |
443 | |
444 % set up the UserData data (here so not corrupted by log10's and such) | |
445 ud = [start stop len baseangle tipangle wid page crossdir ends]; | |
446 | |
447 % Set Page defaults | |
448 %page = (~isnan(page))&(page); | |
449 if isnan(page) | |
450 page = 0; | |
451 end | |
452 | |
453 % Get axes limits, range, min; correct for aspect ratio and log scale | |
454 axm = zeros(3,narrows); | |
455 axr = zeros(3,narrows); | |
456 axrev = zeros(3,narrows); | |
457 ap = zeros(2,narrows); | |
458 xyzlog = zeros(3,narrows); | |
459 limmin = zeros(2,narrows); | |
460 limrange = zeros(2,narrows); | |
461 oldaxlims = zeros(narrows,7); | |
462 oneax = all(ax==ax(1)); | |
463 if (oneax), | |
464 T = zeros(4,4); | |
465 invT = zeros(4,4); | |
466 else, | |
467 T = zeros(16,narrows); | |
468 invT = zeros(16,narrows); | |
469 end; | |
470 axnotdone = logical(ones(size(ax))); | |
471 while (any(axnotdone)), | |
472 ii = min(find(axnotdone)); | |
473 curax = ax(ii); | |
474 curpage = page(ii); | |
475 % get axes limits and aspect ratio | |
476 axl = [get(curax,'XLim'); get(curax,'YLim'); get(curax,'ZLim')]; | |
477 oldaxlims(min(find(oldaxlims(:,1)==0)),:) = [curax reshape(axl',1,6)]; | |
478 % get axes size in pixels (points) | |
479 u = get(curax,'Units'); | |
480 axposoldunits = get(curax,'Position'); | |
481 really_curpage = curpage & strcmp(u,'normalized'); | |
482 if (really_curpage), | |
483 curfig = get(curax,'Parent'); | |
484 pu = get(curfig,'PaperUnits'); | |
485 set(curfig,'PaperUnits','points'); | |
486 pp = get(curfig,'PaperPosition'); | |
487 set(curfig,'PaperUnits',pu); | |
488 set(curax,'Units','pixels'); | |
489 curapscreen = get(curax,'Position'); | |
490 set(curax,'Units','normalized'); | |
491 curap = pp.*get(curax,'Position'); | |
492 else, | |
493 set(curax,'Units','pixels'); | |
494 curapscreen = get(curax,'Position'); | |
495 curap = curapscreen; | |
496 end; | |
497 set(curax,'Units',u); | |
498 set(curax,'Position',axposoldunits); | |
499 % handle non-stretched axes position | |
500 str_stretch = { 'DataAspectRatioMode' ; ... | |
501 'PlotBoxAspectRatioMode' ; ... | |
502 'CameraViewAngleMode' }; | |
503 str_camera = { 'CameraPositionMode' ; ... | |
504 'CameraTargetMode' ; ... | |
505 'CameraViewAngleMode' ; ... | |
506 'CameraUpVectorMode' }; | |
507 notstretched = strcmp(get(curax,str_stretch),'manual'); | |
508 manualcamera = strcmp(get(curax,str_camera),'manual'); | |
509 if ~arrow_WarpToFill(notstretched,manualcamera,curax), | |
510 % give a warning that this has not been thoroughly tested | |
511 if 0 & ARROW_STRETCH_WARN, | |
512 ARROW_STRETCH_WARN = 0; | |
513 strs = {str_stretch{1:2},str_camera{:}}; | |
514 strs = [char(ones(length(strs),1)*sprintf('\n ')) char(strs)]'; | |
515 warning([upper(mfilename) ' may not yet work quite right ' ... | |
516 'if any of the following are ''manual'':' strs(:).']); | |
517 end; | |
518 % find the true pixel size of the actual axes | |
519 texttmp = text(axl(1,[1 2 2 1 1 2 2 1]), ... | |
520 axl(2,[1 1 2 2 1 1 2 2]), ... | |
521 axl(3,[1 1 1 1 2 2 2 2]),''); | |
522 set(texttmp,'Units','points'); | |
523 textpos = get(texttmp,'Position'); | |
524 delete(texttmp); | |
525 textpos = cat(1,textpos{:}); | |
526 textpos = max(textpos(:,1:2)) - min(textpos(:,1:2)); | |
527 % adjust the axes position | |
528 if (really_curpage), | |
529 % adjust to printed size | |
530 textpos = textpos * min(curap(3:4)./textpos); | |
531 curap = [curap(1:2)+(curap(3:4)-textpos)/2 textpos]; | |
532 else, | |
533 % adjust for pixel roundoff | |
534 textpos = textpos * min(curapscreen(3:4)./textpos); | |
535 curap = [curap(1:2)+(curap(3:4)-textpos)/2 textpos]; | |
536 end; | |
537 end; | |
538 if ARROW_PERSP_WARN & ~strcmp(get(curax,'Projection'),'orthographic'), | |
539 ARROW_PERSP_WARN = 0; | |
540 warning([upper(mfilename) ' does not yet work right for 3-D perspective projection.']); | |
541 end; | |
542 % adjust limits for log scale on axes | |
543 curxyzlog = [strcmp(get(curax,'XScale'),'log'); ... | |
544 strcmp(get(curax,'YScale'),'log'); ... | |
545 strcmp(get(curax,'ZScale'),'log')]; | |
546 if (any(curxyzlog)), | |
547 ii = find([curxyzlog;curxyzlog]); | |
548 if (any(axl(ii)<=0)), | |
549 error([upper(mfilename) ' does not support non-positive limits on log-scaled axes.']); | |
550 else, | |
551 axl(ii) = log10(axl(ii)); | |
552 end; | |
553 end; | |
554 % correct for 'reverse' direction on axes; | |
555 curreverse = [strcmp(get(curax,'XDir'),'reverse'); ... | |
556 strcmp(get(curax,'YDir'),'reverse'); ... | |
557 strcmp(get(curax,'ZDir'),'reverse')]; | |
558 ii = find(curreverse); | |
559 if ~isempty(ii), | |
560 axl(ii,[1 2])=-axl(ii,[2 1]); | |
561 end; | |
562 % compute the range of 2-D values | |
563 curT = get(curax,'Xform'); | |
564 lim = curT*[0 1 0 1 0 1 0 1;0 0 1 1 0 0 1 1;0 0 0 0 1 1 1 1;1 1 1 1 1 1 1 1]; | |
565 lim = lim(1:2,:)./([1;1]*lim(4,:)); | |
566 curlimmin = min(lim')'; | |
567 curlimrange = max(lim')' - curlimmin; | |
568 curinvT = inv(curT); | |
569 if (~oneax), | |
570 curT = curT.'; | |
571 curinvT = curinvT.'; | |
572 curT = curT(:); | |
573 curinvT = curinvT(:); | |
574 end; | |
575 % check which arrows to which cur corresponds | |
576 ii = find((ax==curax)&(page==curpage)); | |
577 oo = ones(1,length(ii)); | |
578 axr(:,ii) = diff(axl')' * oo; | |
579 axm(:,ii) = axl(:,1) * oo; | |
580 axrev(:,ii) = curreverse * oo; | |
581 ap(:,ii) = curap(3:4)' * oo; | |
582 xyzlog(:,ii) = curxyzlog * oo; | |
583 limmin(:,ii) = curlimmin * oo; | |
584 limrange(:,ii) = curlimrange * oo; | |
585 if (oneax), | |
586 T = curT; | |
587 invT = curinvT; | |
588 else, | |
589 T(:,ii) = curT * oo; | |
590 invT(:,ii) = curinvT * oo; | |
591 end; | |
592 axnotdone(ii) = zeros(1,length(ii)); | |
593 end; | |
594 oldaxlims(oldaxlims(:,1)==0,:)=[]; | |
595 | |
596 % correct for log scales | |
597 curxyzlog = xyzlog.'; | |
598 ii = find(curxyzlog(:)); | |
599 if ~isempty(ii), | |
600 start( ii) = real(log10(start( ii))); | |
601 stop( ii) = real(log10(stop( ii))); | |
602 if (all(imag(crossdir)==0)), % pulled (ii) subscript on crossdir, 12/5/96 eaj | |
603 crossdir(ii) = real(log10(crossdir(ii))); | |
604 end; | |
605 end; | |
606 | |
607 % correct for reverse directions | |
608 ii = find(axrev.'); | |
609 if ~isempty(ii), | |
610 start( ii) = -start( ii); | |
611 stop( ii) = -stop( ii); | |
612 crossdir(ii) = -crossdir(ii); | |
613 end; | |
614 | |
615 % transpose start/stop values | |
616 start = start.'; | |
617 stop = stop.'; | |
618 | |
619 % take care of defaults, page was done above | |
620 ii=find(isnan(start(:) )); if ~isempty(ii), start(ii) = axm(ii)+axr(ii)/2; end; | |
621 ii=find(isnan(stop(:) )); if ~isempty(ii), stop(ii) = axm(ii)+axr(ii)/2; end; | |
622 ii=find(isnan(crossdir(:) )); if ~isempty(ii), crossdir(ii) = zeros(length(ii),1); end; | |
623 ii=find(isnan(len )); if ~isempty(ii), len(ii) = ones(length(ii),1)*deflen; end; | |
624 ii=find(isnan(baseangle )); if ~isempty(ii), baseangle(ii) = ones(length(ii),1)*defbaseangle; end; | |
625 ii=find(isnan(tipangle )); if ~isempty(ii), tipangle(ii) = ones(length(ii),1)*deftipangle; end; | |
626 ii=find(isnan(wid )); if ~isempty(ii), wid(ii) = ones(length(ii),1)*defwid; end; | |
627 ii=find(isnan(ends )); if ~isempty(ii), ends(ii) = ones(length(ii),1)*defends; end; | |
628 | |
629 % transpose rest of values | |
630 len = len.'; | |
631 baseangle = baseangle.'; | |
632 tipangle = tipangle.'; | |
633 wid = wid.'; | |
634 page = page.'; | |
635 crossdir = crossdir.'; | |
636 ends = ends.'; | |
637 ax = ax.'; | |
638 | |
639 % given x, a 3xN matrix of points in 3-space; | |
640 % want to convert to X, the corresponding 4xN 2-space matrix | |
641 % | |
642 % tmp1=[(x-axm)./axr; ones(1,size(x,1))]; | |
643 % if (oneax), X=T*tmp1; | |
644 % else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T.*tmp1; | |
645 % tmp2=zeros(4,4*N); tmp2(:)=tmp1(:); | |
646 % X=zeros(4,N); X(:)=sum(tmp2)'; end; | |
647 % X = X ./ (ones(4,1)*X(4,:)); | |
648 | |
649 % for all points with start==stop, start=stop-(verysmallvalue)*(up-direction); | |
650 ii = find(all(start==stop)); | |
651 if ~isempty(ii), | |
652 % find an arrowdir vertical on screen and perpendicular to viewer | |
653 % transform to 2-D | |
654 tmp1 = [(stop(:,ii)-axm(:,ii))./axr(:,ii);ones(1,length(ii))]; | |
655 if (oneax), twoD=T*tmp1; | |
656 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T(:,ii).*tmp1; | |
657 tmp2=zeros(4,4*length(ii)); tmp2(:)=tmp1(:); | |
658 twoD=zeros(4,length(ii)); twoD(:)=sum(tmp2)'; end; | |
659 twoD=twoD./(ones(4,1)*twoD(4,:)); | |
660 % move the start point down just slightly | |
661 tmp1 = twoD + [0;-1/1000;0;0]*(limrange(2,ii)./ap(2,ii)); | |
662 % transform back to 3-D | |
663 if (oneax), threeD=invT*tmp1; | |
664 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT(:,ii).*tmp1; | |
665 tmp2=zeros(4,4*length(ii)); tmp2(:)=tmp1(:); | |
666 threeD=zeros(4,length(ii)); threeD(:)=sum(tmp2)'; end; | |
667 start(:,ii) = (threeD(1:3,:)./(ones(3,1)*threeD(4,:))).*axr(:,ii)+axm(:,ii); | |
668 end; | |
669 | |
670 % compute along-arrow points | |
671 % transform Start points | |
672 tmp1=[(start-axm)./axr;ones(1,narrows)]; | |
673 if (oneax), X0=T*tmp1; | |
674 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T.*tmp1; | |
675 tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); | |
676 X0=zeros(4,narrows); X0(:)=sum(tmp2)'; end; | |
677 X0=X0./(ones(4,1)*X0(4,:)); | |
678 % transform Stop points | |
679 tmp1=[(stop-axm)./axr;ones(1,narrows)]; | |
680 if (oneax), Xf=T*tmp1; | |
681 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T.*tmp1; | |
682 tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); | |
683 Xf=zeros(4,narrows); Xf(:)=sum(tmp2)'; end; | |
684 Xf=Xf./(ones(4,1)*Xf(4,:)); | |
685 % compute pixel distance between points | |
686 D = sqrt(sum(((Xf(1:2,:)-X0(1:2,:)).*(ap./limrange)).^2)); | |
687 % compute and modify along-arrow distances | |
688 len1 = len; | |
689 len2 = len - (len.*tan(tipangle/180*pi)-wid/2).*tan((90-baseangle)/180*pi); | |
690 slen0 = zeros(1,narrows); | |
691 slen1 = len1 .* ((ends==2)|(ends==3)); | |
692 slen2 = len2 .* ((ends==2)|(ends==3)); | |
693 len0 = zeros(1,narrows); | |
694 len1 = len1 .* ((ends==1)|(ends==3)); | |
695 len2 = len2 .* ((ends==1)|(ends==3)); | |
696 % for no start arrowhead | |
697 ii=find((ends==1)&(D<len2)); | |
698 if ~isempty(ii), | |
699 slen0(ii) = D(ii)-len2(ii); | |
700 end; | |
701 % for no end arrowhead | |
702 ii=find((ends==2)&(D<slen2)); | |
703 if ~isempty(ii), | |
704 len0(ii) = D(ii)-slen2(ii); | |
705 end; | |
706 len1 = len1 + len0; | |
707 len2 = len2 + len0; | |
708 slen1 = slen1 + slen0; | |
709 slen2 = slen2 + slen0; | |
710 % note: the division by D below will probably not be accurate if both | |
711 % of the following are true: | |
712 % 1. the ratio of the line length to the arrowhead | |
713 % length is large | |
714 % 2. the view is highly perspective. | |
715 % compute stoppoints | |
716 tmp1=X0.*(ones(4,1)*(len0./D))+Xf.*(ones(4,1)*(1-len0./D)); | |
717 if (oneax), tmp3=invT*tmp1; | |
718 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; | |
719 tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); | |
720 tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; | |
721 stoppoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; | |
722 % compute tippoints | |
723 tmp1=X0.*(ones(4,1)*(len1./D))+Xf.*(ones(4,1)*(1-len1./D)); | |
724 if (oneax), tmp3=invT*tmp1; | |
725 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; | |
726 tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); | |
727 tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; | |
728 tippoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; | |
729 % compute basepoints | |
730 tmp1=X0.*(ones(4,1)*(len2./D))+Xf.*(ones(4,1)*(1-len2./D)); | |
731 if (oneax), tmp3=invT*tmp1; | |
732 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; | |
733 tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); | |
734 tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; | |
735 basepoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; | |
736 % compute startpoints | |
737 tmp1=X0.*(ones(4,1)*(1-slen0./D))+Xf.*(ones(4,1)*(slen0./D)); | |
738 if (oneax), tmp3=invT*tmp1; | |
739 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; | |
740 tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); | |
741 tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; | |
742 startpoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; | |
743 % compute stippoints | |
744 tmp1=X0.*(ones(4,1)*(1-slen1./D))+Xf.*(ones(4,1)*(slen1./D)); | |
745 if (oneax), tmp3=invT*tmp1; | |
746 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; | |
747 tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); | |
748 tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; | |
749 stippoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; | |
750 % compute sbasepoints | |
751 tmp1=X0.*(ones(4,1)*(1-slen2./D))+Xf.*(ones(4,1)*(slen2./D)); | |
752 if (oneax), tmp3=invT*tmp1; | |
753 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=invT.*tmp1; | |
754 tmp2=zeros(4,4*narrows); tmp2(:)=tmp1(:); | |
755 tmp3=zeros(4,narrows); tmp3(:)=sum(tmp2)'; end; | |
756 sbasepoint = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)).*axr+axm; | |
757 | |
758 % compute cross-arrow directions for arrows with NormalDir specified | |
759 if (any(imag(crossdir(:))~=0)), | |
760 ii = find(any(imag(crossdir)~=0)); | |
761 crossdir(:,ii) = cross((stop(:,ii)-start(:,ii))./axr(:,ii), ... | |
762 imag(crossdir(:,ii))).*axr(:,ii); | |
763 end; | |
764 | |
765 % compute cross-arrow directions | |
766 basecross = crossdir + basepoint; | |
767 tipcross = crossdir + tippoint; | |
768 sbasecross = crossdir + sbasepoint; | |
769 stipcross = crossdir + stippoint; | |
770 ii = find(all(crossdir==0)|any(isnan(crossdir))); | |
771 if ~isempty(ii), | |
772 numii = length(ii); | |
773 % transform start points | |
774 tmp1 = [basepoint(:,ii) tippoint(:,ii) sbasepoint(:,ii) stippoint(:,ii)]; | |
775 tmp1 = (tmp1-axm(:,[ii ii ii ii])) ./ axr(:,[ii ii ii ii]); | |
776 tmp1 = [tmp1; ones(1,4*numii)]; | |
777 if (oneax), X0=T*tmp1; | |
778 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T(:,[ii ii ii ii]).*tmp1; | |
779 tmp2=zeros(4,16*numii); tmp2(:)=tmp1(:); | |
780 X0=zeros(4,4*numii); X0(:)=sum(tmp2)'; end; | |
781 X0=X0./(ones(4,1)*X0(4,:)); | |
782 % transform stop points | |
783 tmp1 = [(2*stop(:,ii)-start(:,ii)-axm(:,ii))./axr(:,ii);ones(1,numii)]; | |
784 tmp1 = [tmp1 tmp1 tmp1 tmp1]; | |
785 if (oneax), Xf=T*tmp1; | |
786 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=T(:,[ii ii ii ii]).*tmp1; | |
787 tmp2=zeros(4,16*numii); tmp2(:)=tmp1(:); | |
788 Xf=zeros(4,4*numii); Xf(:)=sum(tmp2)'; end; | |
789 Xf=Xf./(ones(4,1)*Xf(4,:)); | |
790 % compute perpendicular directions | |
791 pixfact = ((limrange(1,ii)./limrange(2,ii)).*(ap(2,ii)./ap(1,ii))).^2; | |
792 pixfact = [pixfact pixfact pixfact pixfact]; | |
793 pixfact = [pixfact;1./pixfact]; | |
794 [dummyval,jj] = max(abs(Xf(1:2,:)-X0(1:2,:))); | |
795 jj1 = ((1:4)'*ones(1,length(jj))==ones(4,1)*jj); | |
796 jj2 = ((1:4)'*ones(1,length(jj))==ones(4,1)*(3-jj)); | |
797 jj3 = jj1(1:2,:); | |
798 Xp = X0; | |
799 Xp(jj2) = X0(jj2) + ones(sum(jj2(:)),1); | |
800 Xp(jj1) = X0(jj1) - (Xf(jj2)-X0(jj2))./(Xf(jj1)-X0(jj1)) .* pixfact(jj3); | |
801 % inverse transform the cross points | |
802 if (oneax), Xp=invT*Xp; | |
803 else, tmp1=[Xp;Xp;Xp;Xp]; tmp1=invT(:,[ii ii ii ii]).*tmp1; | |
804 tmp2=zeros(4,16*numii); tmp2(:)=tmp1(:); | |
805 Xp=zeros(4,4*numii); Xp(:)=sum(tmp2)'; end; | |
806 Xp=(Xp(1:3,:)./(ones(3,1)*Xp(4,:))).*axr(:,[ii ii ii ii])+axm(:,[ii ii ii ii]); | |
807 basecross(:,ii) = Xp(:,0*numii+(1:numii)); | |
808 tipcross(:,ii) = Xp(:,1*numii+(1:numii)); | |
809 sbasecross(:,ii) = Xp(:,2*numii+(1:numii)); | |
810 stipcross(:,ii) = Xp(:,3*numii+(1:numii)); | |
811 end; | |
812 | |
813 % compute all points | |
814 % compute start points | |
815 axm11 = [axm axm axm axm axm axm axm axm axm axm axm]; | |
816 axr11 = [axr axr axr axr axr axr axr axr axr axr axr]; | |
817 st = [stoppoint tippoint basepoint sbasepoint stippoint startpoint stippoint sbasepoint basepoint tippoint stoppoint]; | |
818 tmp1 = (st - axm11) ./ axr11; | |
819 tmp1 = [tmp1; ones(1,size(tmp1,2))]; | |
820 if (oneax), X0=T*tmp1; | |
821 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=[T T T T T T T T T T T].*tmp1; | |
822 tmp2=zeros(4,44*narrows); tmp2(:)=tmp1(:); | |
823 X0=zeros(4,11*narrows); X0(:)=sum(tmp2)'; end; | |
824 X0=X0./(ones(4,1)*X0(4,:)); | |
825 % compute stop points | |
826 tmp1 = ([start tipcross basecross sbasecross stipcross stop stipcross sbasecross basecross tipcross start] ... | |
827 - axm11) ./ axr11; | |
828 tmp1 = [tmp1; ones(1,size(tmp1,2))]; | |
829 if (oneax), Xf=T*tmp1; | |
830 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=[T T T T T T T T T T T].*tmp1; | |
831 tmp2=zeros(4,44*narrows); tmp2(:)=tmp1(:); | |
832 Xf=zeros(4,11*narrows); Xf(:)=sum(tmp2)'; end; | |
833 Xf=Xf./(ones(4,1)*Xf(4,:)); | |
834 % compute lengths | |
835 len0 = len.*((ends==1)|(ends==3)).*tan(tipangle/180*pi); | |
836 slen0 = len.*((ends==2)|(ends==3)).*tan(tipangle/180*pi); | |
837 le = [zeros(1,narrows) len0 wid/2 wid/2 slen0 zeros(1,narrows) -slen0 -wid/2 -wid/2 -len0 zeros(1,narrows)]; | |
838 aprange = ap./limrange; | |
839 aprange = [aprange aprange aprange aprange aprange aprange aprange aprange aprange aprange aprange]; | |
840 D = sqrt(sum(((Xf(1:2,:)-X0(1:2,:)).*aprange).^2)); | |
841 Dii=find(D==0); if ~isempty(Dii), D=D+(D==0); le(Dii)=zeros(1,length(Dii)); end; %should fix DivideByZero warnings | |
842 tmp1 = X0.*(ones(4,1)*(1-le./D)) + Xf.*(ones(4,1)*(le./D)); | |
843 % inverse transform | |
844 if (oneax), tmp3=invT*tmp1; | |
845 else, tmp1=[tmp1;tmp1;tmp1;tmp1]; tmp1=[invT invT invT invT invT invT invT invT invT invT invT].*tmp1; | |
846 tmp2=zeros(4,44*narrows); tmp2(:)=tmp1(:); | |
847 tmp3=zeros(4,11*narrows); tmp3(:)=sum(tmp2)'; end; | |
848 pts = tmp3(1:3,:)./(ones(3,1)*tmp3(4,:)) .* axr11 + axm11; | |
849 | |
850 % correct for ones where the crossdir was specified | |
851 ii = find(~(all(crossdir==0)|any(isnan(crossdir)))); | |
852 if ~isempty(ii), | |
853 D1 = [pts(:,1*narrows+ii)-pts(:,9*narrows+ii) ... | |
854 pts(:,2*narrows+ii)-pts(:,8*narrows+ii) ... | |
855 pts(:,3*narrows+ii)-pts(:,7*narrows+ii) ... | |
856 pts(:,4*narrows+ii)-pts(:,6*narrows+ii) ... | |
857 pts(:,6*narrows+ii)-pts(:,4*narrows+ii) ... | |
858 pts(:,7*narrows+ii)-pts(:,3*narrows+ii) ... | |
859 pts(:,8*narrows+ii)-pts(:,2*narrows+ii) ... | |
860 pts(:,9*narrows+ii)-pts(:,1*narrows+ii)]/2; | |
861 ii = ii'*ones(1,8) + ones(length(ii),1)*[1:4 6:9]*narrows; | |
862 ii = ii(:)'; | |
863 pts(:,ii) = st(:,ii) + D1; | |
864 end; | |
865 | |
866 | |
867 % readjust for reverse directions | |
868 iicols=(1:narrows)'; iicols=iicols(:,ones(1,11)); iicols=iicols(:).'; | |
869 tmp1=axrev(:,iicols); | |
870 ii = find(tmp1(:)); if ~isempty(ii), pts(ii)=-pts(ii); end; | |
871 | |
872 % readjust for log scale on axes | |
873 tmp1=xyzlog(:,iicols); | |
874 ii = find(tmp1(:)); if ~isempty(ii), pts(ii)=10.^pts(ii); end; | |
875 | |
876 % compute the x,y,z coordinates of the patches; | |
877 ii = narrows*(0:10)'*ones(1,narrows) + ones(11,1)*(1:narrows); | |
878 ii = ii(:)'; | |
879 x = zeros(11,narrows); | |
880 y = zeros(11,narrows); | |
881 z = zeros(11,narrows); | |
882 x(:) = pts(1,ii)'; | |
883 y(:) = pts(2,ii)'; | |
884 z(:) = pts(3,ii)'; | |
885 | |
886 % do the output | |
887 if (nargout<=1) | |
888 % % create or modify the patches | |
889 if isnan(ispatch), ispatch =0; end | |
890 newpatch = ispatch & (isempty(oldh)|~strcmp(get(oldh,'Type'),'patch')); | |
891 newline = ~ispatch & (isempty(oldh)|~strcmp(get(oldh,'Type'),'line')); | |
892 if isempty(oldh), H=zeros(narrows,1); else, H=oldh; end; | |
893 % % make or modify the arrows | |
894 for k=1:narrows, | |
895 if all(isnan(ud(k,[3 6])))&arrow_is2DXY(ax(k)), zz=[]; else, zz=z(:,k); end; | |
896 xyz = {'XData',x(:,k),'YData',y(:,k),'ZData',zz,'Tag',ArrowTag}; | |
897 if newpatch(k)|newline(k), | |
898 if newpatch(k), | |
899 H(k) = patch(xyz{:}); | |
900 else, | |
901 H(k) = line(xyz{:}); | |
902 end; | |
903 if ~isempty(oldh), arrow_copyprops(oldh(k),H(k)); end; | |
904 else, | |
905 if ispatch(k), xyz={xyz{:},'CData',[]}; end; | |
906 set(H(k),xyz{:}); | |
907 end; | |
908 end; | |
909 if ~isempty(oldh), delete(oldh(oldh~=H)); end; | |
910 % % additional properties | |
911 set(H,'Clipping','off'); | |
912 set(H,{'UserData'},num2cell(ud,2)); | |
913 if (length(extraprops)>0), set(H,extraprops{:}); end; | |
914 % handle choosing arrow Start and/or Stop locations if unspecified | |
915 [H,oldaxlims,errstr] = arrow_clicks(H,ud,x,y,z,ax,oldaxlims); | |
916 if ~isempty(errstr), error([upper(mfilename) ' got ' errstr]); end; | |
917 % set the output | |
918 if (nargout>0), h=H; end; | |
919 % make sure the axis limits did not change | |
920 if isempty(oldaxlims), | |
921 ARROW_AXLIMITS = []; | |
922 else, | |
923 lims = get(oldaxlims(:,1),{'XLim','YLim','ZLim'})'; | |
924 lims = reshape(cat(2,lims{:}),6,size(lims,2)); | |
925 %mask = arrow_is2DXY(oldaxlims(:,1)); | |
926 %oldaxlims(mask,6:7) = lims(5:6,mask)'; | |
927 ARROW_AXLIMITS = oldaxlims(find(any(oldaxlims(:,2:7)'~=lims)),:); | |
928 if ~isempty(ARROW_AXLIMITS), | |
929 warning(arrow_warnlimits(ARROW_AXLIMITS,narrows)); | |
930 end; | |
931 end; | |
932 else, | |
933 % don't create the patch, just return the data | |
934 h=x; | |
935 yy=y; | |
936 zz=z; | |
937 end; | |
938 | |
939 | |
940 | |
941 function out = arrow_defcheck(in,def,prop) | |
942 % check if we got 'default' values | |
943 out = in; | |
944 if ~isstr(in), return; end; | |
945 if size(in,1)==1 & strncmp(lower(in),'def',3), | |
946 out = def; | |
947 elseif ~isempty(prop), | |
948 error([upper(mfilename) ' does not recognize ''' in(:)' ''' as a valid ''' prop ''' string.']); | |
949 end; | |
950 | |
951 | |
952 | |
953 function [H,oldaxlims,errstr] = arrow_clicks(H,ud,x,y,z,ax,oldaxlims) | |
954 % handle choosing arrow Start and/or Stop locations if necessary | |
955 errstr = ''; | |
956 if isempty(H)|isempty(ud)|isempty(x), return; end; | |
957 % determine which (if any) need Start and/or Stop | |
958 needStart = all(isnan(ud(:,1:3)'))'; | |
959 needStop = all(isnan(ud(:,4:6)'))'; | |
960 mask = any(needStart|needStop); | |
961 if ~any(mask), return; end; | |
962 ud(~mask,:)=[]; ax(:,~mask)=[]; | |
963 x(:,~mask)=[]; y(:,~mask)=[]; z(:,~mask)=[]; | |
964 % make them invisible for the time being | |
965 set(H,'Visible','off'); | |
966 % save the current axes and limits modes; set to manual for the time being | |
967 oldAx = gca; | |
968 limModes=get(ax(:),{'XLimMode','YLimMode','ZLimMode'}); | |
969 set(ax(:),{'XLimMode','YLimMode','ZLimMode'},{'manual','manual','manual'}); | |
970 % loop over each arrow that requires attention | |
971 jj = find(mask); | |
972 for ii=1:length(jj), | |
973 h = H(jj(ii)); | |
974 axes(ax(ii)); | |
975 % figure out correct call | |
976 if needStart(ii), prop='Start'; else, prop='Stop'; end; | |
977 [wasInterrupted,errstr] = arrow_click(needStart(ii)&needStop(ii),h,prop,ax(ii)); | |
978 % handle errors and control-C | |
979 if wasInterrupted, | |
980 delete(H(jj(ii:end))); | |
981 H(jj(ii:end))=[]; | |
982 oldaxlims(jj(ii:end),:)=[]; | |
983 break; | |
984 end; | |
985 end; | |
986 % restore the axes and limit modes | |
987 axes(oldAx); | |
988 set(ax(:),{'XLimMode','YLimMode','ZLimMode'},limModes); | |
989 | |
990 function [wasInterrupted,errstr] = arrow_click(lockStart,H,prop,ax) | |
991 % handle the clicks for one arrow | |
992 fig = get(ax,'Parent'); | |
993 % save some things | |
994 oldFigProps = {'Pointer','WindowButtonMotionFcn','WindowButtonUpFcn'}; | |
995 oldFigValue = get(fig,oldFigProps); | |
996 oldArrowProps = {'EraseMode'}; | |
997 oldArrowValue = get(H,oldArrowProps); | |
998 set(H,'EraseMode','background'); %because 'xor' makes shaft invisible unless Width>1 | |
999 global ARROW_CLICK_H ARROW_CLICK_PROP ARROW_CLICK_AX ARROW_CLICK_USE_Z | |
1000 ARROW_CLICK_H=H; ARROW_CLICK_PROP=prop; ARROW_CLICK_AX=ax; | |
1001 ARROW_CLICK_USE_Z=~arrow_is2DXY(ax)|~arrow_planarkids(ax); | |
1002 set(fig,'Pointer','crosshair'); | |
1003 % set up the WindowButtonMotion so we can see the arrow while moving around | |
1004 set(fig,'WindowButtonUpFcn','set(gcf,''WindowButtonUpFcn'','''')', ... | |
1005 'WindowButtonMotionFcn',''); | |
1006 if ~lockStart, | |
1007 set(H,'Visible','on'); | |
1008 set(fig,'WindowButtonMotionFcn',[mfilename '(''callback'',''motion'');']); | |
1009 end; | |
1010 % wait for the button to be pressed | |
1011 [wasKeyPress,wasInterrupted,errstr] = arrow_wfbdown(fig); | |
1012 % if we wanted to click-drag, set the Start point | |
1013 if lockStart & ~wasInterrupted, | |
1014 pt = arrow_point(ARROW_CLICK_AX,ARROW_CLICK_USE_Z); | |
1015 feval(mfilename,H,'Start',pt,'Stop',pt); | |
1016 set(H,'Visible','on'); | |
1017 ARROW_CLICK_PROP='Stop'; | |
1018 set(fig,'WindowButtonMotionFcn',[mfilename '(''callback'',''motion'');']); | |
1019 % wait for the mouse button to be released | |
1020 eval('waitfor(fig,''WindowButtonUpFcn'','''');','wasInterrupted=1;'); | |
1021 if wasInterrupted, errstr=lasterr; end; | |
1022 end; | |
1023 if ~wasInterrupted, feval(mfilename,'callback','motion'); end; | |
1024 % restore some things | |
1025 set(gcf,oldFigProps,oldFigValue); | |
1026 set(H,oldArrowProps,oldArrowValue); | |
1027 | |
1028 function arrow_callback(varargin) | |
1029 % handle redrawing callbacks | |
1030 if nargin==0, return; end; | |
1031 str = varargin{1}; | |
1032 if ~isstr(str), error([upper(mfilename) ' got an invalid Callback command.']); end; | |
1033 s = lower(str); | |
1034 if strcmp(s,'motion'), | |
1035 % motion callback | |
1036 global ARROW_CLICK_H ARROW_CLICK_PROP ARROW_CLICK_AX ARROW_CLICK_USE_Z | |
1037 feval(mfilename,ARROW_CLICK_H,ARROW_CLICK_PROP,arrow_point(ARROW_CLICK_AX,ARROW_CLICK_USE_Z)); | |
1038 drawnow; | |
1039 else, | |
1040 error([upper(mfilename) ' does not recognize ''' str(:).' ''' as a valid Callback option.']); | |
1041 end; | |
1042 | |
1043 function out = arrow_point(ax,use_z) | |
1044 % return the point on the given axes | |
1045 if nargin==0, ax=gca; end; | |
1046 if nargin<2, use_z=~arrow_is2DXY(ax)|~arrow_planarkids(ax); end; | |
1047 out = get(ax,'CurrentPoint'); | |
1048 out = out(1,:); | |
1049 if ~use_z, out=out(1:2); end; | |
1050 | |
1051 function [wasKeyPress,wasInterrupted,errstr] = arrow_wfbdown(fig) | |
1052 % wait for button down ignoring object ButtonDownFcn's | |
1053 if nargin==0, fig=gcf; end; | |
1054 errstr = ''; | |
1055 % save ButtonDownFcn values | |
1056 objs = findobj(fig); | |
1057 buttonDownFcns = get(objs,'ButtonDownFcn'); | |
1058 mask=~strcmp(buttonDownFcns,''); objs=objs(mask); buttonDownFcns=buttonDownFcns(mask); | |
1059 set(objs,'ButtonDownFcn',''); | |
1060 % save other figure values | |
1061 figProps = {'KeyPressFcn','WindowButtonDownFcn'}; | |
1062 figValue = get(fig,figProps); | |
1063 % do the real work | |
1064 set(fig,'KeyPressFcn','set(gcf,''KeyPressFcn'','''',''WindowButtonDownFcn'','''');', ... | |
1065 'WindowButtonDownFcn','set(gcf,''WindowButtonDownFcn'','''')'); | |
1066 lasterr(''); | |
1067 wasInterrupted=0; eval('waitfor(fig,''WindowButtonDownFcn'','''');','wasInterrupted=1;'); | |
1068 wasKeyPress = ~wasInterrupted & strcmp(get(fig,'KeyPressFcn'),''); | |
1069 if wasInterrupted, errstr=lasterr; end; | |
1070 % restore ButtonDownFcn and other figure values | |
1071 set(objs,'ButtonDownFcn',buttonDownFcns); | |
1072 set(fig,figProps,figValue); | |
1073 | |
1074 | |
1075 | |
1076 function [out,is2D] = arrow_is2DXY(ax) | |
1077 % check if axes are 2-D X-Y plots | |
1078 % may not work for modified camera angles, etc. | |
1079 out = zeros(size(ax)); % 2-D X-Y plots | |
1080 is2D = out; % any 2-D plots | |
1081 views = get(ax(:),{'View'}); | |
1082 views = cat(1,views{:}); | |
1083 out(:) = abs(views(:,2))==90; | |
1084 is2D(:) = out(:) | all(rem(views',90)==0)'; | |
1085 | |
1086 function out = arrow_planarkids(ax) | |
1087 % check if axes descendents all have empty ZData (lines,patches,surfaces) | |
1088 out = logical(ones(size(ax))); | |
1089 allkids = get(ax(:),{'Children'}); | |
1090 for k=1:length(allkids), | |
1091 kids = get([findobj(allkids{k},'flat','Type','line') | |
1092 findobj(allkids{k},'flat','Type','patch') | |
1093 findobj(allkids{k},'flat','Type','surface')],{'ZData'}); | |
1094 for j=1:length(kids), | |
1095 if ~isempty(kids{j}), out(k)=logical(0); break; end; | |
1096 end; | |
1097 end; | |
1098 | |
1099 | |
1100 | |
1101 function arrow_fixlimits(axlimits) | |
1102 % reset the axis limits as necessary | |
1103 if isempty(axlimits), disp([upper(mfilename) ' does not remember any axis limits to reset.']); end; | |
1104 for k=1:size(axlimits,1), | |
1105 if any(get(axlimits(k,1),'XLim')~=axlimits(k,2:3)), set(axlimits(k,1),'XLim',axlimits(k,2:3)); end; | |
1106 if any(get(axlimits(k,1),'YLim')~=axlimits(k,4:5)), set(axlimits(k,1),'YLim',axlimits(k,4:5)); end; | |
1107 if any(get(axlimits(k,1),'ZLim')~=axlimits(k,6:7)), set(axlimits(k,1),'ZLim',axlimits(k,6:7)); end; | |
1108 end; | |
1109 | |
1110 | |
1111 | |
1112 function out = arrow_WarpToFill(notstretched,manualcamera,curax) | |
1113 % check if we are in "WarpToFill" mode. | |
1114 out = strcmp(get(curax,'WarpToFill'),'on'); | |
1115 % 'WarpToFill' is undocumented, so may need to replace this by | |
1116 % out = ~( any(notstretched) & any(manualcamera) ); | |
1117 | |
1118 | |
1119 | |
1120 function out = arrow_warnlimits(axlimits,narrows) | |
1121 % create a warning message if we've changed the axis limits | |
1122 msg = ''; | |
1123 switch (size(axlimits,1)==1) | |
1124 case 1, msg=''; | |
1125 case 2, msg='on two axes '; | |
1126 otherwise, msg='on several axes '; | |
1127 end; | |
1128 msg = [upper(mfilename) ' changed the axis limits ' msg ... | |
1129 'when adding the arrow']; | |
1130 if (narrows>1), msg=[msg 's']; end; | |
1131 out = [msg '.' sprintf('\n') ' Call ' upper(mfilename) ... | |
1132 ' FIXLIMITS to reset them now.']; | |
1133 | |
1134 | |
1135 | |
1136 function arrow_copyprops(fm,to) | |
1137 % copy line properties to patches | |
1138 props = {'EraseMode','LineStyle','LineWidth','Marker','MarkerSize',... | |
1139 'MarkerEdgeColor','MarkerFaceColor','ButtonDownFcn', ... | |
1140 'Clipping','DeleteFcn','BusyAction','HandleVisibility', ... | |
1141 'Selected','SelectionHighlight','Visible'}; | |
1142 lineprops = {'Color', props{:}}; | |
1143 patchprops = {'EdgeColor',props{:}}; | |
1144 patch2props = {'FaceColor',patchprops{:}}; | |
1145 fmpatch = strcmp(get(fm,'Type'),'patch'); | |
1146 topatch = strcmp(get(to,'Type'),'patch'); | |
1147 set(to( fmpatch& topatch),patch2props,get(fm( fmpatch& topatch),patch2props)); %p->p | |
1148 set(to(~fmpatch&~topatch),lineprops, get(fm(~fmpatch&~topatch),lineprops )); %l->l | |
1149 set(to( fmpatch&~topatch),lineprops, get(fm( fmpatch&~topatch),patchprops )); %p->l | |
1150 set(to(~fmpatch& topatch),patchprops, get(fm(~fmpatch& topatch),lineprops) ,'FaceColor','none'); %l->p | |
1151 | |
1152 | |
1153 | |
1154 function arrow_props | |
1155 % display further help info about ARROW properties | |
1156 c = sprintf('\n'); | |
1157 disp([c ... | |
1158 'ARROW Properties: Default values are given in [square brackets], and other' c ... | |
1159 ' acceptable equivalent property names are in (parenthesis).' c c ... | |
1160 ' Start The starting points. For N arrows, B' c ... | |
1161 ' this should be a Nx2 or Nx3 matrix. /|\ ^' c ... | |
1162 ' Stop The end points. For N arrows, this /|||\ |' c ... | |
1163 ' should be a Nx2 or Nx3 matrix. //|||\\ L|' c ... | |
1164 ' Length Length of the arrowhead (in pixels on ///|||\\\ e|' c ... | |
1165 ' screen, points on a page). [16] (Len) ////|||\\\\ n|' c ... | |
1166 ' BaseAngle Angle (degrees) of the base angle /////|D|\\\\\ g|' c ... | |
1167 ' ADE. For a simple stick arrow, use //// ||| \\\\ t|' c ... | |
1168 ' BaseAngle=TipAngle. [90] (Base) /// ||| \\\ h|' c ... | |
1169 ' TipAngle Angle (degrees) of tip angle ABC. //<----->|| \\ |' c ... | |
1170 ' [16] (Tip) / base ||| \ V' c ... | |
1171 ' Width Width of the base in pixels. Not E angle ||<-------->C' c ... | |
1172 ' the ''LineWidth'' prop. [0] (Wid) |||tipangle' c ... | |
1173 ' Page If provided, non-empty, and not NaN, |||' c ... | |
1174 ' this causes ARROW to use hardcopy |||' c ... | |
1175 ' rather than onscreen proportions. A' c ... | |
1176 ' This is important if screen aspect --> <-- width' c ... | |
1177 ' ratio and hardcopy aspect ratio are ----CrossDir---->' c ... | |
1178 ' vastly different. []' c... | |
1179 ' CrossDir A vector giving the direction towards which the fletches' c ... | |
1180 ' on the arrow should go. [computed such that it is perpen-' c ... | |
1181 ' dicular to both the arrow direction and the view direction' c ... | |
1182 ' (i.e., as if it was pasted on a normal 2-D graph)] (Note' c ... | |
1183 ' that CrossDir is a vector. Also note that if an axis is' c ... | |
1184 ' plotted on a log scale, then the corresponding component' c ... | |
1185 ' of CrossDir must also be set appropriately, i.e., to 1 for' c ... | |
1186 ' no change in that direction, >1 for a positive change, >0' c ... | |
1187 ' and <1 for negative change.)' c ... | |
1188 ' NormalDir A vector normal to the fletch direction (CrossDir is then' c ... | |
1189 ' computed by the vector cross product [Line]x[NormalDir]). []' c ... | |
1190 ' (Note that NormalDir is a vector. Unlike CrossDir,' c ... | |
1191 ' NormalDir is used as is regardless of log-scaled axes.)' c ... | |
1192 ' Ends Set which end has an arrowhead. Valid values are ''none'',' c ... | |
1193 ' ''stop'', ''start'', and ''both''. [''stop''] (End)' c... | |
1194 ' ObjectHandles Vector of handles to previously-created arrows to be' c ... | |
1195 ' updated or line objects to be converted to arrows.' c ... | |
1196 ' [] (Object,Handle)' c ]); | |
1197 | |
1198 | |
1199 | |
1200 function out = arrow_demo | |
1201 % demo | |
1202 % create the data | |
1203 [x,y,z] = peaks; | |
1204 [ddd,out.iii]=max(z(:)); | |
1205 out.axlim = [min(x(:)) max(x(:)) min(y(:)) max(y(:)) min(z(:)) max(z(:))]; | |
1206 | |
1207 % modify it by inserting some NaN's | |
1208 [m,n] = size(z); | |
1209 m = floor(m/2); | |
1210 n = floor(n/2); | |
1211 z(1:m,1:n) = NaN*ones(m,n); | |
1212 | |
1213 % graph it | |
1214 clf('reset'); | |
1215 out.hs=surf(x,y,z); | |
1216 out.x=x; out.y=y; out.z=z; | |
1217 xlabel('x'); ylabel('y'); | |
1218 | |
1219 function h = arrow_demo3(in) | |
1220 % set the view | |
1221 axlim = in.axlim; | |
1222 axis(axlim); | |
1223 zlabel('z'); | |
1224 %set(in.hs,'FaceColor','interp'); | |
1225 view(viewmtx(-37.5,30,20)); | |
1226 title(['Demo of the capabilities of the ARROW function in 3-D']); | |
1227 | |
1228 % Normal blue arrow | |
1229 h1 = feval(mfilename,[axlim(1) axlim(4) 4],[-.8 1.2 4], ... | |
1230 'EdgeColor','b','FaceColor','b'); | |
1231 | |
1232 % Normal white arrow, clipped by the surface | |
1233 h2 = feval(mfilename,axlim([1 4 6]),[0 2 4]); | |
1234 t=text(-2.4,2.7,7.7,'arrow clipped by surf'); | |
1235 | |
1236 % Baseangle<90 | |
1237 h3 = feval(mfilename,[3 .125 3.5],[1.375 0.125 3.5],30,50); | |
1238 t2=text(3.1,.125,3.5,'local maximum'); | |
1239 | |
1240 % Baseangle<90, fill and edge colors different | |
1241 h4 = feval(mfilename,axlim(1:2:5)*.5,[0 0 0],36,60,25, ... | |
1242 'EdgeColor','b','FaceColor','c'); | |
1243 t3=text(axlim(1)*.5,axlim(3)*.5,axlim(5)*.5-.75,'origin'); | |
1244 set(t3,'HorizontalAlignment','center'); | |
1245 | |
1246 % Baseangle>90, black fill | |
1247 h5 = feval(mfilename,[-2.9 2.9 3],[-1.3 .4 3.2],30,120,[],6, ... | |
1248 'EdgeColor','r','FaceColor','k','LineWidth',2); | |
1249 | |
1250 % Baseangle>90, no fill | |
1251 h6 = feval(mfilename,[-2.9 2.9 1.3],[-1.3 .4 1.5],30,120,[],6, ... | |
1252 'EdgeColor','r','FaceColor','none','LineWidth',2); | |
1253 | |
1254 % Stick arrow | |
1255 h7 = feval(mfilename,[-1.6 -1.65 -6.5],[0 -1.65 -6.5],[],16,16); | |
1256 t4=text(-1.5,-1.65,-7.25,'global mininum'); | |
1257 set(t4,'HorizontalAlignment','center'); | |
1258 | |
1259 % Normal, black fill | |
1260 h8 = feval(mfilename,[-1.4 0 -7.2],[-1.4 0 -3],'FaceColor','k'); | |
1261 t5=text(-1.5,0,-7.75,'local minimum'); | |
1262 set(t5,'HorizontalAlignment','center'); | |
1263 | |
1264 % Gray fill, crossdir specified, 'LineStyle' -- | |
1265 h9 = feval(mfilename,[-3 2.2 -6],[-3 2.2 -.05],36,[],27,6,[],[0 -1 0], ... | |
1266 'EdgeColor','k','FaceColor',.75*[1 1 1],'LineStyle','--'); | |
1267 | |
1268 % a series of normal arrows, linearly spaced, crossdir specified | |
1269 h10y=(0:4)'/3; | |
1270 h10 = feval(mfilename,[-3*ones(size(h10y)) h10y -6.5*ones(size(h10y))], ... | |
1271 [-3*ones(size(h10y)) h10y -.05*ones(size(h10y))], ... | |
1272 12,[],[],[],[],[0 -1 0]); | |
1273 | |
1274 % a series of normal arrows, linearly spaced | |
1275 h11x=(1:.33:2.8)'; | |
1276 h11 = feval(mfilename,[h11x -3*ones(size(h11x)) 6.5*ones(size(h11x))], ... | |
1277 [h11x -3*ones(size(h11x)) -.05*ones(size(h11x))]); | |
1278 | |
1279 % series of magenta arrows, radially oriented, crossdir specified | |
1280 h12x=2; h12y=-3; h12z=axlim(5)/2; h12xr=1; h12zr=h12z; ir=.15;or=.81; | |
1281 h12t=(0:11)'/6*pi; | |
1282 h12 = feval(mfilename, ... | |
1283 [h12x+h12xr*cos(h12t)*ir h12y*ones(size(h12t)) ... | |
1284 h12z+h12zr*sin(h12t)*ir],[h12x+h12xr*cos(h12t)*or ... | |
1285 h12y*ones(size(h12t)) h12z+h12zr*sin(h12t)*or], ... | |
1286 10,[],[],[],[], ... | |
1287 [-h12xr*sin(h12t) zeros(size(h12t)) h12zr*cos(h12t)],... | |
1288 'FaceColor','none','EdgeColor','m'); | |
1289 | |
1290 % series of normal arrows, tangentially oriented, crossdir specified | |
1291 or13=.91; h13t=(0:.5:12)'/6*pi; | |
1292 locs = [h12x+h12xr*cos(h13t)*or13 h12y*ones(size(h13t)) h12z+h12zr*sin(h13t)*or13]; | |
1293 h13 = feval(mfilename,locs(1:end-1,:),locs(2:end,:),6); | |
1294 | |
1295 % arrow with no line ==> oriented downwards | |
1296 h14 = feval(mfilename,[3 3 .100001],[3 3 .1],30); | |
1297 t6=text(3,3,3.6,'no line'); set(t6,'HorizontalAlignment','center'); | |
1298 | |
1299 % arrow with arrowheads at both ends | |
1300 h15 = feval(mfilename,[-.5 -3 -3],[1 -3 -3],'Ends','both','FaceColor','g', ... | |
1301 'Length',20,'Width',3,'CrossDir',[0 0 1],'TipAngle',25); | |
1302 | |
1303 h=[h1;h2;h3;h4;h5;h6;h7;h8;h9;h10;h11;h12;h13;h14;h15]; | |
1304 | |
1305 function h = arrow_demo2(in) | |
1306 axlim = in.axlim; | |
1307 dolog = 1; | |
1308 if (dolog), set(in.hs,'YData',10.^get(in.hs,'YData')); end; | |
1309 shading('interp'); | |
1310 view(2); | |
1311 title(['Demo of the capabilities of the ARROW function in 2-D']); | |
1312 hold on; [C,H]=contour(in.x,in.y,in.z,20,'-'); hold off; | |
1313 for k=H', | |
1314 set(k,'ZData',(axlim(6)+1)*ones(size(get(k,'XData'))),'Color','k'); | |
1315 if (dolog), set(k,'YData',10.^get(k,'YData')); end; | |
1316 end; | |
1317 if (dolog), axis([axlim(1:2) 10.^axlim(3:4)]); set(gca,'YScale','log'); | |
1318 else, axis(axlim(1:4)); end; | |
1319 | |
1320 % Normal blue arrow | |
1321 start = [axlim(1) axlim(4) axlim(6)+2]; | |
1322 stop = [in.x(in.iii) in.y(in.iii) axlim(6)+2]; | |
1323 if (dolog), start(:,2)=10.^start(:,2); stop(:,2)=10.^stop(:,2); end; | |
1324 h1 = feval(mfilename,start,stop,'EdgeColor','b','FaceColor','b'); | |
1325 | |
1326 % three arrows with varying fill, width, and baseangle | |
1327 start = [-3 -3 10; -3 -1.5 10; -1.5 -3 10]; | |
1328 stop = [-.03 -.03 10; -.03 -1.5 10; -1.5 -.03 10]; | |
1329 if (dolog), start(:,2)=10.^start(:,2); stop(:,2)=10.^stop(:,2); end; | |
1330 h2 = feval(mfilename,start,stop,24,[90;60;120],[],[0;0;4],'Ends',str2mat('both','stop','stop')); | |
1331 set(h2(2),'EdgeColor',[0 .35 0],'FaceColor',[0 .85 .85]); | |
1332 set(h2(3),'EdgeColor','r','FaceColor',[1 .5 1]); | |
1333 h=[h1;h2]; |