# HG changeset patch # User Colin Macdonald # Date 1468387948 25200 # Node ID 5ce4dfe5d90646852387654f7ac627405fe1b11a # Parent b188be2b962beb8e8d0b7079da37b1f6c76f3a3a Add basic camera set/get functions (patch #9046). * scripts/plot/appearance/campos.m, camtarget.m, camup.m, camva.m: New functions. * scripts/plot/appearance/module.mk: Add functions. * doc/interpreter/plot.txi: Add docstrings to manual. * scripts/help/__unimplemented__.m: Remove new functions from list. * scripts/plot/draw/camlight: Add cross references. diff -r b188be2b962b -r 5ce4dfe5d906 doc/interpreter/plot.txi --- a/doc/interpreter/plot.txi Tue Jul 12 23:33:36 2016 -0700 +++ b/doc/interpreter/plot.txi Tue Jul 12 22:32:28 2016 -0700 @@ -464,6 +464,14 @@ @DOCSTRING(view) +@DOCSTRING(campos) + +@DOCSTRING(camtarget) + +@DOCSTRING(camup) + +@DOCSTRING(camva) + @DOCSTRING(slice) @DOCSTRING(ribbon) diff -r b188be2b962b -r 5ce4dfe5d906 scripts/help/__unimplemented__.m --- a/scripts/help/__unimplemented__.m Tue Jul 12 23:33:36 2016 -0700 +++ b/scripts/help/__unimplemented__.m Tue Jul 12 22:32:28 2016 -0700 @@ -577,12 +577,8 @@ "camlookat", "camorbit", "campan", - "campos", "camproj", "camroll", - "camtarget", - "camup", - "camva", "camzoom", "categorical", "categories", diff -r b188be2b962b -r 5ce4dfe5d906 scripts/plot/appearance/campos.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/plot/appearance/campos.m Tue Jul 12 22:32:28 2016 -0700 @@ -0,0 +1,178 @@ +## 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 . + +## -*- texinfo -*- +## @deftypefn {} {@var{P} =} campos () +## @deftypefnx {} {} campos ([@var{x} @var{y} @var{z}]) +## @deftypefnx {} {@var{mode} =} campos ("mode") +## @deftypefnx {} {} campos (@var{mode}) +## @deftypefnx {} {} campos (@var{ax}, @dots{}) +## Set or get the camera position. +## +## The default camera position is determined automatically based on the scene. +## For example, to get the camera position: +## @example +## @group +## hf = figure(); +## peaks() +## p = campos () +## @result{} p = +## -27.394 -35.701 64.079 +## @end group +## @end example +## +## We can then move the camera further up the z-axis: +## @example +## @group +## campos (p + [0 0 10]) +## campos () +## @result{} ans = +## -27.394 -35.701 74.079 +## @end group +## @end example +## +## Having made that change, the camera position @var{mode} is now manual: +## @example +## @group +## campos ("mode") +## @result{} manual +## @end group +## @end example +## +## We can set it back to automatic: +## @example +## @group +## campos ("auto") +## campos () +## @result{} ans = +## -27.394 -35.701 64.079 +## 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{camup, camtarget, camva} +## @end deftypefn + + +function p = campos (varargin) + + [hax, varargin, nargin] = __plt_get_axis_arg__ ("campos", varargin{:}); + + if (nargin > 1) + print_usage (); + endif + + if (isempty (hax)) + hax = gca (); + else + hax = hax(1); + endif + + prop = "cameraposition"; + if (nargin == 0) + p = get (hax, prop); + elseif (nargin == 1 && isnumeric (varargin{1}) && numel (varargin{1}) == 3) + set (hax, prop, varargin{1}); + elseif (nargin == 1 && ischar (varargin{1})) + s = varargin{1}; + if (strcmp (s, "mode")) + p = get (hax, [prop "mode"]); + else + set (hax, [prop "mode"], s); + endif + else + print_usage (); + endif + +endfunction + + +%!demo +%! sphere (); +%! ## where is camera located? +%! x1 = campos () +%! ## move the camera upwards +%! campos (x1 + [0 0 2]) +%! x2 = campos () + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! hax = axes ("parent", hf); +%! sphere (hax); +%! x = campos (); +%! campos ([1 2 3]); +%! y = campos (); +%! assert (y, [1 2 3]); +%! campos (x); +%! x2 = campos (); +%! assert (x, x2); +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! sphere(); +%! p_orig = campos (); +%! m = campos ("mode"); +%! assert (strcmp (m, "auto")); +%! +%! campos ([1 2 3]); +%! m = campos ("mode"); +%! assert (strcmp (m, "manual")); +%! +%! campos ("auto"); +%! p = campos (); +%! assert (p, p_orig); +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect + +## test ax input by creating another axis +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! subplot (1, 2, 1); sphere (); hax1 = gca (); +%! subplot (1, 2, 2); peaks (); hax2 = gca (); +%! campos (hax1, [20 0 0]); +%! subplot (1, 2, 1); +%! x = campos (); +%! z = campos (hax2); +%! subplot (1, 2, 2); +%! y = campos (); +%! assert (x, [20 0 0]); +%! assert (norm (y - [20 0 0]) > 1); +%! assert (y, z); +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect + +## Test input validation +%!error campos (1, 2) +%!error +%! hf = figure ("visible", "off"); +%! unwind_protect +%! campos ("mod"); +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect diff -r b188be2b962b -r 5ce4dfe5d906 scripts/plot/appearance/camtarget.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/plot/appearance/camtarget.m Tue Jul 12 22:32:28 2016 -0700 @@ -0,0 +1,187 @@ +## 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 . + +## -*- texinfo -*- +## @deftypefn {} {@var{T} =} camtarget () +## @deftypefnx {} {} camtarget ([@var{x} @var{y} @var{z}]) +## @deftypefnx {} {@var{mode} =} camtarget ("mode") +## @deftypefnx {} {} camtarget (@var{mode}) +## @deftypefnx {} {} camtarget (@var{ax}, @dots{}) +## Set or get where the camera is pointed. +## +## The camera target is a point in space where the camera is pointing. Usually, +## it is determined automatically based on the scene: +## @example +## @group +## hf = figure(); +## sphere (36) +## v = camtarget () +## @result{} v = +## 0 0 0 +## @end group +## @end example +## +## We can turn the camera to point at a new target: +## @example +## @group +## camtarget ([1 1 1]) +## camtarget () +## @result{} 1 1 1 +## @end group +## @end example +## +## Having done so, the camera target @var{mode} is manual: +## @example +## @group +## camtarget ("mode") +## @result{} manual +## @end group +## @end example +## This means, for example, adding new objects to the scene will not retarget +## the camera: +## @example +## @group +## hold on; +## peaks () +## camtarget () +## @result{} 1 1 1 +## @end group +## @end example +## +## We can reset it to be automatic: +## @example +## @group +## @c doctest: +XFAIL +## @c https://savannah.gnu.org/bugs/?44503 +## camtarget ("auto") +## camtarget () +## @result{} 0 0 0.76426 +## 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{campos, camup, camva} +## @end deftypefn + + +function p = camtarget (varargin) + + [hax, varargin, nargin] = __plt_get_axis_arg__ ("camtarget", varargin{:}); + + if (nargin > 1) + print_usage (); + endif + + if (isempty (hax)) + hax = gca (); + else + hax = hax(1); + endif + + prop = "cameratarget"; + if (nargin == 0) + p = get (hax, prop); + elseif (nargin == 1 && isnumeric (varargin{1}) && numel (varargin{1}) == 3) + set (hax, prop, varargin{1}); + elseif (nargin == 1 && ischar (varargin{1})) + s = varargin{1}; + if (strcmp (s, "mode")) + p = get (hax, [prop "mode"]); + else + set (hax, [prop "mode"], s); + endif + else + print_usage (); + endif + +endfunction + + +%!demo +%! sphere (); +%! ## where is camera pointing? +%! x1 = camtarget () +%! ## point the camera upwards +%! camtarget (x1 + [0 0 1]) +%! x2 = camtarget () + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! sphere (); +%! x = camtarget (); +%! camtarget ([1 2 3]); +%! y = camtarget (); +%! assert (y, [1 2 3]); +%! camtarget (x); +%! x2 = camtarget (); +%! assert (x, x2); +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! sphere (); +%! x_orig = camtarget (); +%! m = camtarget ("mode"); +%! assert (strcmp (m, "auto")); +%! +%! camtarget ([1 2 3]); +%! m = camtarget ("mode"); +%! assert (strcmp (m, "manual")); +%! +%! camtarget ("auto"); +%! x = camtarget (); +%! assert (x, x_orig); +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect + +## test ax input by creating another axis +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! subplot (1, 2, 1); sphere (); hax1 = gca (); +%! subplot (1, 2, 2); peaks (); hax2 = gca (); +%! camtarget (hax1, [0.1 0.2 0.3]); +%! subplot (1, 2, 1); +%! x = camtarget (); +%! z = camtarget (hax2); +%! subplot (1, 2, 2); +%! y = camtarget (); +%! assert (x, [0.1 0.2 0.3]); +%! assert (norm (y - [0.1 0.2 0.3]) > 0.1); +%! assert (y, z); +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect + +## Test input validation +%!error camtarget (1, 2) +%!error +%! hf = figure ("visible", "off"); +%! unwind_protect +%! camtarget ("mod") +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect diff -r b188be2b962b -r 5ce4dfe5d906 scripts/plot/appearance/camup.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/plot/appearance/camup.m Tue Jul 12 22:32:28 2016 -0700 @@ -0,0 +1,180 @@ +## 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 . + +## -*- texinfo -*- +## @deftypefn {} {@var{up} =} camup () +## @deftypefnx {} {} camup ([@var{x} @var{y} @var{z}]) +## @deftypefnx {} {@var{mode} =} camup ("mode") +## @deftypefnx {} {} camup (@var{mode}) +## @deftypefnx {} {} camup (@var{ax}, @dots{}) +## Set or get the camera up vector. +## +## By default, the camera is oriented so that ``up'' corresponds to the positive +## z-axis: +## @example +## @group +## hf = figure (); +## sphere (36) +## v = camup () +## @result{} v = +## 0 0 1 +## @end group +## @end example +## +## Specifying a new ``up vector'' rolls the camera and sets the mode to manual: +## @example +## @group +## camup ([1 1 0]) +## camup () +## @result{} 1 1 0 +## camup ("mode") +## @result{} manual +## @end group +## @end example +## +## Modifying the up vector does not modify the camera target +## (@pxref{XREFcamtarget,,camtarget}). Thus, the camera up vector might not be +## orthogonal to the direction of the camera's view: +## @example +## camup ([1 2 3]) +## dot (camup (), camtarget () - campos ()) +## @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). +## +## Finally, we can reset the up vector to automatic mode: +## @example +## @group +## camup ("auto") +## camup () +## @result{} 0 0 1 +## 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{campos, camtarget, camva} +## @end deftypefn + + +function p = camup (varargin) + + [hax, varargin, nargin] = __plt_get_axis_arg__ ("camup", varargin{:}); + + if (nargin > 1) + print_usage (); + endif + + if (isempty (hax)) + hax = gca (); + else + hax = hax(1); + endif + + prop = "cameraupvector"; + if (nargin == 0) + p = get (hax, prop); + elseif (nargin == 1 && isnumeric (varargin{1}) && numel (varargin{1}) == 3) + set (hax, prop, varargin{1}); + elseif (nargin == 1 && ischar (varargin{1})) + s = varargin{1}; + if (strcmp (s, "mode")) + p = get (hax, [prop "mode"]); + else + set (hax, [prop "mode"], s); + endif + else + print_usage (); + endif + +endfunction + + +%!demo +%! sphere () +%! ## what direction is "up" for the camera? +%! x1 = camup () +%! ## re-orient the camera with a new up-vector +%! camup ([1 0 0]) +%! x2 = camup () + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! sphere (); +%! x = camup (); +%! camup ([1 2 3]); +%! y = camup (); +%! assert (y, [1 2 3]); +%! camup (x); +%! x2 = camup (); +%! assert (x, x2); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! sphere (); +%! p_orig = camup (); +%! m = camup ("mode"); +%! assert (strcmp (m, "auto")); +%! +%! camup ([1 2 3]); +%! m = camup ("mode"); +%! assert (strcmp (m, "manual")); +%! +%! camup ("auto"); +%! p = camup (); +%! assert (p, p_orig); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + +## test ax input by creating another axis +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! subplot (1, 2, 1); sphere (); hax1 = gca (); +%! subplot (1, 2, 2); peaks (); hax2 = gca (); +%! camup (hax1, [1 0 0]); +%! subplot (1, 2, 1); +%! x = camup (); +%! z = camup (hax2); +%! subplot (1, 2, 2); +%! y = camup (); +%! assert (x, [1 0 0]); +%! assert (norm (y - [1 0 0]) > 0.1); +%! assert (y, z); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + +## Test input validation +%!error camup (1, 2) +%!error +%! hf = figure ("visible", "off"); +%! unwind_protect +%! camup ("mod") +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect diff -r b188be2b962b -r 5ce4dfe5d906 scripts/plot/appearance/camva.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/plot/appearance/camva.m Tue Jul 12 22:32:28 2016 -0700 @@ -0,0 +1,169 @@ +## 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 . + +## -*- texinfo -*- +## @deftypefn {} {@var{a} =} camva () +## @deftypefnx {} {} camva (@var{a}) +## @deftypefnx {} {@var{mode} =} camva ("mode") +## @deftypefnx {} {} camva (@var{mode}) +## @deftypefnx {} {} camva (@var{ax}, @dots{}) +## Set or get the camera viewing angle. +## +## The camera has a viewing angle which determines how much can be seen. By +## default this is: +## @example +## @group +## hf = figure(); +## sphere (36) +## a = camva () +## @result{} a = 10.340 +## @end group +## @end example +## +## To get a wider-angle view, we could double the viewing angle. This will also +## set the mode to manual: +## @example +## @group +## camva (2*a) +## camva ("mode") +## @result{} manual +## @end group +## @end example +## +## We can set it back to automatic: +## @example +## @group +## camva ("auto") +## camva ("mode") +## @result{} auto +## camva () +## @result{} ans = 10.340 +## 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{campos, camtarget, camup} +## @end deftypefn + + +function p = camva (varargin) + + [hax, varargin, nargin] = __plt_get_axis_arg__ ("camva", varargin{:}); + + if (nargin > 1) + print_usage (); + endif + + if (isempty (hax)) + hax = gca (); + else + hax = hax(1); + endif + + prop = "cameraviewangle"; + if (nargin == 0) + p = get (hax, prop); + elseif (nargin == 1 && isnumeric (varargin{1}) && isscalar (varargin{1})) + set (hax, prop, varargin{1}); + elseif (nargin == 1 && ischar (varargin{1})) + s = varargin{1}; + if (strcmp (s, "mode")) + p = get (hax, [prop "mode"]); + else + set (hax, [prop "mode"], s); + endif + else + print_usage (); + endif + +endfunction + + +%!demo +%! peaks (); +%! ## query the viewing angle +%! a1 = camva () +%! ## get a close-up view by decreasing the viewing angle: +%! camva (0.5*a1) +%! a2 = camva () + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! sphere (); +%! x = camva (); +%! camva (5); +%! y = camva (); +%! assert (y, 5); +%! camva (x); +%! x2 = camva (); +%! assert (x, x2); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! sphere(); +%! a_orig = camva (); +%! m = camva ("mode"); +%! assert (strcmp (m, "auto")); +%! +%! camva (15); +%! m = camva ("mode"); +%! assert (strcmp (m, "manual")); +%! +%! camva ("auto"); +%! a = camva (); +%! assert (a, a_orig); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + +## test ax input by creating another axis +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! subplot (1, 2, 1); sphere (); hax1 = gca (); +%! subplot (1, 2, 2); sphere (); hax2 = gca (); +%! camva (hax1, 5); +%! subplot (1, 2, 1); +%! x = camva (); +%! z = camva (hax2); +%! subplot (1, 2, 2); +%! y = camva (); +%! assert (x, 5); +%! assert (abs (z - 5) > 1); +%! assert (y, z); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + +## Test input validation +%!error camva (1, 2) +%!error +%! hf = figure ("visible", "off"); +%! unwind_protect +%! camva ("mod") +%! unwind_protect_cleanup +%! delete (hf); +%! end_unwind_protect diff -r b188be2b962b -r 5ce4dfe5d906 scripts/plot/appearance/module.mk --- a/scripts/plot/appearance/module.mk Tue Jul 12 23:33:36 2016 -0700 +++ b/scripts/plot/appearance/module.mk Tue Jul 12 22:32:28 2016 -0700 @@ -12,6 +12,10 @@ %reldir%/annotation.m \ %reldir%/axis.m \ %reldir%/box.m \ + %reldir%/campos.m \ + %reldir%/camtarget.m \ + %reldir%/camup.m \ + %reldir%/camva.m \ %reldir%/caxis.m \ %reldir%/clabel.m \ %reldir%/daspect.m \ diff -r b188be2b962b -r 5ce4dfe5d906 scripts/plot/draw/camlight.m --- a/scripts/plot/draw/camlight.m Tue Jul 12 23:33:36 2016 -0700 +++ b/scripts/plot/draw/camlight.m Tue Jul 12 22:32:28 2016 -0700 @@ -69,9 +69,10 @@ ## @end group ## @end example ## -## Here the light is first pitched upwards from the camera position by 30 -## degrees. It is then yawed by 45 degrees to the right. Both rotations are -## centered around the camera target. +## Here the light is first pitched upwards (@pxref{XREFcamup,,camup}) from the +## camera position (@pxref{XREFcampos,,campos}) by 30 degrees. It is then yawed +## by 45 degrees to the right. Both rotations are centered around the camera +## target (@pxref{XREFcamtarget,,camtarget}). ## ## Return a handle to further manipulate the light object ##