changeset 24129:f80dc6db9d18

Add camzoom and camroll functions (patch #9049). * scripts/plot/appearance/camroll.m, camzoom.m: New functions. * scripts/plot/appearance/module.mk: Add new files. * doc/interpreter/plot.txi: Add docstrings to manual. * scripts/help/__unimplemented__.m: Remove new functions from list. * scripts/plot/appearance/camup.m: Docs now suggest camroll. * scripts/plot/appearance/__rotate_around_axis__.m: Move file from draw/private. * scripts/plot/draw/module.mk: Remove moved file.
author Colin Macdonald <cbm@m.fsf.org>
date Tue, 12 Jul 2016 22:19:54 -0700
parents 5ce4dfe5d906
children 6fdbdb66d7cb
files doc/interpreter/plot.txi scripts/help/__unimplemented__.m scripts/plot/appearance/__rotate_around_axis__.m scripts/plot/appearance/camroll.m scripts/plot/appearance/camup.m scripts/plot/appearance/camzoom.m scripts/plot/appearance/module.mk scripts/plot/draw/module.mk scripts/plot/draw/private/__rotate_around_axis__.m
diffstat 9 files changed, 372 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/doc/interpreter/plot.txi	Tue Jul 12 22:32:28 2016 -0700
+++ b/doc/interpreter/plot.txi	Tue Jul 12 22:19:54 2016 -0700
@@ -466,12 +466,16 @@
 
 @DOCSTRING(campos)
 
+@DOCSTRING(camroll)
+
 @DOCSTRING(camtarget)
 
 @DOCSTRING(camup)
 
 @DOCSTRING(camva)
 
+@DOCSTRING(camzoom)
+
 @DOCSTRING(slice)
 
 @DOCSTRING(ribbon)
--- a/scripts/help/__unimplemented__.m	Tue Jul 12 22:32:28 2016 -0700
+++ b/scripts/help/__unimplemented__.m	Tue Jul 12 22:19:54 2016 -0700
@@ -578,8 +578,6 @@
   "camorbit",
   "campan",
   "camproj",
-  "camroll",
-  "camzoom",
   "categorical",
   "categories",
   "cdf2rdf",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/__rotate_around_axis__.m	Tue Jul 12 22:19:54 2016 -0700
@@ -0,0 +1,58 @@
+## Copyright (C) 2014-2017 John W. Eaton
+## Copyright (C) 2016 Colin B. Macdonald
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {} {[@var{xr}, @var{yr}, @var{zr}] =} __rotate_around_axis__ (@var{x}, @var{y}, @var{z}, @var{angle}, @var{dir}, @var{origin})
+## Rotate the points given by X, Y, Z about an axis by ANGLE degrees.
+## The axis is specified by the vector DIR and the point ORIGIN.
+## @end deftypefn
+
+function [xr, yr, zr] = __rotate_around_axis__ (x, y, z, angle, dir, origin)
+
+  dir /= norm (dir);
+  u = dir(1);
+  v = dir(2);
+  w = dir(3);
+
+  a = origin(1);
+  b = origin(2);
+  c = origin(3);
+
+  sa = sind (angle);
+  ca = cosd (angle);
+
+  if (a == 0 && b == 0 && c == 0)
+    tmp = (u*x + v*y + w*z) * (1 - ca);
+
+    xr = u*tmp + x*ca + (-w*y + v*z)*sa;
+    yr = v*tmp + y*ca + (w*x - u*z)*sa;
+    zr = w*tmp + z*ca + (-v*x + u*y)*sa;
+  else
+    one_m_ca = 1 - ca;
+    tmp = u*x + v*y + w*z;
+
+    xr = ((a*(v**2 + w**2) - u*(b*v + c*w - tmp))*one_m_ca
+          + x*ca + (-c*v + b*w - w*y + v*z)*sa);
+    yr = ((b*(u**2 + w**2) - v*(a*u + c*w - tmp))*one_m_ca
+          + y*ca + (c*u - a*w + w*x - u*z)*sa);
+    zr = ((c*(u**2 + v**2) - w*(a*u + b*v - tmp))*one_m_ca
+          + z*ca + (-b*u + a*v - v*x + u*y)*sa);
+  endif
+
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/camroll.m	Tue Jul 12 22:19:54 2016 -0700
@@ -0,0 +1,152 @@
+## Copyright (C) 2016 Colin B. Macdonald
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty
+## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public
+## License along with this software; see the file COPYING.
+## If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} camroll (@var{theta})
+## @deftypefnx {} {} camroll (@var{ax}, @var{theta})
+## Roll the camera.
+##
+## Roll the camera clockwise by @var{theta} degrees.
+## For example, the following command will roll the camera by
+## 30 degrees clockwise (to the right); this will cause the scene
+## to appear to roll by 30 degrees to the left:
+## @example
+## @group
+## @c doctest: +SKIP
+## peaks ()
+## camroll (30)
+## @end group
+## @end example
+##
+## Roll the camera back:
+## @example
+## @group
+## @c doctest: +SKIP
+## camroll (-30)
+## @end group
+## @end example
+##
+## The following command restores the default camera roll:
+## @example
+## @group
+## @c doctest: +SKIP
+## camup ("auto")
+## @end group
+## @end example
+##
+## By default, these commands affect the current axis; alternatively, an axis
+## can be specified by the optional argument @var{ax}.
+##
+## @seealso{camzoom, camup}
+## @end deftypefn
+
+
+function camroll (varargin)
+
+  [hax, varargin, nargin] = __plt_get_axis_arg__ ("camroll", varargin{:});
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  a = varargin{1};
+
+  if (! (isnumeric (a) && isscalar (a) ))
+    print_usage ();
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  else
+    hax = hax(1);
+  endif
+
+  view_ax = camtarget (hax) - campos (hax);
+  view_ax /= norm (view_ax);
+  ## orthogonalize the camup vector
+  up = camup (hax) - view_ax*dot (camup (hax), view_ax);
+  up /= norm (up);
+
+  ## rotate the modified camup vector around the view axis
+  up = num2cell (up);
+  [up{:}] = __rotate_around_axis__ (up{:}, a, view_ax, [0 0 0]);
+  up = [up{:}];
+  camup (hax, up)
+
+endfunction
+
+
+%!demo
+%! peaks ()
+%! camroll (30)
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   sphere (10);
+%!   campos ([10 0 0]);
+%!   camroll (30);
+%!   p = camup ();
+%!   assert (p, [0 1/2 sqrt(3)/2], eps);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## test rolling, then rolling back
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   peaks ();
+%!   p = camup ();
+%!   assert (p, [0 0 1], eps);
+%!   camroll (30);
+%!   p = camup ();
+%!   ## from Matlab R2014a
+%!   q = [0.826398839602911  0.255644120004753  0.50170812412194];
+%!   assert (p, q, 10*eps);
+%!   camroll (-30);
+%!   ## note it does not go back to [0 0 1]: instead orthog to camera view:
+%!   p = camup ();
+%!   assert (dot (p, camtarget () - campos ()), 0, eps);
+%!   q = [0.496200420425837  0.646660977913424  0.57932264103285];
+%!   assert (p, q, 10*eps);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## test ax input by creating another axis
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   hax1 = subplot (1, 2, 1);
+%!   sphere (hax1);
+%!   hax2 = subplot (1, 2, 2);
+%!   sphere (hax2);
+%!   camroll (hax1, 30);
+%!   x = camup (hax1);
+%!   y = camup (hax2);
+%!   assert (x, [0.660278 0.039151 0.750000], -1e-5)
+%!   assert (y, [0 0 1])
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <Invalid call> camroll (1, 2, 3)
+%!error <Invalid call> camroll ("mod")
+%!error <Invalid call> camroll (1, [1 2])
--- a/scripts/plot/appearance/camup.m	Tue Jul 12 22:32:28 2016 -0700
+++ b/scripts/plot/appearance/camup.m	Tue Jul 12 22:19:54 2016 -0700
@@ -56,7 +56,9 @@
 ##   @result{} 6...
 ## @end example
 ## A consequence is that ``pulling back'' on the up vector does not pitch the
-## camera view (as that would require changing the target).
+## camera view (as that would require changing the target).  Setting the up
+## vector is thus typically used only to roll the camera.  A more intuitive
+## command for this purpose is @pxref{XREFcamroll,,camroll}.
 ##
 ## Finally, we can reset the up vector to automatic mode:
 ## @example
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/camzoom.m	Tue Jul 12 22:19:54 2016 -0700
@@ -0,0 +1,152 @@
+## Copyright (C) 2016 Colin B. Macdonald
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty
+## of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public
+## License along with this software; see the file COPYING.
+## If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} camzoom (@var{zf})
+## @deftypefnx {} {} camzoom (@var{ax}, @var{zf})
+## Zoom the camera in or out.
+##
+## A value of @var{zf} larger than 1 ``zooms in'' such that the scene appears
+## magnified:
+## @example
+## @group
+## hf = figure ();
+## sphere (36)
+## camzoom (1.2)
+## @end group
+## @end example
+##
+## A value smaller than 1 ``zooms out'' so the camera can see more of the scene:
+## @example
+## @group
+## camzoom (0.5)
+## @end group
+## @end example
+##
+## Technically speaking, zooming affects the ``viewing angle''.  The following
+## command resets to the default zoom:
+## @example
+## @group
+## camva ("auto")
+## close (hf)
+## @end group
+## @end example
+##
+## By default, these commands affect the current axis; alternatively, an axis
+## can be specified by the optional argument @var{ax}.
+##
+## @seealso{camroll, camva}
+## @end deftypefn
+
+
+function camzoom (varargin)
+
+  [hax, varargin, nargin] = __plt_get_axis_arg__ ("camva", varargin{:});
+
+  if (nargin != 1)
+    print_usage ();
+  endif
+
+  zf = varargin{1};
+
+  if (! (isnumeric (zf) && isscalar (zf) ))
+    print_usage ();
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  else
+    hax = hax(1);
+  endif
+
+  va = 2 * atand (tand (camva (hax)/2) / zf);
+  camva (hax, va);
+
+endfunction
+
+
+%!demo
+%! peaks ();
+%! camzoom (2);
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   sphere ();
+%!   x = camva ();
+%!   camzoom (5);
+%!   assert (tand (x/2) / tand (camva ()/2), 5);
+%!   camzoom (1/5);
+%!   y = camva ();
+%!   assert (x, y, eps);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   sphere();
+%!   x = camva ();
+%!   camzoom (2);
+%!   y = camva ();
+%!   ## Matlab 2014a
+%!   xm = 10.339584907202;
+%!   ym = 5.18033628450948;
+%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14)
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   peaks ();
+%!   campos ([20, 30, 50]);
+%!   camtarget ([0 0 1]);
+%!   x = camva ();
+%!   camzoom (5);
+%!   y = camva ();
+%!   ## Matlab 2014a
+%!   xm = 13.0746680295069;
+%!   ym = 2.62588066987212;
+%!   assert (tand (x/2) / tand (y/2), tand (xm/2) / tand (ym/2), 2e-14)
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## test ax input by creating another axis
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   hax1 = subplot (1, 2, 1);
+%!   sphere (hax1);
+%!   hax2 = subplot (1, 2, 2);
+%!   sphere (hax2);
+%!   camzoom (hax1, 2)
+%!   x = camva (hax1);
+%!   y = camva (hax2);
+%!   assert (tand (y/2) / tand (x/2), 2)
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <Invalid call> camzoom (1, 2, 3)
+%!error <Invalid call> camzoom (1, [2, 3])
+%!error <Invalid call> camzoom ("string")
--- a/scripts/plot/appearance/module.mk	Tue Jul 12 22:32:28 2016 -0700
+++ b/scripts/plot/appearance/module.mk	Tue Jul 12 22:19:54 2016 -0700
@@ -9,13 +9,16 @@
 %canon_reldir%_FCN_FILES = \
   %reldir%/__clabel__.m \
   %reldir%/__getlegenddata__.m \
