# HG changeset patch
# User Colin Macdonald <cbm@m.fsf.org>
# Date 1464818133 25200
#      Wed Jun 01 14:55:33 2016 -0700
# Node ID 5f321ecd0d7b824d1ce3133feaf2863ae146b684
# Parent  065aabcba59e282d48817e6a709c069ce62f4490
Camlight can modify existing lights with handle

* camlight.m: support camlight(h)

diff -r 065aabcba59e -r 5f321ecd0d7b scripts/plot/draw/camlight.m
--- a/scripts/plot/draw/camlight.m	Wed Jun 01 10:59:29 2016 -0700
+++ b/scripts/plot/draw/camlight.m	Wed Jun 01 14:55:33 2016 -0700
@@ -24,12 +24,13 @@
 %% @deftypefnx {} {} camlight headlight
 %% @deftypefnx {} {} camlight (@var{az}, @var{el})
 %% @deftypefnx {} {@var{h} =} camlight (@dots{})
+%% @deftypefnx {} {} camlight (@var{h}, @dots{})
 %% Add lights to a figure using a simple interface.
 %%
 %% Example:
 %% @example
+%% @group
 %% @c doctest: +SKIP
-%% @group
 %% sphere (36)
 %% camlight
 %% @end group
@@ -48,21 +49,47 @@
 %% then yawed by @var{az}.  Both rotations are centered around the
 %% camera target (@pxref{camtarget}).
 %%
+%% A handle to the light can optionally be returned.  It can be
+%% used to further manipulate the light.  For example, we can create
+%% a light on the left and then move it to the right:
+%% @example
+%% @group
+%% @c doctest: +SKIP
+%% clf
+%% sphere (36)
+%% h = camlight ('left')
+%% drawnow ()
+%% camlight (h, 'right')
+%% drawnow ()
+%% set (h, 'color', 'r')
+%% @end group
+%% @end example
 %%
-%% TODO: style kwarg.
-%%
-%% @seealso{lighting, light, material}
+%% @seealso{light, material}
 %% @end deftypefn
 
 
-function varargout = camlight(az, el)
+function h = camlight (varargin)
 
-  if (nargin == 0)
+  if ( (nargin == 0) || (! ishandle (varargin{1})) )
+    hin = [];  % no handle
+    z = 0;     % first input
+  else
+    hin = varargin{1};
+    z = 1;
+  end
+
+  if (nargin == z)
     s = 'right';
-  elseif ((nargin == 1) && (ischar (az)))
-    s = az;
-  elseif (nargin == 2)
+  elseif (nargin == z + 1)
+    s = varargin{z + 1};
+    if (! ischar (s))
+      print_usage ();
+    end
+  elseif (nargin == z + 2)
     s = '_skip';
+    az = varargin{z + 1};
+    el = varargin{z + 2};
   else
     print_usage ();
   end
@@ -97,10 +124,15 @@
   A = rotateAxis(cam_pos, el, pitch_ax, cam_target);
   light_pos = rotateAxis(A, az, yaw_ax, cam_target);
 
-  h = light ('Position', light_pos);
+  if (isempty (hin))
+    htmp = light ('Position', light_pos);
+  else
+    set (hin, 'Position', light_pos);
+    htmp = hin;
+  end
 
-  if (nargout == 1)
-    varargout = {h};
+  if (nargout > 0)
+    h = htmp;
   end
 end
 
@@ -126,10 +158,23 @@
 %!   drawnow ()
 %! end
 
+%!demo
+%! sphere (48)
+%! title ('Move the camera and update the light position');
+%! axis equal; shading flat
+%! view (30, 30)
+%!
+%! h = camlight ();          % keep a handle to the light
+%!
+%! for a = 30:2:390
+%!   view (a, 30)
+%!   camlight (h, 'right')   % update light position
+%!   drawnow ()
+%! end
+
 
 %!error <Invalid> camlight ('wtf')
 %!error <Invalid> camlight (42)
-%!error <Invalid> camlight (1, 2, 3)
 
 %!shared hf
 %! hf = figure ('visible', 'off');
@@ -148,6 +193,29 @@
 %! A = get (h, 'position');
 %! B = [-11.054849015640563 2.931330143100648 -11.315623892092518];
 %! assert (A, B, -20*eps)
