changeset 22247:c8fc60a183a3

Add function material. (patch #9013) * scripts/plot/appearance/material.m: New function. * scripts/plot/appearance/module.mk: Update build system. * NEWS: Announce new function. * __unimplemented__.m: Remove "material" from list. * doc/interpreter/plot.txi: Add doc string. * light.m: Add "material" to "see also".
author Markus Muetzel <markus.muetzel@gmx.de>
date Mon, 18 Jul 2016 17:46:05 +0200
parents fa917f1f0faf
children 60986498af9e
files NEWS doc/interpreter/plot.txi scripts/help/__unimplemented__.m scripts/plot/appearance/material.m scripts/plot/appearance/module.mk scripts/plot/draw/light.m
diffstat 6 files changed, 317 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Aug 10 00:56:51 2016 +0100
+++ b/NEWS	Mon Jul 18 17:46:05 2016 +0200
@@ -117,6 +117,7 @@
       hash
       im2double
       localfunctions
+      material
       normest1
       ode45
       odeget
--- a/doc/interpreter/plot.txi	Wed Aug 10 00:56:51 2016 +0100
+++ b/doc/interpreter/plot.txi	Mon Jul 18 17:46:05 2016 +0200
@@ -398,6 +398,8 @@
 
 @DOCSTRING(lighting)
 
+@DOCSTRING(material)
+
 @DOCSTRING(meshgrid)
 
 @DOCSTRING(ndgrid)
--- a/scripts/help/__unimplemented__.m	Wed Aug 10 00:56:51 2016 +0100
+++ b/scripts/help/__unimplemented__.m	Mon Jul 18 17:46:05 2016 +0200
@@ -713,7 +713,6 @@
   "lsqr",
   "makehgtform",
   "mapreduce",
-  "material",
   "matfile",
   "matlabrc",
   "memmapfile",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/appearance/material.m	Mon Jul 18 17:46:05 2016 +0200
@@ -0,0 +1,312 @@
+## Copyright (C) 2016 Markus Muetzel
+##
+## 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  {} {} material shiny
+## @deftypefnx {} {} material dull
+## @deftypefnx {} {} material metal
+## @deftypefnx {} {} material default
+## @deftypefnx {} {} material ([@var{as}, @var{ds}, @var{ss}])
+## @deftypefnx {} {} material ([@var{as}, @var{ds}, @var{ss}, @var{se}])
+## @deftypefnx {} {} material ([@var{as}, @var{ds}, @var{ss}, @var{se}, @var{scr}])
+## @deftypefnx {} {} material (@var{hlist}, @dots{})
+## @deftypefnx {} {@var{mtypes} =} material ()
+## @deftypefnx {} {@var{refl_props} =} material (@var{mtype_string})
+## Set reflectance properties for the lighting of surfaces and patches.
+##
+## This function changes the ambient, diffuse, and specular strengths, as well
+## as the specular exponent and specular color reflectance, of all
+## @code{patch} and @code{surface} objects in the current axes.  This can be
+## used to simulate, to some extent, the reflectance properties of certain
+## materials when used with @code{light}.
+##
+## When called with a string, the aforementioned properties are set
+## according to the values in the following table:
+##
+## @multitable @columnfractions .0 .2 .15 .15 .15 .15 .15 .0
+## @headitem @tab @var{mtype} @tab ambient- strength @tab diffuse-
+## strength @tab specular- strength @tab specular- exponent @tab specular-
+## color- reflectance @tab
+## @item @tab @qcode{"shiny"} @tab 0.3 @tab 0.6 @tab 0.9 @tab 20 @tab 1.0 @tab
+## @item @tab @qcode{"dull"} @tab 0.3 @tab 0.8 @tab 0.0 @tab 10 @tab 1.0 @tab
+## @item @tab @qcode{"metal"} @tab 0.3 @tab 0.3 @tab 1.0 @tab 25 @tab 0.5 @tab
+## @item @tab @qcode{"default"} @tab @qcode{"default"} @tab @qcode{"default"} @tab @qcode{"default"} @tab
+## @qcode{"default"} @tab @qcode{"default"} @tab
+## @end multitable
+##
+## When called with a vector of three elements, the ambient, diffuse, and
+## specular strengths of all @code{patch} and @code{surface} objects in the
+## current axes are updated.  An optional fourth vector element updates the
+## specular exponent, and an optional fifth vector element updates the
+## specular color reflectance.
+##
+## A list of graphic handles can also be passed as the first argument.  In
+## this case, the properties of these handles and all child @code{patch} and
+## @code{surface} objects will be updated.
+##
+## Additionally, @code{material} can be called with a single output argument.
+## If called without input arguments, a column cell vector @var{mtypes} with
+## the strings for all available materials is returned.  If the one input
+## argument @var{mtype_string} is the name of a material, a 1x5 cell vector
+## @var{refl_props} with the reflectance properties of that material is
+## returned.  In both cases, no graphic properties are changed.
+##
+## @seealso{light, fill, mesh, patch, pcolor, surf, surface}
+## @end deftypefn
+
+## Author: mmuetzel
+
+function retval = material (varargin)
+
+  if (! ((nargout == 0 && (nargin == 1 || nargin == 2)) ||
+         (nargout == 1 && (nargin == 0 || nargin == 1))) )
+    print_usage ();
+  endif
+
+  ## resolve input
+  if (nargout == 0)
+    ## Check whether first argument is list of graphics handles.
+    if (all (ishandle (varargin{1})))
+      h = varargin{1};
+      varargin(1) = [];
+    else
+      h = gca ();
+    endif
+
+    ## There must be one (additional) argument.
+    if (numel (varargin) != 1)
+      if (nargin == 2)
+        error (["material: When called with two arguments, the first argument " ...
+                "must be a list of handles to graphics objects."]);
+      else
+        print_usage ();
+      endif
+    endif
+  elseif (nargin == 0)
+    ## Return name of materials.
+    retval = {"shiny"; "dull"; "metal"; "default"};
+    return;
+  endif
+
+  mtype = varargin{1};
+
+  se = [];
+  scr = [];
+
+  ## check material type
+  if (ischar (mtype))
+    switch (lower (mtype))
+      case "shiny"
+        as = 0.3;
+        ds = 0.6;
+        ss = 0.9;
+        se = 20;
+        scr = 1.0;
+
+      case "dull"
+        as = 0.3;
+        ds = 0.8;
+        ss = 0.0;
+        se = 10;
+        scr = 1.0;
+
+      case "metal"
+        as = 0.3;
+        ds = 0.3;
+        ss = 1.0;
+        se = 25;
+        scr = .5;
+
+      case "default"
+        as = "default";
+        ds = "default";
+        ss = "default";
+        se = "default";
+        scr = "default";
+
+      otherwise
+        error ("material: unknown material type '%s'", mtype);
+
+    endswitch
+    
+    if (nargout == 1)
+      ## Return 1x5 cell vector with reflectance properties.
+      retval = {as, ds, ss, se, scr};
+      return;
+    endif
+
+  elseif (nargout == 1)
+    ## If we reach here with one output argument, the input was wrong.
+    print_usage ();
+
+  elseif (isvector (mtype))
+    num_mtype = numel (mtype);
+    if (num_mtype < 2 || num_mtype > 5)
+      error ("material: incorrect number of elements in material vector");
+    endif
+    as = mtype(1);
+    ds = mtype(2);
+    ss = mtype(3);
+    if (num_mtype >= 4)
+      se = mtype(4);
+      if (num_mtype == 5)
+        scr = mtype(5);
+      endif
+    endif
+
+  else
+    error ("material: MTYPE must be a named material or a vector");
+  endif
+
+  ## find all patch and surface objects in current axes
+  hps = findobj (h, "Type", "patch", "-or", "Type", "surface");
+
+  ## set properties
+  set (hps,
+       "ambientstrength", as, "diffusestrength", ds, "specularstrength", ss);
+
+  if (! isempty (se))
+    set (hps, "specularexponent", se);
+    if (! isempty (scr))
+      set (hps, "specularcolorreflectance", scr);
+    endif
+  endif
+
+endfunction
+
+
+%!demo
+%! clf;
+%! %% patch
+%! h_axes = axes;
+%! [x,y,z] = meshgrid (-2:0.2:2, -2:0.2:2, -2:0.2:2);
+%! val = x.^2 + y.^2 + z.^2;
+%! fv1 = isosurface (x, y, z, val, 1);
+%! h_patch = patch (fv1, "FaceColor", "r", "EdgeColor", "none", "FaceLighting", "Gouraud");
+%! isonormals (x, y, z, val, h_patch)
+%! axis equal; axis tight
+%! view (3)
+%! drawnow
+%! h_light = light ();
+%! material ([0 0.5 1 10 .5])
+
+%!demo
+%! clf
+%! %% surface
+%! h_axes = axes;
+%! h_surf = surf (h_axes, peaks, "LineStyle", "none", "FaceLighting", "Gouraud");
+%! view (3)
+%! h_light = light ();
+%! material metal
+
+%!test
+%! hf = figure ("Visible", "off");
+%! unwind_protect
+%!   hp = patch;
+%!   hs = surface;
+%!   material dull
+%!   assert (get (hp, "ambientstrength"), 0.3);
+%!   assert (get (hs, "ambientstrength"), 0.3);
+%!   assert (get (hp, "diffusestrength"), 0.8);
+%!   assert (get (hs, "diffusestrength"), 0.8);
+%!   assert (get (hp, "specularstrength"), 0.0);
+%!   assert (get (hs, "specularstrength"), 0.0);
+%!   assert (get (hp, "specularexponent"), 10);
+%!   assert (get (hs, "specularexponent"), 10);
+%!   assert (get (hp, "specularcolorreflectance"), 1.0);
+%!   assert (get (hs, "specularcolorreflectance"), 1.0);
+%!   material default
+%!   assert (get (hp, "ambientstrength"), get (0, "defaultpatchambientstrength"));
+%!   assert (get (hs, "ambientstrength"), get (0, "defaultsurfaceambientstrength"));
+%!   assert (get (hp, "diffusestrength"), get (0, "defaultpatchdiffusestrength"));
+%!   assert (get (hs, "diffusestrength"), get (0, "defaultsurfacediffusestrength"));
+%!   assert (get (hp, "specularstrength"), get (0, "defaultpatchspecularstrength"));
+%!   assert (get (hs, "specularstrength"), get (0, "defaultsurfacespecularstrength"));
+%!   assert (get (hp, "specularexponent"), get (0, "defaultpatchspecularexponent"));
+%!   assert (get (hs, "specularexponent"), get (0, "defaultsurfacespecularexponent"));
+%!   assert (get (hp, "specularcolorreflectance"), get (0, "defaultpatchspecularcolorreflectance"));
+%!   assert (get (hs, "specularcolorreflectance"), get (0, "defaultsurfacespecularcolorreflectance"));
+%!   material ([0.5 0.6 0.7 20 0.8])
+%!   assert (get (hp, "ambientstrength"), 0.5);
+%!   assert (get (hs, "ambientstrength"), 0.5);
+%!   assert (get (hp, "diffusestrength"), 0.6);
+%!   assert (get (hs, "diffusestrength"), 0.6);
+%!   assert (get (hp, "specularstrength"), 0.7);
+%!   assert (get (hs, "specularstrength"), 0.7);
+%!   assert (get (hp, "specularexponent"), 20);
+%!   assert (get (hs, "specularexponent"), 20);
+%!   assert (get (hp, "specularcolorreflectance"), 0.8);
+%!   assert (get (hs, "specularcolorreflectance"), 0.8);
+%!   material (hp, "shiny")
+%!   assert (get (hp, "ambientstrength"), 0.3);
+%!   assert (get (hs, "ambientstrength"), 0.5);
+%!   assert (get (hp, "diffusestrength"), 0.6);
+%!   assert (get (hs, "diffusestrength"), 0.6);
+%!   assert (get (hp, "specularstrength"), 0.9);
+%!   assert (get (hs, "specularstrength"), 0.7);
+%!   assert (get (hp, "specularexponent"), 20);
+%!   assert (get (hs, "specularexponent"), 20);
+%!   assert (get (hp, "specularcolorreflectance"), 1.0);
+%!   assert (get (hs, "specularcolorreflectance"), 0.8);
+%!   material (hf, "metal")
+%!   assert (get (hp, "ambientstrength"), 0.3);
+%!   assert (get (hs, "ambientstrength"), 0.3);
+%!   assert (get (hp, "diffusestrength"), 0.3);
+%!   assert (get (hs, "diffusestrength"), 0.3);
+%!   assert (get (hp, "specularstrength"), 1.0);
+%!   assert (get (hs, "specularstrength"), 1.0);
+%!   assert (get (hp, "specularexponent"), 25);
+%!   assert (get (hs, "specularexponent"), 25);
+%!   assert (get (hp, "specularcolorreflectance"), 0.5);
+%!   assert (get (hs, "specularcolorreflectance"), 0.5);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
+%!test
+%! mtypes = material ();
+%! assert (iscell (mtypes));
+%! assert (size (mtypes, 2), 1);
+%! assert (all (cellfun (@ischar, mtypes)));
+
+%!test
+%! refl_props = material ("metal");
+%! assert (refl_props, {0.3, 0.3, 1, 25, 0.5})
+
+## Test input validation
+%!error <Invalid call to material> material ()
+%!error <Invalid call to material> material (-1, 2, 3)
+%!error <Invalid call to material> a = material (-1)
+%!error <Invalid call to material> a = material (-1, 2)
+%!error <Invalid call to material> a = material ({})
+%!error <Invalid call to material> a = material ([.3 .4 .5])
+%!error <Invalid call to material> [a, b] = material ()
+%!error <first argument must be a list of handles> material (-1, "metal")
+%!error <unknown material type 'foo'> material foo
+%!error <incorrect number of elements in material vector> material (-1)
+%!error <incorrect number of elements in material vector> material ([1 2 3 4 5 6])
+%!error <MTYPE must be a named material or a vector> material ({})
+
+%!error <Invalid call to material.> 
+%! hf = figure ("visible", "off");
+%! unwind_protect
+%!   material (hf);
+%! unwind_protect_cleanup
+%!   close (hf);
+%! end_unwind_protect
+
--- a/scripts/plot/appearance/module.mk	Wed Aug 10 00:56:51 2016 +0100
+++ b/scripts/plot/appearance/module.mk	Mon Jul 18 17:46:05 2016 +0200
@@ -22,6 +22,7 @@
   scripts/plot/appearance/hidden.m \
   scripts/plot/appearance/legend.m \
   scripts/plot/appearance/lighting.m \
+  scripts/plot/appearance/material.m \
   scripts/plot/appearance/orient.m \
   scripts/plot/appearance/pbaspect.m \
   scripts/plot/appearance/shading.m \
--- a/scripts/plot/draw/light.m	Wed Aug 10 00:56:51 2016 +0100
+++ b/scripts/plot/draw/light.m	Mon Jul 18 17:46:05 2016 +0200
@@ -59,7 +59,7 @@
 ##
 ## Optionally, the handle to the light object is returned in @var{h}.
 ##
-## @seealso{get, set, patch, surface, lighting}
+## @seealso{get, set, patch, surface, lighting, material}
 ## @end deftypefn
 
 ## Author: mmuetzel