changeset 29400:4d747b196935

fill3.m: Add new function. * script/plot/draw/fill3.m: Add new function. * script/plot/draw/module.mk: Add new file to build system. * doc/interpreter/plot.txi: Add docstring to manual. Mention new function in listings. * script/plot/draw/fill.m: Add new function to see also list. * NEWS: Add note about new function.
author Markus Mützel <markus.muetzel@gmx.de>
date Sun, 28 Feb 2021 12:15:27 +0100
parents f91ff3f7f5dc
children b03104e38964
files NEWS doc/interpreter/plot.txi scripts/plot/draw/fill.m scripts/plot/draw/fill3.m scripts/plot/draw/module.mk
diffstat 5 files changed, 274 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Sat Feb 27 16:05:54 2021 +0100
+++ b/NEWS	Sun Feb 28 12:15:27 2021 +0100
@@ -191,6 +191,7 @@
 * `cospi`
 * `getpixelposition`
 * `endsWith`
+* `fill3`
 * `jsondecode`
 * `jsonencode`
 * `listfonts`
--- a/doc/interpreter/plot.txi	Sat Feb 27 16:05:54 2021 +0100
+++ b/doc/interpreter/plot.txi	Sun Feb 28 12:15:27 2021 +0100
@@ -281,6 +281,8 @@
 
 @DOCSTRING(fill)
 
+@DOCSTRING(fill3)
+
 @DOCSTRING(comet)
 
 @DOCSTRING(comet3)
@@ -1208,16 +1210,17 @@
 limited to the following functions: The functions @code{plot} and @code{plot3}
 return a handle pointing to an object of type @code{line}.  The function
 @code{subplot} returns a handle pointing to an object of type @code{axes}.
-The functions @code{fill}, @code{trimesh}, and @code{trisurf} return a handle
-pointing to an object of type patch.  The function @code{scatter3} returns a
-handle to an object of type scatter.  The functions @code{slice}, @code{surf},
-@code{surfl}, @code{mesh}, @code{meshz}, @code{pcolor}, and @code{waterfall}
-each return a handle of type surface.  The function @code{camlight} returns a
-handle to an object of type light.  The functions @code{area}, @code{bar},
-@code{barh}, @code{contour}, @code{contourf}, @code{contour3}, @code{surfc},
-@code{meshc}, @code{errorbar}, @code{quiver}, @code{quiver3}, @code{stair},
-@code{stem}, @code{stem3} each return a handle to a complex data structure as
-documented in @ref{XREFdatasources,,Data Sources}.
+The functions @code{fill}, @code{fill3}, @code{trimesh}, and @code{trisurf}
+return a handle pointing to an object of type patch.  The function
+@code{scatter3} returns a handle to an object of type scatter.  The functions
+@code{slice}, @code{surf}, @code{surfl}, @code{mesh}, @code{meshz},
+@code{pcolor}, and @code{waterfall} each return a handle of type surface.  The
+function @code{camlight} returns a handle to an object of type light.  The
+functions @code{area}, @code{bar}, @code{barh}, @code{contour},
+@code{contourf}, @code{contour3}, @code{surfc}, @code{meshc}, @code{errorbar},
+@code{quiver}, @code{quiver3}, @code{stair}, @code{stem}, @code{stem3} each
+return a handle to a complex data structure as documented in
+@ref{XREFdatasources,,Data Sources}.
 
 The graphics objects are arranged in a hierarchy:
 
@@ -1370,7 +1373,7 @@
 Alternatively, the easier way is to call a high-level graphics routine which
 will both create the plot and then populate it with low-level graphics objects.
 Instead of calling @code{line}, use @code{plot}.  Or use @code{surf} instead of
-@code{surface}.  Or use @code{fill} instead of @code{patch}.
+@code{surface}.  Or use @code{fill} or @code{fill3} instead of @code{patch}.
 
 @DOCSTRING(axes)
 
--- a/scripts/plot/draw/fill.m	Sat Feb 27 16:05:54 2021 +0100
+++ b/scripts/plot/draw/fill.m	Sun Feb 28 12:15:27 2021 +0100
@@ -70,7 +70,7 @@
 ## @end group
 ## @end example
 ##
-## @seealso{patch, caxis, colormap}
+## @seealso{patch, fill3, caxis, colormap}
 ## @end deftypefn
 
 function h = fill (varargin)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/draw/fill3.m	Sun Feb 28 12:15:27 2021 +0100