+
+%!test
+%! % move a light
+%! h = camlight ('left');
+%! h2 = camlight ();
+%! p2 = get(h2, 'position');
+%! camlight(h, 'right')
+%! p = get(h, 'position');
+%! assert (p, p2)
+%! camlight(h)
+%! p = get(h, 'position');
+%! assert (p, p2)
+
+%!test
+%! % Should be a new light at az == h + 10, el == 20
+%! h = camlight();
+%! camlight(double(h) + 10, 20)
+
+%!xtest
+%! % Should be a new light at az == h, el == 20
+%! h = camlight();
+%! camlight(double(h), 20)
+
 %!test
 %! close (hf);
 
# HG changeset patch
# User Colin Macdonald <cbm@m.fsf.org>
# Date 1464889114 25200
#      Thu Jun 02 10:38:34 2016 -0700
# Node ID ee2c31f894fc7dbbc440c6c117cd929a72b4be3a
# Parent  5f321ecd0d7b824d1ce3133feaf2863ae146b684
Support style in camlight, other fixes

Now supports style argument (can be "local", "infinite").  Redo processing
of inputs: handles are also doubles so previous had annoyingly rare bugs.
This fixes an xtest.  Add new tests, especially ones for invalid inputs.
Reword some documentation.  Finally, Matlab uses 30 az for left and right,
so update to match.

* camlight.m: support style, fixes, redo, input verifying

diff -r 5f321ecd0d7b -r ee2c31f894fc scripts/plot/draw/camlight.m
--- a/scripts/plot/draw/camlight.m	Wed Jun 01 14:55:33 2016 -0700
+++ b/scripts/plot/draw/camlight.m	Thu Jun 02 10:38:34 2016 -0700
@@ -23,6 +23,7 @@
 %% @deftypefnx {} {} camlight left
 %% @deftypefnx {} {} camlight headlight
 %% @deftypefnx {} {} camlight (@var{az}, @var{el})
+%% @deftypefnx {} {} camlight (@dots{}, @var{style})
 %% @deftypefnx {} {@var{h} =} camlight (@dots{})
 %% @deftypefnx {} {} camlight (@var{h}, @dots{})
 %% Add lights to a figure using a simple interface.
@@ -43,15 +44,27 @@
 %%
 %% For more control, the light can also be positioned by an azimuthal
 %% rotation @var{az} and an elevation angle @var{el}, both in degrees,
-%% and both relative to the current properties of the camera.
-%% More specifically, the light is first pitched upwards (@pxref{camup})
-%% from the the camera position (@pxref{campos}) by @var{el}.  It is
-%% then yawed by @var{az}.  Both rotations are centered around the
+%% and both relative to the current properties of the camera.  Consider
+%% the example:
+%% @example
+%% @group
+%% @c doctest: +SKIP
+%% camlight (45, 30)
+%% @end group
+%% @end example
+%% Here the light is first pitched upwards (@pxref{camup}) from the
+%% camera position (@pxref{campos}) by 30 degrees.  It is then yawed by
+%% 45 degrees to the right.  Both rotations are centered around the
 %% camera target (@pxref{camtarget}).
 %%
-%% A handle to the light can optionally be returned.  It can be
-%% used to further manipulate the light.  For example, we can create
-%% a light on the left and then move it to the right:
+%% An optional string @var{style} specifies whether the light is a
+%% local point source (@qcode{"local"}, the default) or placed at
+%% infinite distance (@qcode{"infinite"}).
+%%
+%% A handle to the light can optionally be returned.  It can be used to
+%% move or otherwise manipulate the light.  For example, we can create
+%% a light on the left, move it to the right, finally changing its
+%% colour:
 %% @example
 %% @group
 %% @c doctest: +SKIP
@@ -69,45 +82,88 @@
 %% @end deftypefn
 
 
-function h = camlight (varargin)
+function hout = camlight (varargin)
 
-  if ( (nargin == 0) || (! ishandle (varargin{1})) )
-    hin = [];  % no handle
-    z = 0;     % first input
-  else
-    hin = varargin{1};
-    z = 1;
-  end
+  h = [];
+  style = 'local';
 
-  if (nargin == z)
-    s = 'right';
-  elseif (nargin == z + 1)
-    s = varargin{z + 1};
-    if (! ischar (s))
+  if (nargin == 0)
+    where = 'right';
+
+  elseif (nargin == 1)
+    _v = varargin{1};
+    if (ischar (_v) && (strcmp (_v, 'local') || strcmp (_v, 'infinite')))
+      % camlight (style)
+      style = _v;
+      where = 'right';
+    elseif (ischar (_v))
+      % camlight (where)
+      where = _v;
+    elseif (ishandle (_v))
+      % camlight (h)
+      h = _v;
+      where = 'right';
+    else
       print_usage ();
     end
