1 ## Copyright (C) 2007-2012 David Bateman
3 ## This file is part of Octave.
5 ## Octave is free software; you can redistribute it and/or modify it
6 ## under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation; either version 3 of the License, or (at
8 ## your option) any later version.
10 ## Octave is distributed in the hope that it will be useful, but
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ## General Public License for more details.
15 ## You should have received a copy of the GNU General Public License
16 ## along with Octave; see the file COPYING. If not, see
17 ## <http://www.gnu.org/licenses/>.
20 ## @deftypefn {Function File} {@var{hg} =} __quiver__ (@dots{})
21 ## Undocumented internal function.
24 function hg = __quiver__ (varargin)
32 firstnonnumeric = Inf;
34 if (! isnumeric (varargin{i}))
41 if (nargin < (6 + is3d) || firstnonnumeric < (6 + is3d))
46 [x, y, z] = meshgrid (1:size(u,2), 1:size(u,1), 1:max(size(w)));
48 [x, y] = meshgrid (1:size(u,2), 1:size(u,1));
50 if (nargin >= ioff && isnumeric (varargin{ioff})
51 && isscalar (varargin{ioff}))
52 autoscale = varargin{ioff++};
64 if (isvector (x) && isvector (y) && isvector (z)
65 && (! isvector (u) || ! isvector (v) || ! isvector(w)))
66 [x, y, z] = meshgrid (x, y, z);
69 if (isvector (x) && isvector (y) && (! isvector (u) || ! isvector (v)))
70 [x, y] = meshgrid (x, y);
73 if (nargin >= ioff && isnumeric (varargin{ioff})
74 && isscalar (varargin{ioff}))
75 autoscale = varargin{ioff++};
80 have_line_spec = false;
82 while (ioff <= nargin)
83 arg = varargin{ioff++};
84 if (ischar (arg) && strncmpi (arg, "filled", 6))
86 elseif ((ischar (arg) || iscell (arg))
88 [linespec, valid] = __pltopt__ ("quiver", arg, false);
90 have_line_spec = true;
91 if (strncmp (linespec.linestyle, "none", 4))
92 linespec.linestyle = "-";
97 args {end + 1} = varargin{ioff++};
101 args {end + 1} = arg;
103 args {end + 1} = varargin{ioff++};
108 if (autoscale && numel (u) > 1)
109 ## Scale the arrows to fit in the grid
111 ny = nx = length (x);
115 dx = (max(x(:)) - min(x(:))) ./ nx;
116 dy = (max(y(:)) - min(y(:))) ./ ny;
118 dz = (max(z(:)) - min(z(:))) ./ max (size (z));
119 len = max (sqrt (u(:).^2 + v(:).^2 + w(:).^2));
122 len = max (sqrt (u(:).^2 + v(:).^2));
125 sd = sqrt (dx.^2 + dy.^2 + dz.^2) / len;
127 s = sqrt(2) * autoscale * sd;
128 else # special case of identical points with multiple vectors
145 hstate = get (h, "nextplot");
149 args = __add_datasource__ ("quiver3", hg,
150 {"x", "y", "z", "u", "v", "w"}, args{:});
152 args = __add_datasource__ ("quiver", hg,
153 {"x", "y", "z", "u", "v", "w"}, args{:});
157 addproperty ("xdata", hg, "data", x);
158 addproperty ("ydata", hg, "data", y);
160 addproperty ("udata", hg, "data", u);
161 addproperty ("vdata", hg, "data", v);
163 addproperty ("zdata", hg, "data", z);
164 addproperty ("wdata", hg, "data", w);
166 addproperty ("zdata", hg, "data", []);
167 addproperty ("wdata", hg, "data", []);
170 addlistener (hg, "xdata", @update_data);
171 addlistener (hg, "ydata", @update_data);
172 addlistener (hg, "zdata", @update_data);
173 addlistener (hg, "udata", @update_data);
174 addlistener (hg, "vdata", @update_data);
175 addlistener (hg, "wdata", @update_data);
188 h1 = plot3 ([x.'; xend.'; NaN(1, length (x))](:),
189 [y.'; yend.'; NaN(1, length (y))](:),
190 [z.'; zend.'; NaN(1, length (z))](:),
191 "linestyle", linespec.linestyle,
192 "color", linespec.color, "parent", hg);
194 h1 = plot ([x.'; xend.'; NaN(1, length (x))](:),
195 [y.'; yend.'; NaN(1, length (y))](:),
196 "linestyle", linespec.linestyle,
197 "color", linespec.color, "parent", hg);
201 h1 = plot3 ([x.'; xend.'; NaN(1, length (x))](:),
202 [y.'; yend.'; NaN(1, length (y))](:),
203 [z.'; zend.'; NaN(1, length (z))](:),
204 "color", "black", "parent", hg);
206 h1 = plot ([x.'; xend.'; NaN(1, length (x))](:),
207 [y.'; yend.'; NaN(1, length (y))](:),
212 xtmp = x + uu(:) .* (1 - arrowsize);
213 ytmp = y + vv(:) .* (1 - arrowsize);
214 xarrw1 = xtmp + (y - yend) * arrowsize / 3;
215 xarrw2 = xtmp - (y - yend) * arrowsize / 3;
216 yarrw1 = ytmp - (x - xend) * arrowsize / 3;
217 yarrw2 = ytmp + (x - xend) * arrowsize / 3;
219 zarrw1 = zarrw2 = zend - ww(:) * arrowsize;
223 if (isfield (linespec, "marker")
224 && ! strncmp (linespec.marker, "none", 4))
226 h2 = plot3 ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
227 [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
228 [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:),
229 "linestyle", "none", "parent", hg);
231 h2 = plot ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
232 [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
233 "linestyle", "none", "parent", hg);
237 h2 = plot3 ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
238 [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
239 [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:),
240 "linestyle", linespec.linestyle,
241 "color", linespec.color, "parent", hg);
243 h2 = plot ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
244 [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
245 "linestyle", linespec.linestyle,
246 "color", linespec.color, "parent", hg);
250 h2 = plot3 ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
251 [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
252 [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:),
253 "color", "black", "parent", hg);
255 h2 = plot ([xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:),
256 [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:),
261 || (isfield (linespec, "marker")
262 && strncmp (linespec.marker, "none", 4)))
264 h3 = plot3 (x, y, z, "linestyle", "none", "marker", "none",
267 h3 = plot (x, y, "linestyle", "none", "marker", "none", "parent", hg);
271 h3 = plot3 (x, y, z, "linestyle", "none", "marker", linespec.marker,
275 h3 = plot (x, y, "linestyle", "none", "marker", linespec.marker,
280 ## FIXME gnuplot doesn't respect the markerfacecolor field
281 set (h3, "markerfacecolor", get (h1, "color"));
284 ## Set up the hggroup properties and listeners
286 addproperty ("autoscale", hg, "radio", "{on}|off", "on");
287 addproperty ("autoscalefactor", hg, "data", autoscale);
289 addproperty ("autoscale", hg, "radio", "{on}|off", "off");
290 addproperty ("autoscalefactor", hg, "data", 1.0);
292 addlistener (hg, "autoscale", @update_data);
293 addlistener (hg, "autoscalefactor", @update_data);
295 addproperty ("maxheadsize", hg, "data", arrowsize);
296 addlistener (hg, "maxheadsize", @update_data);
298 addproperty ("showarrowhead", hg, "radio", "{on}|off", "on");
299 addlistener (hg, "showarrowhead", @update_props);
301 addproperty ("color", hg, "linecolor", get (h1, "color"));
302 addproperty ("linewidth", hg, "linelinewidth", get (h1, "linewidth"));
303 addproperty ("linestyle", hg, "linelinestyle", get (h1, "linestyle"));
304 addproperty ("marker", hg, "linemarker", get (h3, "marker"));
305 addproperty ("markerfacecolor", hg, "linemarkerfacecolor",
306 get (h3, "markerfacecolor"));
307 addproperty ("markersize", hg, "linemarkersize", get (h3, "markersize"));
309 addlistener (hg, "color", @update_props);
310 addlistener (hg, "linewidth", @update_props);
311 addlistener (hg, "linestyle", @update_props);
312 addlistener (hg, "marker", @update_props);
313 addlistener (hg, "markerfacecolor", @update_props);
314 addlistener (hg, "markersize", @update_props);
316 if (! isempty (args))
319 unwind_protect_cleanup
320 set (h, "nextplot", hstate);
325 function update_data (h, d)
326 x = get (h, "xdata");
327 y = get (h, "ydata");
328 z = get (h, "zdata");
330 u = get (h, "udata");
331 v = get (h, "vdata");
332 w = get (h, "wdata");
334 s = get (h, "autoscalefactor");
335 arrowsize = get (h, "maxheadsize");
337 kids = get (h, "children");
339 if (isempty (z) || isempty (w))
345 if (strcmpi (get (h, "autoscale"), "on") && s != 0)
346 ## Scale the arrows to fit in the grid
348 ny = nx = length (x);
352 dx = (max(x(:)) - min(x(:))) ./ nx;
353 dy = (max(y(:)) - min(y(:))) ./ ny;
355 dz = (max(z(:)) - min(z(:))) ./ max (size (z));
356 len = max (sqrt (u(:).^2 + v(:).^2 + w(:).^2));
359 len = max (sqrt (u(:).^2 + v(:).^2));
362 sd = sqrt (dx.^2 + dy.^2 + dz.^2) / len;
383 set (kids (3), "xdata", [x.'; xend.'; NaN(1, length (x))](:));
384 set (kids (3), "ydata", [y.'; yend.'; NaN(1, length (y))](:));
386 set (kids (3), "zdata", [z.'; zend.'; NaN(1, length (z))](:));
389 xtmp = x + u(:) .* (1 - arrowsize);
390 ytmp = y + v(:) .* (1 - arrowsize);
391 xarrw1 = xtmp + (y - yend) * arrowsize / 3;
392 xarrw2 = xtmp - (y - yend) * arrowsize / 3;
393 yarrw1 = ytmp - (x - xend) * arrowsize / 3;
394 yarrw2 = ytmp + (x - xend) * arrowsize / 3;
396 zarrw1 = zarrw2 = zend - w(:) * arrowsize;
399 set (kids (2), "xdata", [x.'; xend.'; NaN(1, length (x))](:));
400 set (kids (2), "ydata", [y.'; yend.'; NaN(1, length (y))](:));
402 set (kids (2), "zdata", [z.'; zend.'; NaN(1, length (z))](:));
405 set (kids (2), "xdata", [xarrw1.'; xend.'; xarrw2.'; NaN(1, length (x))](:));
406 set (kids (2), "ydata", [yarrw1.'; yend.'; yarrw2.'; NaN(1, length (y))](:));
408 set (kids (2), "zdata", [zarrw1.'; zend.'; zarrw2.'; NaN(1, length (z))](:));
411 set (kids (1), "xdata", x);
412 set (kids (1), "ydata", y);
414 set (kids (1), "zdata", z);
419 function update_props (h, d)
420 kids = get (h, "children");
422 set (kids(3), "color", get (h, "color"),
423 "linewidth", get (h, "linewidth"),
424 "linestyle", get (h, "linestyle"));
425 set (kids(2), "color", get (h, "color"),
426 "linewidth", get (h, "linewidth"),
427 "linestyle", get (h, "linestyle"));
428 if (strcmpi (get (h, "showarrowhead"), "on"))
429 set (kids (2), "visible", "on");
431 set (kids (2), "visible", "off");
433 set (kids(1), "color", get (h, "color"),
434 "marker", get (h, "marker"),
435 "markerfacecolor", get (h, "markerfacecolor"),
436 "markersize", get (h, "markersize"));