@@ -0,0 +1,257 @@
+########################################################################
+##
+## Copyright (C) 2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## 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  {} {} fill3 (@var{x}, @var{y}, @var{z}, @var{c})
+## @deftypefnx {} {} fill3 (@var{x1}, @var{y1}, @var{z1}, @var{c1}, @var{x2}, @var{y2}, @var{z2}, @var{c2})
+## @deftypefnx {} {} fill3 (@dots{}, @var{prop}, @var{val})
+## @deftypefnx {} {} fill3 (@var{hax}, @dots{})
+## @deftypefnx {} {@var{h} =} fill3 (@dots{})
+## Create one or more filled 3-D polygons.
+##
+## The inputs @var{x}, @var{y} and @var{z} are the coordinates of the polygon
+## vertices.  If the inputs are matrices then the rows represent different
+## vertices and each column produces a different polygon.  @code{fill3} will
+## close any open polygons before plotting.
+##
+## The input @var{c} determines the color of the polygon.  The simplest form
+## is a single color specification such as a @code{plot} format or an
+## RGB-triple.  In this case the polygon(s) will have one unique color.  If
+## @var{c} is a vector or matrix then the color data is first scaled using
+## @code{caxis} and then indexed into the current colormap.  A row vector will
+## color each polygon (a column from matrices @var{x}, @var{y} and @var{z})
+## with a single computed color.  A matrix @var{c} of the same size as @var{x},
+## @var{y} and @var{z} will compute the color of each vertex and then
+## interpolate the face color between the vertices.
+##
+## Multiple property/value pairs for the underlying patch object may be
+## specified, but they must appear in pairs.
+##
+## If the first argument @var{hax} is an axes handle, then plot into this axes,
+## rather than the current axes returned by @code{gca}.
+##
+## The optional return value @var{h} is a vector of graphics handles to
+## the created patch objects.
+##
+## Example: oblique red rectangle
+##
+## @example
+## @group
+## vertices = [0 0 0
+##             1 1 0
+##             1 1 1
+##             0 0 1];
+## fill3 (vertices(:,1), vertices(:,2), vertices(:,3), "r");
+## axis ([-0.5 1.5, -0.5 1.5, -0.5 1.5]);
+## axis ("equal");
+## grid ("on");
+## view (-80, 25);
+## @end group
+## @end example
+##
+## @seealso{patch, fill, caxis, colormap}
+## @end deftypefn
+
+function h = fill3 (varargin)
+
+  [hax, varargin] = __plt_get_axis_arg__ ("fill3", varargin{:});
+
+  hlist = [];
+  iargs = __find_patches__ (varargin{:});
+
+  opts = {};
+  if (numel (varargin) > iargs(end) + 3)
+    opts = varargin(iargs(end)+4 : end);
+  endif
+
+  if (! all (cellfun (@(x) iscolorspec (x), varargin(iargs + 3))))
+    print_usage ();
+  endif
+
+  oldfig = [];
+  if (! isempty (hax))
+    oldfig = get (0, "currentfigure");
+  endif
+  unwind_protect
+    hax = newplot (hax);
+    old_nxtplt = get (hax, "nextplot");
+    if (! ishold ())
+      set (hax, "box", "on");
+    endif
+    unwind_protect
+      set (hax, "nextplot", "add");
+
+      for i = 1 : length (iargs)
+        x = varargin{iargs(i)};
+        y = varargin{iargs(i) + 1};
+        z = varargin{iargs(i) + 2};
+        cdata = varargin{iargs(i) + 3};
+
+        if (! size_equal (x, y, z))
+          if (rows (x) != rows (y) || rows (x) != rows (z))
+            error ("fill3: X,Y and Z must have same number of rows");
+          endif
+
+          num_cols = max ([columns(x), columns(y), columns(z)]);
+          if (iscolumn (x))
+            x = repmat (x, [1, num_cols]);
+          end
+          if (iscolumn (y))
+            y = repmat (y, [1, num_cols]);
+          end
+          if (iscolumn (z))
+            z = repmat (z, [1, num_cols]);
+          end
+        endif
+
+        if (isrow (x))
+          x = x(:);
+        endif
+        if (isrow (y))
+          y = y(:);
+        endif
+        if (isrow (z))
+          z = z(:);
+        endif
+
+        if (ischar (cdata) || isequal (size (cdata), [1, 3]))
+          one_color = true;
+        else
+          one_color = false;
+        endif
+
+        ## For Matlab compatibility, replicate cdata to match size of data
+        if (! one_color && iscolumn (cdata))
+          sz = size (x);
+          if (all (sz > 1))
+            cdata = repmat (cdata, [1, sz(2)]);
+          endif
+        endif
+
+        ## For Matlab compatibility, return 1 patch object for each column
+        for j = 1 : columns (x)
+          if (one_color)
+            [htmp, err] = __patch__ (hax, x(:,j), y(:,j), z(:,j), ...
+                                     cdata, opts{:});
+          else
+            [htmp, err] = __patch__ (hax, x(:,j), y(:,j), z(:,j), ...
+                                     cdata(:,j), opts{:});
+          endif
+          if (err)
+            print_usage ();
+          endif
+          hlist(end+1, 1) = htmp;
+        endfor
+      endfor
+
+      view (hax, 3);
+
+    unwind_protect_cleanup
+      if (strcmp (old_nxtplt, "replace"))
+        set (hax, "nextplot", old_nxtplt);
+      endif
+    end_unwind_protect
+
+  unwind_protect_cleanup
+    if (! isempty (oldfig))
+      set (0, "currentfigure", oldfig);
+    endif
+  end_unwind_protect
+
+  if (nargout > 0)
+    h = hlist;
+  endif
+
+endfunction
+
+function iargs = __find_patches__ (varargin)
+  iargs = 1:4:nargin;
+  optidx = find (! cellfun (@isnumeric, varargin(iargs)), 1);
+  iargs(optidx:end) = [];
+endfunction
+
+function retval = iscolorspec (arg)
+
+  retval = false;
+  if (ischar (arg))
+    persistent colors = {"y", "yellow", "r", "red", "m", "magenta", ...
+                         "c", "cyan", "g", "green", "b", "blue", ...
+                         "w", "white", "k", "black"};
+    if (any (strcmpi (arg, colors)))
+      retval = true;
+    endif
+  elseif (isnumeric (arg))
+    ## Assume any numeric argument is correctly formatted cdata.
+    ## Let patch worry about the multple different input formats.
+    retval = true;
+  endif
+
+endfunction
+
+
+%!demo
+%! clf;
+%! t1 = (1/16:1/8:1) * 2*pi;
+%! t2 = ((1/16:1/8:1) + 1/32) * 2*pi;
+%! x1 = sin (t1) - 0.8;
+%! y1 = cos (t1);
+%! z1 = sin (t1);
+%! x2 = sin (t2) + 0.8;
+%! y2 = cos (t2);
+%! z2 = sin (t2);
+%! h = fill3 (x1,y1,z1,"r", x2,y2,z2,"g");
+%! title ({"fill3() function"; "cdata specified with string"});
+%! grid ("on");
+
+%!demo
+%! clf;
+%! t1 = (1/16:1/8:1) * 2*pi;
+%! t2 = ((1/16:1/8:1) + 1/32) * 2*pi;
+%! x1 = sin (t1) - 0.8;
+%! y1 = cos (t1);
+%! z1 = sin (t1);
+%! x2 = sin (t2) + 0.8;
+%! y2 = cos (t2);
+%! z2 = sin (t2);
+%! h = fill3 (x1,y1,z1,1, x2,y2,z2,2);
+%! title ({"fill3() function"; 'cdata = row vector produces FaceColor = "flat"'});
+%! grid ("on");
+
+%!demo
+%! clf;
+%! x = [0 0
+%!      1 0.5
+%!      1 0.5
+%!      0 0];
+%! y = [0 0
+%!      0 0
+%!      1 0.5
+%!      1 0.5];
+%! z = y;
+%! z(:,2) += 1e-4;
+%! c = [1 2 3 4]';
+%! fill3 (x, y, z, [c c]);
+%! title ({"fill3() function"; 'cdata = column vector produces FaceColor = "interp"'});
+%! grid ("on");
--- a/scripts/plot/draw/module.mk	Sat Feb 27 16:05:54 2021 +0100
+++ b/scripts/plot/draw/module.mk	Sun Feb 28 12:15:27 2021 +0100
@@ -49,6 +49,7 @@
   %reldir%/ezsurfc.m \
   %reldir%/feather.m \
   %reldir%/fill.m \
+  %reldir%/fill3.m \
   %reldir%/fplot.m \
   %reldir%/hist.m \
   %reldir%/isocaps.m \