-  elseif (nargin == z + 2)
-    s = '_skip';
-    az = varargin{z + 1};
-    el = varargin{z + 2};
+
+  elseif (nargin == 2)
+    _v1 = varargin{1};
+    _v2 = varargin{2};
+    if (ishandle (_v1) && ischar (_v2) && ...
+        (strcmp (_v2, 'local') || strcmp (_v2, 'infinite')))
+      % camlight (h, style)
+      h = _v1;
+      style = _v2;
+      where = 'right';
+    elseif (ishandle (_v1) && ischar (_v2))
+      % camlight (h, where)
+      h = _v1;
+      where = _v2;
+    elseif (isnumeric (_v1) && isnumeric (_v2))
+      % camlight (az, el)
+      az = _v1;
+      el = _v2;
+    elseif (ischar (_v1) && ischar (_v2))
+      % camlight (where, style)
+      where = _v1;
+      style = _v2;
+    else
+      print_usage ();
+    end
+
+  elseif (nargin == 3)
+    if (ishandle (varargin{1}) && isnumeric (varargin{2}) && isnumeric (varargin{3}))
+      [h, az, el] = varargin{1:3};
+    elseif (ishandle (varargin{1}) && ischar (varargin{2}) && ischar (varargin{3}))
+      [h, where, style] = varargin{1:3};
+    elseif (isnumeric (varargin{1}) && isnumeric (varargin{2}) && ischar (varargin{3}))
+      [az, el, style] = varargin{1:3};
+    else
+      print_usage ();
+    end
+
+  elseif (nargin == 4)
+    [h, az, el, style] = varargin{1:4};
+    assert (ishandle (h), "Input 'H' must be a handle");
   else
     print_usage ();
   end
 
-  switch lower(s)
-    case 'left'
-      % TODO: compare to Matlab
-      az = -45;
-      el = 30;
-    case 'right'
-      az = 45;
-      el = 30;
-    case 'headlight'
-      az = 0;
-      el = 0;
-    case '_skip'
-    otherwise
-      error ('Invalid camlight position')
+  if (exist ('where', 'var'))
+    switch lower(where)
+      case 'left'
+        az = -30;
+        el = 30;
+      case 'right'
+        az = 30;
+        el = 30;
+      case 'headlight'
+        az = 0;
+        el = 0;
+      otherwise
+        error ('Invalid camlight position')
+    end
   end
 
   cam_up = get (gca, 'cameraupvector');
@@ -124,15 +180,15 @@
   A = rotateAxis(cam_pos, el, pitch_ax, cam_target);
   light_pos = rotateAxis(A, az, yaw_ax, cam_target);
 
-  if (isempty (hin))
-    htmp = light ('Position', light_pos);
+  if (isempty (h))
+    htmp = light ('Position', light_pos, 'style', style);
   else
-    set (hin, 'Position', light_pos);
-    htmp = hin;
+    set (h, 'Position', light_pos, 'style', style);
+    htmp = h;
   end
 
   if (nargout > 0)
-    h = htmp;
+    hout = htmp;
   end
 end
 
@@ -173,11 +229,24 @@
 %! end
 
 
-%!error <Invalid> camlight ('wtf')
-%!error <Invalid> camlight (42)
+%!error <Invalid> camlight ('wrong')
+%!error <Invalid> camlight ('wrong', 'local')
+%!error <Invalid> camlight (1, 2, 3, 4, 5)
 
-%!shared hf
+%!shared hf, nh
 %! hf = figure ('visible', 'off');
+%! do
+%!   nh = 100*rand ();
+%!   % ensure we have a non-handle double
+%! until (!ishandle (nh))
+
+%!error <invalid> camlight ('right', 'gangnam')
+%!error <invalid> camlight (30, 30, 'gangnam')
+%!error <Invalid> camlight (nh)
+%!error <Invalid> camlight (nh, 'right')
+%!error <Invalid> camlight (nh, 'local')
+%!error <must be a handle> camlight (nh, 30, 30, 'local')
+
 %!test
 %! clf; sphere (24);
 %! set (gca, 'cameraposition', [8 12 7.3])