+  %reldir%/__rotate_around_axis__.m \
   %reldir%/annotation.m \
   %reldir%/axis.m \
   %reldir%/box.m \
   %reldir%/campos.m \
+  %reldir%/camroll.m \
   %reldir%/camtarget.m \
   %reldir%/camup.m \
   %reldir%/camva.m \
+  %reldir%/camzoom.m \
   %reldir%/caxis.m \
   %reldir%/clabel.m \
   %reldir%/daspect.m \
--- a/scripts/plot/draw/module.mk	Tue Jul 12 22:32:28 2016 -0700
+++ b/scripts/plot/draw/module.mk	Tue Jul 12 22:19:54 2016 -0700
@@ -16,7 +16,6 @@
   %reldir%/private/__pie__.m \
   %reldir%/private/__plt__.m \
   %reldir%/private/__quiver__.m \
-  %reldir%/private/__rotate_around_axis__.m \
   %reldir%/private/__scatter__.m \
   %reldir%/private/__stem__.m \
   %reldir%/private/__unite_shared_vertices__.m
--- a/scripts/plot/draw/private/__rotate_around_axis__.m	Tue Jul 12 22:32:28 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-## Copyright (C) 2014-2017 John W. Eaton
-## Copyright (C) 2016 Colin B. Macdonald
-##
-## This file is part of Octave.
-##
-## Octave is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or
-## (at your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn {} {[@var{xr}, @var{yr}, @var{zr}] =} __rotate_around_axis__ (@var{x}, @var{y}, @var{z}, @var{angle}, @var{dir}, @var{origin})
-## Rotate the points given by X, Y, Z about an axis by ANGLE degrees.
-## The axis is specified by the vector DIR and the point ORIGIN.
-## @end deftypefn
-
-function [xr, yr, zr] = __rotate_around_axis__ (x, y, z, angle, dir, origin)
-
-  dir /= norm (dir);
-  u = dir(1);
-  v = dir(2);
-  w = dir(3);
-
-  a = origin(1);
-  b = origin(2);
-  c = origin(3);
-
-  sa = sind (angle);
-  ca = cosd (angle);
-
-  if (a == 0 && b == 0 && c == 0)
-    tmp = (u*x + v*y + w*z) * (1 - ca);
-
-    xr = u*tmp + x*ca + (-w*y + v*z)*sa;
-    yr = v*tmp + y*ca + (w*x - u*z)*sa;
-    zr = w*tmp + z*ca + (-v*x + u*y)*sa;
-  else
-    one_m_ca = 1 - ca;
-    tmp = u*x + v*y + w*z;
-
-    xr = ((a*(v**2 + w**2) - u*(b*v + c*w - tmp))*one_m_ca
-          + x*ca + (-c*v + b*w - w*y + v*z)*sa);
-    yr = ((b*(u**2 + w**2) - v*(a*u + c*w - tmp))*one_m_ca
-          + y*ca + (c*u - a*w + w*x - u*z)*sa);
-    zr = ((c*(u**2 + v**2) - w*(a*u + b*v - tmp))*one_m_ca
-          + z*ca + (-b*u + a*v - v*x + u*y)*sa);
-  endif
-
-endfunction