view scripts/plot/surfnorm.m @ 14237:11949c9795a0

Revamp %!demos in m-files to use Octave coding conventions on spacing, etc. Add clf() to all demos using plot features to get reproducibility. Use 64 as input to all colormaps (jet (64)) to get reproducibility. * bicubic.m, cell2mat.m, celldisp.m, cplxpair.m, interp1.m, interp2.m, interpft.m, interpn.m, profile.m, profshow.m, convhull.m, delaunay.m, griddata.m, inpolygon.m, voronoi.m, autumn.m, bone.m, contrast.m, cool.m, copper.m, flag.m, gmap40.m, gray.m, hot.m, hsv.m, image.m, imshow.m, jet.m, ocean.m, pink.m, prism.m, rainbow.m, spring.m, summer.m, white.m, winter.m, condest.m, onenormest.m, axis.m, clabel.m, colorbar.m, comet.m, comet3.m, compass.m, contour.m, contour3.m, contourf.m, cylinder.m, daspect.m, ellipsoid.m, errorbar.m, ezcontour.m, ezcontourf.m, ezmesh.m, ezmeshc.m, ezplot.m, ezplot3.m, ezpolar.m, ezsurf.m, ezsurfc.m, feather.m, fill.m, fplot.m, grid.m, hold.m, isosurface.m, legend.m, loglog.m, loglogerr.m, pareto.m, patch.m, pbaspect.m, pcolor.m, pie.m, pie3.m, plot3.m, plotmatrix.m, plotyy.m, polar.m, quiver.m, quiver3.m, rectangle.m, refreshdata.m, ribbon.m, rose.m, scatter.m, scatter3.m, semilogx.m, semilogxerr.m, semilogy.m, semilogyerr.m, shading.m, slice.m, sombrero.m, stairs.m, stem.m, stem3.m, subplot.m, surf.m, surfc.m, surfl.m, surfnorm.m, text.m, title.m, trimesh.m, triplot.m, trisurf.m, uigetdir.m, uigetfile.m, uimenu.m, uiputfile.m, waitbar.m, xlim.m, ylim.m, zlim.m, mkpp.m, pchip.m, polyaffine.m, spline.m, bicgstab.m, cgs.m, gplot.m, pcg.m, pcr.m, treeplot.m, strtok.m, demo.m, example.m, rundemos.m, speed.m, test.m, calendar.m, datestr.m, datetick.m, weekday.m: Revamp %!demos to use Octave coding conventions on spacing, etc.
author Rik <octave@nomad.inbox5.com>
date Fri, 20 Jan 2012 12:59:53 -0800
parents ba7a26030214
children c4fa5e0b6193
line wrap: on
line source

## Copyright (C) 2007-2012 David Bateman
##
## 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  {Function File} {} surfnorm (@var{x}, @var{y}, @var{z})
## @deftypefnx {Function File} {} surfnorm (@var{z})
## @deftypefnx {Function File} {[@var{nx}, @var{ny}, @var{nz}] =} surfnorm (@dots{})
## @deftypefnx {Function File} {} surfnorm (@var{h}, @dots{})
## Find the vectors normal to a meshgridded surface.  The meshed gridded
## surface is defined by @var{x}, @var{y}, and @var{z}.  If @var{x} and
## @var{y} are not defined, then it is assumed that they are given by
##
## @example
## @group
## [@var{x}, @var{y}] = meshgrid (1:size(@var{z}, 1),
##                      1:size(@var{z}, 2));
## @end group
## @end example
##
## If no return arguments are requested, a surface plot with the normal
## vectors to the surface is plotted.  Otherwise the components of the normal
## vectors at the mesh gridded points are returned in @var{nx}, @var{ny},
## and @var{nz}.
##
## The normal vectors are calculated by taking the cross product of the
## diagonals of each of the quadrilaterals in the meshgrid to find the
## normal vectors of the centers of these quadrilaterals.  The four nearest
## normal vectors to the meshgrid points are then averaged to obtain the
## normal to the surface at the meshgridded points.
##
## An example of the use of @code{surfnorm} is
##
## @example
## surfnorm (peaks (25));
## @end example
## @seealso{surf, quiver3}
## @end deftypefn