@@ -211,10 +280,21 @@
 %! h = camlight();
 %! camlight(double(h) + 10, 20)
 
-%!xtest
+%!test
 %! % Should be a new light at az == h, el == 20
-%! h = camlight();
-%! camlight(double(h), 20)
+%! h = camlight ();
+%! camlight (double (h), 20)
+
+%!test
+%! % updating style also moves light
+%! clf
+%! h1 = camlight ('right');
+%! h = camlight ('headlight');
+%! p1 = get (h1, 'position');
+%! h2 = camlight (h, 'local');
+%! p2 = get (h2, 'position');
+%! assert (h, h2)
+%! assert (p1, p2)
 
 %!test
 %! close (hf);
# HG changeset patch
# User Colin Macdonald <cbm@m.fsf.org>
# Date 1464889592 25200
#      Thu Jun 02 10:46:32 2016 -0700
# Node ID 3fdc821e2de7954fb58acd1811e41931f0126560
# Parent  ee2c31f894fc7dbbc440c6c117cd929a72b4be3a
Reformat camlight to more closely follow Octave conventions

* camlight.m: reformatting

diff -r ee2c31f894fc -r 3fdc821e2de7 scripts/plot/draw/camlight.m
--- a/scripts/plot/draw/camlight.m	Thu Jun 02 10:38:34 2016 -0700
+++ b/scripts/plot/draw/camlight.m	Thu Jun 02 10:46:32 2016 -0700
@@ -1,85 +1,85 @@
-%% 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/>.
+## 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 -*-
-%% @documentencoding UTF-8
-%% @deftypefn  {} {} camlight {}
-%% @deftypefnx {} {} camlight right
-%% @deftypefnx {} {} camlight left
-%% @deftypefnx {} {} camlight headlight
-%% @deftypefnx {} {} camlight (@var{az}, @var{el})
-%% @deftypefnx {} {} camlight (@dots{}, @var{style})
-%% @deftypefnx {} {@var{h} =} camlight (@dots{})
-%% @deftypefnx {} {} camlight (@var{h}, @dots{})
-%% Add lights to a figure using a simple interface.
-%%
-%% Example:
-%% @example
-%% @group
-%% @c doctest: +SKIP
-%% sphere (36)
-%% camlight
-%% @end group
-%% @end example
-%%
-%% By default the light is positioned slightly above and to the
-%% right of the camera's current position: this is the same as
-%% @code{camlight right}.  The commands @code{camlight left} and
-%% @code{camlight headlight} behave similarly.
-%%
-%% For more control, the light can also be positioned by an azimuthal
-%% rotation @var{az} and an elevation angle @var{el}, both in degrees,
-%% and both relative to the current properties of the camera.  Consider
-%% the example:
-%% @example
-%% @group
-%% @c doctest: +SKIP
-%% camlight (45, 30)
-%% @end group
-%% @end example
-%% Here the light is first pitched upwards (@pxref{camup}) from the
-%% camera position (@pxref{campos}) by 30 degrees.  It is then yawed by
-%% 45 degrees to the right.  Both rotations are centered around the
-%% camera target (@pxref{camtarget}).
-%%
-%% An optional string @var{style} specifies whether the light is a
-%% local point source (@qcode{"local"}, the default) or placed at
-%% infinite distance (@qcode{"infinite"}).
-%%
-%% A handle to the light can optionally be returned.  It can be used to
-%% move or otherwise manipulate the light.  For example, we can create
-%% a light on the left, move it to the right, finally changing its
-%% colour:
-%% @example
-%% @group
-%% @c doctest: +SKIP
-%% clf
-%% sphere (36)
-%% h = camlight ('left')
-%% drawnow ()
-%% camlight (h, 'right')
-%% drawnow ()
-%% set (h, 'color', 'r')
-%% @end group
-%% @end example
-%%
-%% @seealso{light, material}
-%% @end deftypefn
+## -*- texinfo -*-
+## @documentencoding UTF-8
+## @deftypefn  {} {} camlight {}
+## @deftypefnx {} {} camlight right
+## @deftypefnx {} {} camlight left
+## @deftypefnx {} {} camlight headlight
+## @deftypefnx {} {} camlight (@var{az}, @var{el})
+## @deftypefnx {} {} camlight (@dots{}, @var{style})
+## @deftypefnx {} {@var{h} =} camlight (@dots{})
+## @deftypefnx {} {} camlight (@var{h}, @dots{})
+## Add lights to a figure using a simple interface.
+##
+## Example:
+## @example
+## @group
+## @c doctest: +SKIP
+## sphere (36)
+## camlight
+## @end group
+## @end example
+##
+## By default the light is positioned slightly above and to the
+## right of the camera's current position: this is the same as
+## @code{camlight right}.  The commands @code{camlight left} and
+## @code{camlight headlight} behave similarly.
+##
+## For more control, the light can also be positioned by an azimuthal
+## rotation @var{az} and an elevation angle @var{el}, both in degrees,
+## and both relative to the current properties of the camera.  Consider
+## the example:
+## @example
+## @group
+## @c doctest: +SKIP
+## camlight (45, 30)
+## @end group
+## @end example
+## Here the light is first pitched upwards (@pxref{camup}) from the
+## camera position (@pxref{campos}) by 30 degrees.  It is then yawed by
+## 45 degrees to the right.  Both rotations are centered around the
+## camera target (@pxref{camtarget}).
+##
+## An optional string @var{style} specifies whether the light is a
+## local point source (@qcode{"local"}, the default) or placed at
+## infinite distance (@qcode{"infinite"}).
+##
+## A handle to the light can optionally be returned.  It can be used to
+## move or otherwise manipulate the light.  For example, we can create
+## a light on the left, move it to the right, finally changing its
+## colour:
+## @example
+## @group
+## @c doctest: +SKIP
+## clf
+## sphere (36)
+## h = camlight ("left")
+## drawnow ()
+## camlight (h, "right")
+## drawnow ()
+## set (h, "color", "r")
+## @end group
+## @end example
+##
+## @seealso{light, material}
+## @end deftypefn
 
 
 function hout = camlight (varargin)
