1######################################################################## 2## 3## Copyright (C) 2009-2021 The Octave Project Developers 4## 5## See the file COPYRIGHT.md in the top-level directory of this 6## distribution or <https://octave.org/copyright/>. 7## 8## This file is part of Octave. 9## 10## Octave is free software: you can redistribute it and/or modify it 11## under the terms of the GNU General Public License as published by 12## the Free Software Foundation, either version 3 of the License, or 13## (at your option) any later version. 14## 15## Octave is distributed in the hope that it will be useful, but 16## WITHOUT ANY WARRANTY; without even the implied warranty of 17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18## GNU General Public License for more details. 19## 20## You should have received a copy of the GNU General Public License 21## along with Octave; see the file COPYING. If not, see 22## <https://www.gnu.org/licenses/>. 23## 24######################################################################## 25 26## -*- texinfo -*- 27## @deftypefn {} {} surfl (@var{z}) 28## @deftypefnx {} {} surfl (@var{x}, @var{y}, @var{z}) 29## @deftypefnx {} {} surfl (@dots{}, @var{lsrc}) 30## @deftypefnx {} {} surfl (@var{x}, @var{y}, @var{z}, @var{lsrc}, @var{P}) 31## @deftypefnx {} {} surfl (@dots{}, "cdata") 32## @deftypefnx {} {} surfl (@dots{}, "light") 33## @deftypefnx {} {} surfl (@var{hax}, @dots{}) 34## @deftypefnx {} {@var{h} =} surfl (@dots{}) 35## Plot a 3-D surface using shading based on various lighting models. 36## 37## The surface mesh is plotted using shaded rectangles. The vertices of the 38## rectangles [@var{x}, @var{y}] are typically the output of @code{meshgrid}. 39## over a 2-D rectangular region in the x-y plane. @var{z} determines the 40## height above the plane of each vertex. If only a single @var{z} matrix is 41## given, then it is plotted over the meshgrid 42## @code{@var{x} = 1:columns (@var{z}), @var{y} = 1:rows (@var{z})}. 43## Thus, columns of @var{z} correspond to different @var{x} values and rows 44## of @var{z} correspond to different @var{y} values. 45## 46## The default lighting mode @qcode{"cdata"}, changes the cdata property of the 47## surface object to give the impression of a lighted surface. 48## 49## The alternate mode @qcode{"light"} creates a light object to illuminate the 50## surface. 51## 52## The light source location may be specified using @var{lsrc} which can be 53## a 2-element vector [azimuth, elevation] in degrees, or a 3-element vector 54## [lx, ly, lz]. The default value is rotated 45 degrees counterclockwise to 55## the current view. 56## 57## The material properties of the surface can specified using a 4-element 58## vector @var{P} = [@var{AM} @var{D} @var{SP} @var{exp}] which defaults to 59## @var{p} = [0.55 0.6 0.4 10]. 60## 61## @table @asis 62## @item @qcode{"AM"} strength of ambient light 63## 64## @item @qcode{"D"} strength of diffuse reflection 65## 66## @item @qcode{"SP"} strength of specular reflection 67## 68## @item @qcode{"EXP"} specular exponent 69## @end table 70## 71## If the first argument @var{hax} is an axes handle, then plot into this axes, 72## rather than the current axes returned by @code{gca}. 73## 74## The optional return value @var{h} is a graphics handle to the created 75## surface object. 76## 77## Example: 78## 79## @example 80## @group 81## colormap (bone (64)); 82## surfl (peaks); 83## shading interp; 84## @end group 85## @end example 86## @seealso{diffuse, specular, surf, shading, colormap, caxis} 87## @end deftypefn 88 89function h = surfl (varargin) 90 91 [hax, varargin, nargin] = __plt_get_axis_arg__ ("surfl", varargin{:}); 92 93 if (nargin == 0) 94 print_usage (); 95 endif 96 97 ## Check for lighting type. 98 use_cdata = true; 99 if (ischar (varargin{end})) 100 switch (tolower (varargin{end})) 101 case "light" 102 use_cdata = false; 103 case "cdata" 104 use_cdata = true; 105 otherwise 106 error ("surfl: unknown lighting method"); 107 endswitch 108 varargin(end) = []; 109 endif 110 111 ## Check for reflection properties argument. 112 ## 113 ## r = [ambient light strength, 114 ## diffuse reflection strength, 115 ## specular reflection strength, 116 ## specular shine] 117 if (isnumeric (varargin{end}) && isvector (varargin{end}) 118 && (numel (varargin{end}) == 4)) 119 r = varargin{end}; 120 varargin(end) = []; 121 else 122 ## Default values. 123 r = [0.55, 0.6, 0.4, 10]; 124 endif 125 126 ## Check for light vector (lv) argument. 127 have_lv = false; 128 if (isnumeric (varargin{end}) && isvector (varargin{end})) 129 len = numel (varargin{end}); 130 lastarg = varargin{end}; 131 if (len == 3) 132 lv = lastarg; 133 varargin(end) = []; 134 have_lv = true; 135 elseif (len == 2) 136 [lv(1), lv(2), lv(3)] = sph2cart ((lastarg(1) - 90) * pi/180, 137 lastarg(2) * pi/180, 138 1.0); 139 varargin(end) = []; 140 have_lv = true; 141 endif 142 endif 143 144 oldfig = []; 145 if (! isempty (hax)) 146 oldfig = get (0, "currentfigure"); 147 endif 148 unwind_protect 149 hax = newplot (hax); 150 151 htmp = surface (varargin{:}); 152 if (! ishold ()) 153 set (hax, "view", [-37.5, 30], 154 "xgrid", "on", "ygrid", "on", "zgrid", "on"); 155 endif 156 157 ## Get view vector (vv). 158 [az, el] = view (); 159 vv = sph2cart ((az - 90) * pi/180.0, el * pi/180.0, 1.0); 160 161 if (! have_lv) 162 ## Calculate light vector (lv) from view vector. 163 phi = pi / 4; # 45 degrees 164 R = [cos(phi), -sin(phi), 0; 165 sin(phi), cos(phi), 0; 166 0, 0, 1]; 167 lv = (R * vv.').'; 168 endif 169 170 if (use_cdata) 171 set (hax, "clim", [0 1]); 172 173 __update_normals__ (htmp); 174 vn = get (htmp, "vertexnormals"); 175 dar = get (hax, "dataaspectratio"); 176 vn(:,:,1) *= dar(1); 177 vn(:,:,2) *= dar(2); 178 vn(:,:,3) *= dar(3); 179 180 ## Normalize vn. 181 vn ./= repmat (sqrt (sumsq (vn, 3)), [1, 1, 3]); 182 [nr, nc] = size (get (htmp, "zdata")); 183 184 ## Ambient, diffuse, and specular term. 185 cdata = ( r(1) * ones (nr, nc) 186 + r(2) * diffuse (vn(:,:,1), vn(:,:,2), vn(:,:,3), lv) 187 + r(3) * specular (vn(:,:,1), vn(:,:,2), vn(:,:,3), lv, vv, r(4))); 188 cdata ./= sum (r(1:3)); 189 190 set (htmp, "cdata", cdata); 191 else 192 light (hax, "position", lv); 193 set (htmp, "ambientstrength", r(1), "diffusestrength", r(2), ... 194 "specularstrength", r(3), "specularexponent", r(4)); 195 endif 196 197 unwind_protect_cleanup 198 if (! isempty (oldfig)) 199 set (0, "currentfigure", oldfig); 200 endif 201 end_unwind_protect 202 203 if (nargout > 0) 204 h = htmp; 205 endif 206 207endfunction 208 209 210%!demo 211%! clf; 212%! [X,Y,Z] = sombrero (); 213%! colormap (copper (64)); 214%! surfl (X,Y,Z); 215%! shading interp; 216%! title ("surfl() with defaults"); 217 218%!demo 219%! clf; 220%! [X,Y,Z] = sombrero (); 221%! colormap (copper (64)); 222%! surfl (X,Y,Z, [62.50,30], [0.2 0.6 0.4 25]); 223%! shading interp; 224%! title ("surfl() with lighting vector and material properties"); 225 226%!demo 227%! clf; 228%! [X, Y] = meshgrid (-3:1/8:3); 229%! Z = peaks (X, Y); 230%! surfl (X, Y, Z, "light"); 231%! shading interp; 232%! title ("surfl() with light object"); 233