function [Nx, Ny, Nz] = surfnorm (varargin)

  [h, varargin, nargin] = __plt_get_axis_arg__ ((nargout != 0), "surfnorm",
                                                varargin{:});

  if (nargin != 1 && nargin != 3)
    print_usage ();
  endif

  if (nargin == 1)
    z = varargin{1};
    [x, y] = meshgrid (1:size(z,1), 1:size(z,2));
    ioff = 2;
  else
    x = varargin{1};
    y = varargin{2};
    z = varargin{3};
    ioff = 4;
  endif

  if (!ismatrix (z) || isvector (z) || isscalar (z))
    error ("surfnorm: Z argument must be a matrix");
  endif
  if (! size_equal (x, y, z))
    error ("surfnorm: X, Y, and Z must have the same dimensions");
  endif

  ## Make life easier, and avoid having to do the extrapolation later, do
  ## a simpler linear extrapolation here. This is approximative, and works
  ## badly for closed surfaces like spheres.
  xx = [2 .* x(:,1) - x(:,2), x, 2 .* x(:,end) - x(:,end-1)];
  xx = [2 .* xx(1,:) - xx(2,:); xx; 2 .* xx(end,:) - xx(end-1,:)];
  yy = [2 .* y(:,1) - y(:,2), y, 2 .* y(:,end) - y(:,end-1)];
  yy = [2 .* yy(1,:) - yy(2,:); yy; 2 .* yy(end,:) - yy(end-1,:)];
  zz = [2 .* z(:,1) - z(:,2), z, 2 .* z(:,end) - z(:,end-1)];
  zz = [2 .* zz(1,:) - zz(2,:); zz; 2 .* zz(end,:) - zz(end-1,:)];

  u.x = xx(1:end-1,1:end-1) - xx(2:end,2:end);
  u.y = yy(1:end-1,1:end-1) - yy(2:end,2:end);
  u.z = zz(1:end-1,1:end-1) - zz(2:end,2:end);
  v.x = xx(1:end-1,2:end) - xx(2:end,1:end-1);
  v.y = yy(1:end-1,2:end) - yy(2:end,1:end-1);
  v.z = zz(1:end-1,2:end) - zz(2:end,1:end-1);

  c = cross ([u.x(:), u.y(:), u.z(:)], [v.x(:), v.y(:), v.z(:)]);
  w.x = reshape (c(:,1), size(u.x));
  w.y = reshape (c(:,2), size(u.y));
  w.z = reshape (c(:,3), size(u.z));

  ## Create normal vectors as mesh vectices from normals at mesh centers
  nx = (w.x(1:end-1,1:end-1) + w.x(1:end-1,2:end) +
        w.x(2:end,1:end-1) + w.x(2:end,2:end)) ./ 4;
  ny = (w.y(1:end-1,1:end-1) + w.y(1:end-1,2:end) +
        w.y(2:end,1:end-1) + w.y(2:end,2:end)) ./ 4;
  nz = (w.z(1:end-1,1:end-1) + w.z(1:end-1,2:end) +
        w.z(2:end,1:end-1) + w.z(2:end,2:end)) ./ 4;

  ## Normalize the normal vectors
  len = sqrt (nx.^2 + ny.^2 + nz.^2);
  nx = nx ./ len;
  ny = ny ./ len;
  nz = nz ./ len;

  if (nargout == 0)
    oldh = gca ();
    unwind_protect
      axes (h);
      newplot ();
      surf (x, y, z, varargin{ioff:end});
      old_hold_state = get (h, "nextplot");
      unwind_protect
        set (h, "nextplot", "add");
        plot3 ([x(:)'; x(:).' + nx(:).' ; NaN(size(x(:).'))](:),
               [y(:)'; y(:).' + ny(:).' ; NaN(size(y(:).'))](:),
               [z(:)'; z(:).' + nz(:).' ; NaN(size(z(:).'))](:),
               varargin{ioff:end});
      unwind_protect_cleanup
        set (h, "nextplot", old_hold_state);
      end_unwind_protect
    unwind_protect_cleanup
      axes (oldh);
    end_unwind_protect
  else
    Nx = nx;
    Ny = ny;
    Nz = nz;
  endif

endfunction


%!demo
%! clf;
%! colormap (jet (64));
%! [x, y, z] = peaks (10);
%! surfnorm (x, y, z);

%!demo
%! clf;
%! surfnorm (peaks (10));

%!demo
%! clf;
%! surfnorm (peaks (32));
%! shading interp;