@@ -93,44 +93,44 @@
   elseif (nargin == 1)
     _v = varargin{1};
     if (ischar (_v) && (strcmp (_v, 'local') || strcmp (_v, 'infinite')))
-      % camlight (style)
+      # camlight (style)
       style = _v;
       where = 'right';
     elseif (ischar (_v))
-      % camlight (where)
+      # camlight (where)
       where = _v;
     elseif (ishandle (_v))
-      % camlight (h)
+      # camlight (h)
       h = _v;
       where = 'right';
     else
       print_usage ();
-    end
+    endif
 
   elseif (nargin == 2)
     _v1 = varargin{1};
     _v2 = varargin{2};
     if (ishandle (_v1) && ischar (_v2) && ...
         (strcmp (_v2, 'local') || strcmp (_v2, 'infinite')))
-      % camlight (h, style)
+      # camlight (h, style)
       h = _v1;
       style = _v2;
       where = 'right';
     elseif (ishandle (_v1) && ischar (_v2))
-      % camlight (h, where)
+      # camlight (h, where)
       h = _v1;
       where = _v2;
     elseif (isnumeric (_v1) && isnumeric (_v2))
-      % camlight (az, el)
+      # camlight (az, el)
       az = _v1;
       el = _v2;
     elseif (ischar (_v1) && ischar (_v2))
-      % camlight (where, style)
+      # camlight (where, style)
       where = _v1;
       style = _v2;
     else
       print_usage ();
-    end
+    endif
 
   elseif (nargin == 3)
     if (ishandle (varargin{1}) && isnumeric (varargin{2}) && isnumeric (varargin{3}))
@@ -141,17 +141,17 @@
       [az, el, style] = varargin{1:3};
     else
       print_usage ();
-    end
+    endif
 
   elseif (nargin == 4)
     [h, az, el, style] = varargin{1:4};
     assert (ishandle (h), "Input 'H' must be a handle");
   else
     print_usage ();
-  end
+  endif
 
   if (exist ('where', 'var'))
-    switch lower(where)
+    switch lower (where)
       case 'left'
         az = -30;
         el = 30;
@@ -163,8 +163,8 @@
         el = 0;
       otherwise
         error ('Invalid camlight position')
-    end
-  end
+    endswitch
+  endif
 
   cam_up = get (gca, 'cameraupvector');
   cam_pos = get (gca, 'cameraposition');
@@ -175,22 +175,22 @@
   yaw_ax = cam_up - view_ax*dot (cam_up, view_ax);
   pitch_ax = cross (cam_up, view_ax);
 
