changeset 26545:aea4e66eb331

New function lightangle (bug #55446). * scripts/plot/draw/lightangle.m: New function. * scripts/plot/draw/module.mk: Add new file to build system. * doc/interpreter/plot.txi: Add docstring to manual. * NEWS: Announce new file.
author Guillaume Flandin
date Mon, 14 Jan 2019 12:54:32 +0000
parents 0ba9ecd3814b
children b52f6b0667eb
files NEWS doc/interpreter/plot.txi scripts/plot/draw/lightangle.m scripts/plot/draw/module.mk
diffstat 4 files changed, 166 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Sun Jan 13 19:33:39 2019 -0800
+++ b/NEWS	Mon Jan 14 12:54:32 2019 +0000
@@ -3,6 +3,7 @@
 
  ** New functions added in 6.0:
 
+      lightangle
 
  ** Deprecated functions.
 
--- a/doc/interpreter/plot.txi	Sun Jan 13 19:33:39 2019 -0800
+++ b/doc/interpreter/plot.txi	Mon Jan 14 12:54:32 2019 +0000
@@ -459,6 +459,8 @@
 
 @DOCSTRING(camlight)
 
+@DOCSTRING(lightangle)
+
 @DOCSTRING(meshgrid)
 
 @DOCSTRING(ndgrid)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/lightangle.m	Mon Jan 14 12:54:32 2019 +0000
@@ -0,0 +1,162 @@
+## Copyright (C) 2019 Guillaume Flandin
+##
+## 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
+## <https://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} lightangle (@var{az}, @var{el})
+## @deftypefnx {} {} lightangle (@var{hax}, @var{az}, @var{el})
+## @deftypefnx {} {} lightangle (@var{hl}, @var{az}, @var{el})
+## @deftypefnx {} {@var{hl} =} lightangle (@dots{})
+## @deftypefnx {} {[@var{az}, @var{el}] =} lightangle (@var{hl})
+## Add a light object to the current axes using spherical coordinates.
+##
+## The light position is specified by an azimuthal rotation @var{az} and an
+## elevation angle @var{el}, both in degrees.
+##
+## If the first argument @var{hax} is an axes handle, then create a new light
+## object in this axes, rather than the current axes returned by @code{gca}.
+##
+## If the first argument @var{hl} is a handle to a light object, then act on
+## this light object rather than creating a new object.
+##
+## The optional return value @var{hl} is a graphics handle to the light object.
+##
+## Example:
+##
+## Add a light object to a plot
+##
+## @example
+## @group
+## @c doctest: +SKIP
+## clf;
+## sphere (36);
+## lightangle (45, 30);
+## @end group
+## @end example
+##
+## @seealso{light, view, camlight}
+## @end deftypefn
+
+function varargout = lightangle (varargin)
+
+  if (nargin == 0 || nargin > 3 || nargout > 2 || (nargin > 1 && nargout > 1))
+    print_usage ();
+  endif
+
+  hl = hax = az = el = [];
+
+  if (nargin == 1)
+    hl = varargin{1};
+    if (! isscalar (hl) || ! isgraphics (hl, "light"))
+      error ("lightangle: HL must be a handle to a light object");
+    endif
+  elseif (nargin == 2)
+    az = varargin{1};
+    el = varargin{2};
+  elseif (nargin == 3)
+    h = varargin{1};
+    if (isscalar (h) && isaxes (h))
+      hax = h;
+    elseif (isscalar (h) && isgraphics (h, "light"))
+      hl = h;
+    else
+      error ("lightangle: H must be a handle to an axes or light object");
+    endif
+    az = varargin{2};
+    el = varargin{3};
+  endif
+
+  if (! isempty (hl))
+    hax = ancestor (hl, "axes");
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  endif
+
+  if (isempty (hl))
+    hl = light (hax);
+  endif
+
+  pos = get (hl, "Position");
+
+  if (nargin == 1)
+    [az, el] = cart2sph (pos(1), pos(2), pos(3));
+    az = rad2deg (az) + 90;  # see view.m
+    el = rad2deg (el);
+    varargout = { az, el };
+    return;
+  else
+    if (! isscalar (az) || ! isnumeric (az)
+        || ! isscalar (el) || ! isnumeric (el))
+      error ("lightangle: AZ and EL must be numeric scalars.");
+    endif
+  endif  
+
+  az = deg2rad (az - 90);
+  el = deg2rad (el);
+
+  if (strcmp (get (hl, "Style"), "local"))
+    pos -= get (hax, "CameraTarget");
+  endif 
+
+  pos = sph2cart (az, el, norm (pos));
+
+  if (strcmp (get (hl, "Style"), "local"))
+    pos += get (hax, "CameraTarget");
+  endif
+
+  set (hl, "Position", pos);
+
+  if (nargout == 1)
+    varargout = { hl };
+  endif
+
+endfunction
+
+
+%!demo
+%! clf;
+%! sphere (36);
+%! lightangle (45, 30);
+
+%!test
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   sphere (24);
+%!   hl = lightangle (45, 20);
+%!   assert (isgraphics (hl, "light"));
+%!   [az, el] = lightangle (hl);
+%!   assert ([45, 20], [az, el], -20*eps);
+%!   lightangle (hl, 90, 45);
+%!   [az, el] = lightangle (hl);
+%!   assert ([90, 45], [az, el], -20*eps);
+%!   pos = get (hl, "Position");
+%!   assert ([1, 0, 1], pos, -20*eps);
+%!   hl = lightangle (gca (), 45, 20);
+%!   assert (isgraphics (hl, "light"));
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+## Test input validation
+%!error <Invalid call> lightangle ();
+%!error <Invalid call> lightangle (1, 2, 3, 4);
+%!error <Invalid call> [a, b] = lightangle (45, 30);
+%!error <Invalid call> [a, b, c] = lightangle (45, 30);
+%!error <HL must be a handle to a light object> lightangle (0);
+%!error <H must be a handle to an axes or light object> lightangle (0, 90, 45);
--- a/scripts/plot/draw/module.mk	Sun Jan 13 19:33:39 2019 -0800
+++ b/scripts/plot/draw/module.mk	Mon Jan 14 12:54:32 2019 +0000
@@ -54,6 +54,7 @@
   %reldir%/isonormals.m \
   %reldir%/isosurface.m \
   %reldir%/light.m \
+  %reldir%/lightangle.m \
   %reldir%/line.m \
   %reldir%/loglog.m \
   %reldir%/loglogerr.m \