-  % First pitch up by 'el', then yaw by 'az'.
-  % (order matters, this matches experiments with Matlab).
-  A = rotateAxis(cam_pos, el, pitch_ax, cam_target);
-  light_pos = rotateAxis(A, az, yaw_ax, cam_target);
+  # First pitch up by 'el', then yaw by 'az'.
+  # (order matters, this matches experiments with Matlab).
+  A = rotateAxis (cam_pos, el, pitch_ax, cam_target);
+  light_pos = rotateAxis (A, az, yaw_ax, cam_target);
 
   if (isempty (h))
     htmp = light ('Position', light_pos, 'style', style);
   else
     set (h, 'Position', light_pos, 'style', style);
     htmp = h;
-  end
+  endif
 
   if (nargout > 0)
     hout = htmp;
-  end
-end
+  endif
+endfunction
 
 
 %!demo
@@ -267,18 +267,18 @@
 %! % move a light
 %! h = camlight ('left');
 %! h2 = camlight ();
-%! p2 = get(h2, 'position');
-%! camlight(h, 'right')
-%! p = get(h, 'position');
+%! p2 = get (h2, 'position');
+%! camlight (h, 'right')
+%! p = get (h, 'position');
 %! assert (p, p2)
-%! camlight(h)
-%! p = get(h, 'position');
+%! camlight (h)
+%! p = get (h, 'position');
 %! assert (p, p2)
 
 %!test
 %! % Should be a new light at az == h + 10, el == 20
-%! h = camlight();
-%! camlight(double(h) + 10, 20)
+%! h = camlight ();
+%! camlight (double (h) + 10, 20)
 
 %!test
 %! % Should be a new light at az == h, el == 20
@@ -301,14 +301,14 @@
 
 
 function xxr = rotateAxis(xx, angle, dir, origin);
-  % Rotate the point XX about an axis by ANGLE degrees.
-  % The axis is specified by vector DIR and point ORIGIN.
+  # Rotate the point XX about an axis by ANGLE degrees.
+  # The axis is specified by vector DIR and point ORIGIN.
   dir = dir / norm(dir);
   x = xx(1);
   y = xx(2);
   z = xx(3);
 
-  % this code is copied from @pxref{rotate}.
+  # this code is copied from @pxref{rotate}.
   u = dir(1);
   v = dir(2);
   w = dir(3);
@@ -333,4 +333,4 @@
   xxr(1) = xr;
   xxr(2) = yr;
   xxr(3) = zr;
-end
+endfunction
# HG changeset patch
# User Colin Macdonald <cbm@m.fsf.org>
# Date 1464803969 25200
#      Wed Jun 01 10:59:29 2016 -0700
# Node ID 065aabcba59e282d48817e6a709c069ce62f4490
# Parent  f625afd1ef5553120f0639d5a12562508f93e2d7
Add camlight function

* camlight.m: new function
* __unimplemented__.m: remove camlight

diff -r f625afd1ef55 -r 065aabcba59e scripts/help/__unimplemented__.m
--- a/scripts/help/__unimplemented__.m	Mon May 30 09:51:47 2016 -0400
+++ b/scripts/help/__unimplemented__.m	Wed Jun 01 10:59:29 2016 -0700
@@ -574,7 +574,6 @@
   "callSoapService",
   "camdolly",
   "cameratoolbar",
-  "camlight",
   "camlookat",
   "camorbit",
   "campan",
diff -r f625afd1ef55 -r 065aabcba59e scripts/plot/draw/camlight.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/camlight.m	Wed Jun 01 10:59:29 2016 -0700
@@ -0,0 +1,188 @@
+%% 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 -*-
+%% @documentencoding UTF-8
+%% @deftypefn  {} {} camlight {}
+%% @deftypefnx {} {} camlight right
+%% @deftypefnx {} {} camlight left
+%% @deftypefnx {} {} camlight headlight
+%% @deftypefnx {} {} camlight (@var{az}, @var{el})
+%% @deftypefnx {} {@var{h} =} camlight (@dots{})
+%% Add lights to a figure using a simple interface.
+%%
+%% Example:
+%% @example
+%% @c doctest: +SKIP
+%% @group
+%% sphere (36)
+%% camlight
+%% @end group
+%% @end example
+%%
+%% By default the light is positioned slightly above and to the
+%% right of the camera's current position: this is the same as
+%% @code{camlight right}.  The commands @code{camlight left} and
+%% @code{camlight headlight} behave similarly.
+%%
+%% For more control, the light can also be positioned by an azimuthal
+%% rotation @var{az} and an elevation angle @var{el}, both in degrees,
+%% and both relative to the current properties of the camera.
+%% More specifically, the light is first pitched upwards (@pxref{camup})
+%% from the the camera position (@pxref{campos}) by @var{el}.  It is
+%% then yawed by @var{az}.  Both rotations are centered around the
+%% camera target (@pxref{camtarget}).
+%%
+%%
+%% TODO: style kwarg.
+%%
+%% @seealso{lighting, light, material}
+%% @end deftypefn
+
+
+function varargout = camlight(az, el)
+
+  if (nargin == 0)
+    s = 'right';
+  elseif ((nargin == 1) && (ischar (az)))
+    s = az;
+  elseif (nargin == 2)
+    s = '_skip';
+  else
+    print_usage ();
+  end
+
+  switch lower(s)
+    case 'left'
+      % TODO: compare to Matlab
+      az = -45;
+      el = 30;
+    case 'right'
+      az = 45;
+      el = 30;
+    case 'headlight'
+      az = 0;
+      el = 0;
+    case '_skip'
+    otherwise
+      error ('Invalid camlight position')
+  end
+
+  cam_up = get (gca, 'cameraupvector');
+  cam_pos = get (gca, 'cameraposition');
+  cam_target = get (gca, 'cameratarget');
+
+  view_ax = cam_target - cam_pos;
+  view_ax = view_ax / norm (view_ax);
+  yaw_ax = cam_up - view_ax*dot (cam_up, view_ax);
+  pitch_ax = cross (cam_up, view_ax);
+
+  % First pitch up by 'el', then yaw by 'az'.
+  % (order matters, this matches experiments with Matlab).
+  A = rotateAxis(cam_pos, el, pitch_ax, cam_target);
+  light_pos = rotateAxis(A, az, yaw_ax, cam_target);
+
+  h = light ('Position', light_pos);
+
+  if (nargout == 1)
+    varargout = {h};
+  end
+end
+
+
+%!demo
+%! %% Adding lights to a scene
+%! sphere (64);
+%! camlight
+%!
+%! %% add another light
+%! camlight left
+
+%!demo
+%! sphere (48)
+%! title ('This light has a fixed position, even if the camera moves');
+%! axis equal; shading flat
+%! view (30, 30)
+%!
+%! camlight
+%!
+%! for a = 30:2:390
+%!   view (a, 30)
+%!   drawnow ()
+%! end
+
+
+%!error <Invalid> camlight ('wtf')
+%!error <Invalid> camlight (42)
+%!error <Invalid> camlight (1, 2, 3)
+
+%!shared hf
+%! hf = figure ('visible', 'off');
+%!test
+%! clf; sphere (24);
+%! set (gca, 'cameraposition', [8 12 7.3])
+%! set (gca, 'cameraupvector', [0 2 2])
+%! set (gca, 'cameratarget', [0.5 -0.3 -0.3])
+%! h = camlight (45, 20);
+%! A = get (h, 'position');
+%! % From maillist, someone tested on Matlab R2015b for OSX:
+%! B = [-3.301207088157029 15.474861455795917 1.115828634895176];
+%! assert (A, B, -20*eps)
+%!test
+%! h = camlight (300, -190);
+%! A = get (h, 'position');
+%! B = [-11.054849015640563 2.931330143100648 -11.315623892092518];
+%! assert (A, B, -20*eps)
+%!test
+%! close (hf);
+
+
+function xxr = rotateAxis(xx, angle, dir, origin);
+  % Rotate the point XX about an axis by ANGLE degrees.
+  % The axis is specified by vector DIR and point ORIGIN.
+  dir = dir / norm(dir);
+  x = xx(1);
+  y = xx(2);
+  z = xx(3);
+
+  % this code is copied from @pxref{rotate}.
+  u = dir(1);
+  v = dir(2);
+  w = dir(3);
+
+  a = origin(1);
+  b = origin(2);
+  c = origin(3);
+
+  sa = sind (angle);
+  ca = cosd (angle);
+
+  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);
+  xxr = xx;
+  xxr(1) = xr;
+  xxr(2) = yr;
+  xxr(3) = zr;
+end
