changeset 7020:e31f12bb9194

[project @ 2007-10-13 05:13:28 by dbateman]
author dbateman
date Sat, 13 Oct 2007 05:13:29 +0000
parents 4270ded9ddc6
children 0b91144f9533
files scripts/ChangeLog scripts/plot/__go_draw_axes__.m scripts/plot/__patch__.m scripts/plot/fill.m scripts/plot/patch.m src/ChangeLog src/graphics.cc src/graphics.h.in
diffstat 8 files changed, 480 insertions(+), 179 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog	Sat Oct 13 01:42:21 2007 +0000
+++ b/scripts/ChangeLog	Sat Oct 13 05:13:29 2007 +0000
@@ -1,3 +1,15 @@
+2007-10-13  David Bateman  <dbateman@free.fr>
+
+	* plot/__patch__.m: Allow multiple patches to be defined and
+	return a single patch object. Allow Faces/Vertices form of
+	patch. Flag failure so the patch can call print_usage.
+	* plot/patch.m: Update help string for Faces/Vertices
+	call. Respect the fail flag returned by __patch__. Add demo code
+	that tests the functionality of patch.
+	* plot/__go_draw_axes__.m: Treat an array of patches in a single
+	patch object.
+	* plot/fill.m: New function.
+
 2007-10-12  John W. Eaton  <jwe@octave.org>
 
 	* Change copyright notices in all files that are part of Octave to
--- a/scripts/plot/__go_draw_axes__.m	Sat Oct 13 01:42:21 2007 +0000
+++ b/scripts/plot/__go_draw_axes__.m	Sat Oct 13 05:13:29 2007 +0000
@@ -426,117 +426,149 @@
 	 nd = 2;
          cmap = parent_figure_obj.colormap;
          clim = axis_obj.clim;
-	 data_idx++;
-	 is_image_data(data_idx) = false;
-	 parametric(data_idx) = false;
-         titlespec{data_idx} = "title \"\"";
-	 usingclause{data_idx} = "";
-         if (isfield (obj, "facecolor") && isfield (obj, "cdata"))
-           if (strncmp (obj.facecolor, "none", 4))
-	     color = [1, 1, 1];
-           elseif (strncmp (obj.facecolor, "flat", 4))
-             r = 1 + round ((size (cmap, 1) - 1) * (obj.cdata - clim(1))/(clim(2) - clim(1)));
-             r = max (1, min (r, size (cmap, 1)));
-	     color = cmap(r,:);
-           elseif (strncmp (obj.facecolor, "interp", 6))
-             warning ("\"interp\" not supported, using 1st entry of cdata")
-             r = 1 + round ((size (cmap, 1) - 1) * obj.cdata(1));
-             r = max (1, min (r, size (cmap, 1)));
-	     color = cmap(r,:);
-           else
-	     color = obj.facecolor;
-           endif
-         else
-           color = [1, 0, 0];
-         endif
+	 [nr, nc] = size (obj.xdata);
+
+	 for i = 1 : nc
+	   xcol = obj.xdata(:,i);
+	   ycol = obj.ydata(:,i);
+
+	   if (xautoscale)
+             [xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, xcol);
+	   endif
+	   if (yautoscale)
+	     [ymin, ymax, yminp] = get_data_limits (ymin, ymax, yminp, ycol);
+	   endif
+
+	   if (! isnan (xcol) && ! isnan (ycol))
+	     ## Is the patch closed or not
+	     data_idx++;
+	     is_image_data(data_idx) = false;
+	     parametric(data_idx) = false;
+             titlespec{data_idx} = "title \"\"";
+	     usingclause{data_idx} = "";
+             if (isfield (obj, "facecolor") && isfield (obj, "cdata"))
+               if (strncmp (obj.facecolor, "none", 4))
+		 color = [1, 1, 1];
 
-	 if (have_newer_gnuplot)
-	   withclause{data_idx} = sprintf ("with filledcurve lc rgb \"#%02x%02x%02x\"",round (255*color));
-	 else
-	   if (isequal (color, [0,0,0]))
-	     typ = -1;
-	   elseif (isequal (color, [1,0,0]))
-	     typ = 1;
-	   elseif (isequal (color, [0,1,0]))
-	     typ = 2;
-	   elseif (isequal (color, [0,0,1]))
-	     typ = 3;
-	   elseif (isequal (color, [1,0,1]))
-	     typ = 4;
-	   elseif (isequal (color, [0,1,1]))
-	     typ = 5;
-	   elseif (isequal (color, [1,1,1]))
-	     typ = -1;
-	   elseif (isequal (color, [1,1,0]))
-	     typ = 7;
-	   else
-	     typ = -1;
-	   endif
-	   withclause{data_idx} = sprintf ("with filledcurve lt %d", typ);
-	 endif
-
-	 xdat = obj.xdata(:);
-	 ydat = obj.ydata(:);
+               elseif (strncmp (obj.facecolor, "flat", 4) ||
+		       strncmp (obj.facecolor, "interp", 6))
+		 if (ndims (obj.cdata) == 2 && ... 
+		     ((nr > 3 && size (obj.cdata, 2) == nc) ...
+                      || (size (obj.cdata, 1) > 1 && ...
+			  size (obj.cdata, 2) == nc)))
+		   ccol = obj.cdata (:, i);
+		 elseif (ndims (obj.cdata) == 3)
+		   ccol = permute (obj.cdata (:, i, :), [1, 3, 2]);
+		 else
+		   ccol = obj.cdata;
+		 endif
+		 if (strncmp (obj.facecolor, "flat", 4))
+		   if (numel(ccol) == 3)
+		     color = ccol;
+		   else
+		     r = 1 + round ((size (cmap, 1) - 1) * ...
+				    (ccol - clim(1))/(clim(2) - clim(1)));
+		     r = max (1, min (r, size (cmap, 1)));
+		     color = cmap(r, :);
+		   endif
+		 elseif (strncmp (obj.facecolor, "interp", 6))
+		   warning ("\"interp\" not supported, using 1st entry of cdata")
+		   r = 1 + round ((size (cmap, 1) - 1) * ccol(1));
+		   r = max (1, min (r, size (cmap, 1)));
+		   color = cmap(r,:);
+		 endif
+	       else
+		 color = obj.facecolor;
+	       endif
+             else
+	       color = [0, 1, 0];
+             endif
 
-	 if (xautoscale)
-           [xmin, xmax, xminp] = get_data_limits (xmin, xmax, xminp, xdat);
-	 endif
-	 if (yautoscale)
-	   [ymin, ymax, yminp] = get_data_limits (ymin, ymax, yminp, ydat);
-	 endif
-	 data{data_idx} = [xdat, ydat]';
-	 usingclause{data_idx} = "using ($1):($2)";
+	     if (have_newer_gnuplot)
+	       withclause{data_idx} = ...
+	       sprintf ("with filledcurve lc rgb \"#%02x%02x%02x\"", ...
+			round (255*color));
+	     else
+	       if (isequal (color, [0,0,0]))
+		 typ = -1;
+	       elseif (isequal (color, [1,0,0]))
+		 typ = 1;
+	       elseif (isequal (color, [0,1,0]))
+		 typ = 2;
+	       elseif (isequal (color, [0,0,1]))
+		 typ = 3;
+	       elseif (isequal (color, [1,0,1]))
+		 typ = 4;
+	       elseif (isequal (color, [0,1,1]))
+		 typ = 5;
+	       elseif (isequal (color, [1,1,1]))
+		 typ = -1;
+	       elseif (isequal (color, [1,1,0]))
+		 typ = 7;
+	       else
+		 typ = -1;
+	       endif
+	       withclause{data_idx} = sprintf ("with filledcurve lt %d", typ);
+	     endif
+	     data{data_idx} = [xcol, ycol]';
+	     usingclause{data_idx} = "using ($1):($2)";
+	   endif
 
-         ## patch outline
-         data_idx++;
-         is_image_data(data_idx) = false;
-         parametric(data_idx) = false;
-         titlespec{data_idx} = "title \"\"";
-	 usingclause{data_idx} = "";
-         if (isfield (obj, "edgecolor"))
-           if (strncmp (obj.edgecolor, "none", 4))
-             color = [1, 1, 1];
-           elseif (strncmp (obj.edgecolor, "flat", 4))
-             warning ("\"flat\" for edgecolor not supported");
+           ## patch outline
+	   data_idx++;
+           is_image_data(data_idx) = false;
+           parametric(data_idx) = false;
+           titlespec{data_idx} = "title \"\"";
+	   usingclause{data_idx} = "";
+           if (isfield (obj, "edgecolor"))
+             if (strncmp (obj.edgecolor, "none", 4))
+               color = [1, 1, 1];
+             elseif (strncmp (obj.edgecolor, "flat", 4))
+               warning ("\"flat\" for edgecolor not supported");
+               color = [0, 0, 0];
+             elseif (strncmp (obj.edgecolor, "interp", 6))
+               warning ("\"interp\" for edgecolor not supported");
+               color = [0, 0, 0];
+             else
+	       color = obj.edgecolor;
+             endif
+           else
              color = [0, 0, 0];
-           elseif (strncmp (obj.edgecolor, "interp", 6))
-             warning ("\"interp\" for edgecolor not supported");
-             color = [0, 0, 0];
-           else
-	     color = obj.edgecolor;
            endif
-         else
-           color = [0, 0, 0];
-         endif
-	 if (have_newer_gnuplot)
-	   withclause{data_idx} = sprintf ("with lines lc rgb \"#%02x%02x%02x\"",round (255*color));
-	 else
-	   if (isequal (color, [0,0,0]))
-	     typ = -1;
-	   elseif (isequal (color, [1,0,0]))
-	     typ = 1;
-	   elseif (isequal (color, [0,1,0]))
-	     typ = 2;
-	   elseif (isequal (color, [0,0,1]))
-	     typ = 3;
-	   elseif (isequal (color, [1,0,1]))
-	     typ = 4;
-	   elseif (isequal (color, [0,1,1]))
-	     typ = 5;
-	   elseif (isequal (color, [1,1,1]))
-	     typ = -1;
-	   elseif (isequal (color, [1,1,0]))
-	     typ = 7;
+	   if (have_newer_gnuplot)
+	     withclause{data_idx} = ...
+	     sprintf ("with lines lc rgb \"#%02x%02x%02x\"", ...
+		      round (255*color));
 	   else
-	     typ = -1;
+	     if (isequal (color, [0,0,0]))
+	       typ = -1;
+	     elseif (isequal (color, [1,0,0]))
+	       typ = 1;
+	     elseif (isequal (color, [0,1,0]))
+	       typ = 2;
+	     elseif (isequal (color, [0,0,1]))
+	       typ = 3;
+	     elseif (isequal (color, [1,0,1]))
+	       typ = 4;
+	     elseif (isequal (color, [0,1,1]))
+	       typ = 5;
+	     elseif (isequal (color, [1,1,1]))
+	       typ = -1;
+	     elseif (isequal (color, [1,1,0]))
+	       typ = 7;
+	     else
+	       typ = -1;
+	     endif
+	     withclause{data_idx} = sprintf ("with lines lt %d", typ);
 	   endif
-	   withclause{data_idx} = sprintf ("with lines lt %d", typ);
-	 endif
 
-         xdat = [xdat; xdat(1)];
-	 ydat = [ydat; ydat(1)];
-	 data{data_idx} = [xdat, ydat]';
-	 usingclause{data_idx} = "using ($1):($2)";
+	   if (!isnan (xcol) && !isnan (ycol))
+	     data{data_idx} = [[xcol; xcol(1)], [ycol; ycol(1)]]';
+	   else
+	     data{data_idx} = [xcol, ycol]';
+	   endif
+	   usingclause{data_idx} = "using ($1):($2)";
+	 endfor
 
 	case "surface"
 	  data_idx++;
--- a/scripts/plot/__patch__.m	Sat Oct 13 01:42:21 2007 +0000
+++ b/scripts/plot/__patch__.m	Sat Oct 13 05:13:29 2007 +0000
@@ -24,17 +24,19 @@
 
 ## Author: Kai Habel
 
-function h = __patch__ (p, varargin)
-
+function [h, fail] = __patch__ (p, varargin)
+  fail = false;
   if (nargin < 3)
-    print_usage ();
+    fail = true;
+    return;
   endif
 
   iarg = 1;
-  have_x = have_z = have_c = false;
+  have_x = have_z = have_c = have_faces = false;
   if (isnumeric (varargin{1}))
     if (! isnumeric (varargin{2}))
-      print_usage ();
+      fail = true;
+      return;
     endif
 
     x = varargin{1};
@@ -43,14 +45,40 @@
     iarg += 2;
 
     if (nargin > 3 && ndims (varargin{3}) == 2 && ndims (x) == 2
-	&& size (varargin{3}) == size (x))
+	&& isequal (size (varargin{3}), size (x)))
       z = varargin {3};
       have_z = true;
       iarg++;
     endif
+  elseif (ischar (varargin{1}) && (strcmp (tolower (varargin{1}), "faces") || 
+				strcmp (tolower (varargin{1}), "vertices")))
+    if (! isnumeric (varargin{2}))
+      fail = true;
+      return;
+    endif
+    
+    if (strcmp (tolower (varargin{1}), "faces"))
+      faces = varargin{2};
+      if (strcmp (tolower (varargin{3}), "vertices"))
+	vert = varargin{4};
+	have_faces = true;
+      endif
+    elseif (strcmp (tolower (varargin{3}), "vertices"))
+      vert = varargin{2};
+      if (strcmp (tolower (varargin{3}), "faces"))
+	faces = varargin{4};
+	have_faces = true;
+      endif
+    endif
+    if (!have_faces)
+      fail = true;
+      return;
+    else
+      iarg += 4;
+    endif
   endif
 
-  if (have_x && nargin > iarg)
+  if ((have_x || have_faces) && nargin > iarg)
     if (isnumeric (varargin{iarg}))
       c = varargin{iarg};
       have_c = true;
@@ -68,7 +96,8 @@
   endif
 
   if (rem (nargin - iarg, 2) != 0)
-    print_usage ();
+    fail = true;
+    return;
   endif
 
   if (have_x)
@@ -79,77 +108,92 @@
 	z = z(:);
       endif
     endif
-
     [nr, nc] = size (x);
-
-    for i = 1 : nc
-      h = __go_patch__ (p);
-      ax = get (h, "parent");
-      if (have_x)
-	set (h, "xdata", x (:, i), "ydata", y (:, i));
-	if (have_z)
-	  set (h, "zdata", z (:, i));
-	endif
-      endif
-
-      if (have_c)
-	if (ndims (c) == 2 && ((nr > 3 && size (c, 2) == nc)
-			       || (size (c, 1) > 1 && size (c, 2) == nc)))
-	  c2 = c (:, i);
-	elseif (ndims (c) == 3)
-	  c2 = permute (c(:,i,:), [1, 3, 2]);
-	else
-	  c2 = c;
-	endif
-
-	if (ischar (c2))
-	  set (h, "facecolor", c2);
-	elseif (numel (c2) == 1)
-	  if (isnan (c))
-	    set (h, "facecolor", [1, 1, 1]);
-	    set (h, "cdata", c2);
-	  elseif (isnumeric (c2))
-	    ## Have color index.
-	    set (h, "facecolor", "flat");
-	    set (h, "cdata", c2);
-	    clim = get(ax, "clim");
-	    if (c2 < clim(1))
-              set (ax, "clim", [c2, clim(2)])
-	    endif
-	    if (c2 > clim(2))
-              set (ax, "clim", [clim(1), c2])
-	    endif
-	  else
-	    ## Unknown color value.
-	    error ("patch: color value not valid");
-	  endif
-	elseif (numel (c2) == 3)
-	  ## Have rgb/rgba value.
-	  set (h, "facecolor", c2);
-	else
-	  ## Color vector.
-	  if (length (c2) != length (x) || length (c2) != length (y))
-	    error ("patch: size of x, y, and c must be equal")
-	  else
-	    set (h, "facecolor", "interp");
-	    set(h, "cdata", c2);
-	    if (abs(max(c2) - min(c2)) < eps)
-              set (ax, "clim", [c2(1)-1, c2(1)+1])
-	    else
-              set (ax, "clim", [min(c2), max(c2)]);
-	    endif
-	  endif
-	endif
-      else
-	set (h, "facecolor", [0, 1, 0]);
-      endif
-
-      if (nargin > iarg + 1)
-	set (h, varargin{iarg:end});
+    if (have_z)
+      vert = [x(:), y(:), z(:)];
+    else
+      vert = [x(:), y(:)];
+    endif
+    faces = reshape (1:numel(x), size(x,2), size(x,1));
+  elseif (have_faces)
+    nr = size (faces, 2);
+    nc = size (faces, 1);
+    idx = faces .';
+    for i = 1: nc
+      t1 = isnan (idx (:,i));
+      if (any (t1))
+	t2 = find (t1(1:end-1) != t1(2:end))(1);
+        idx(t1,i) = idx(t2,i);
       endif
     endfor
+    x = vert(:,1)(idx);
+    y = vert(:,2)(idx);
+    if (size(vert,2) > 2)
+      have_z = true;
+      z = vert(:,3)(idx);
+    endif
   else
     error ("patch: not supported");
   endif
 
+  h = __go_patch__ (p);
+  ax = get (h, "parent");
+
+  cargs = {};
+  if (have_c)
+    if (ischar (c))
+      cargs{1} = "facecolor";
+      cargs{2} = c;
+    elseif (isvector(c) && numel(c) == nc)
+      if (isnan (c))
+	cargs{1} = "facecolor";
+	cargs{2} = [1, 1, 1];
+	cargs{3} = "cdata";
+	cargs{4} = c;
+      elseif (isnumeric (c))
+	cargs{1} = "facecolor";
+	cargs{2} = "flat";
+	cargs{3} = "cdata";
+	cargs{4} = c;
+	clim = get(ax, "clim");
+	if (c(1) < clim(1))
+          set (ax, "clim", [c(1), clim(2)])
+	endif
+	if (c(1) > clim(2))
+          set (ax, "clim", [clim(1), c(1)])
+	endif
+      else
+	error ("patch: color value not valid");
+      endif
+    elseif (size(c, ndims(c)) == 3)
+      cargs{1} = "facecolor";
+      cargs{2} = "flat";
+      cargs{3} = "cdata";
+      cargs{4} = c;
+    else
+      ## Color Vectors
+
+      if (rows (c2) != rows (x) || rows (c2) != length (y))
+	error ("patch: size of x, y, and c must be equal")
+      else
+	cargs{1} = "facecolor";
+	cargs{2} = "interp";
+	if (abs(max(c2(:)) - min(c2(:))) < eps)
+          set (ax, "clim", [c2(1)-1, c2(1)+1])
+	else
+          set (ax, "clim", [min(c2(:)), max(c2(:))]);
+	endif
+      endif
+    endif
+  else
+    cargs{1} = "facecolor";
+    cargs{2} = [0, 1, 0];
+  endif
+
+  set (h, "xdata", x, "ydata", y, "faces", faces, "vertices", vert, ...
+       cargs{:}, varargin{iarg:end});
+  if (have_z)
+    set (h, "zdata", z);
+  endif
+ 
 endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/fill.m	Sat Oct 13 05:13:29 2007 +0000
@@ -0,0 +1,134 @@
+## Copyright (C) 2007  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} {} fill (@var{x}, @var{y}, @var{c})
+## @deftypefnx {Function File} {} fill (@var{x1}, @var{y1}, @var{c1}, @var{x2}, @var{y2}, @var{c2})
+## @deftypefnx {Function File} {} fill (@dots{}, @var{prop}, @var{val})
+## @deftypefnx {Function File} {} fill (@var{h}, @dots{})
+## @deftypefnx {Function File} {@var{h} = } fill (@dots{})
+## Create one or more filled patch objects, returning a patch object for each.
+## @end deftypefn
+
+function h = fill (varargin)
+
+  htmp = [];
+
+  if (isscalar (varargin{1}) && ishandle (varargin{1}))
+    h = varargin {1};
+    if (! strcmp (get (h, "type"), "axes"))
+      error ("fill: expecting first argument to be an axes object");
+    endif
+
+    iargs = __find_patches__ (varargin{:}) + 1;
+    oldh = gca ();
+    unwind_protect
+      axes (h);
+
+      for i = 1 : length (iargs)
+	if (i == length (iargs))
+	  args = varargin (iargs(i):end);
+        else
+	  args = varargin (iargs(i):iargs(i+1)-1);
+	endif
+
+	[tmp, fail] = __patch__ (h, args{:});
+	if (fail)
+	  print_usage();
+	endif
+	htmp (end + 1) = tmp;
+      endfor
+    unwind_protect_cleanup
+      axes (oldh);
+    end_unwind_protect
+  else
+    iargs = __find_patches__ (varargin{:});
+    for i = 1 : length (iargs)
+      if (i == length (iargs))
+	args = varargin (iargs(i):end);
+      else
+        args = varargin (iargs(i):iargs(i+1)-1);
+      endif
+      [tmp, fail] = __patch__ (gca (), args{:});
+      if (fail)
+	print_usage();
+      endif
+      htmp (end + 1) = tmp;
+    endfor
+  endif
+  if (nargout > 0)
+    h = htmp;
+  endif
+endfunction
+
+function iargs = __find_patches__ (varargin)
+  iargs = [];
+  i = 1;
+  while (i < nargin)
+    iargs (end + 1) = i;
+    if (ischar (varargin {i}) && (strcmp (tolower (varargin{i}), "faces") || 
+				  strcmp (tolower (varargin{i}), "vertices")))
+      i += 4;
+    elseif (isnumeric (varargin {i}))
+      i += 2;
+    endif
+
+    if (i <= nargin)
+      while (true);
+	if (ischar (varargin {i}) && 
+	    (strcmp (tolower (varargin{i}), "faces") || 
+	     strcmp (tolower (varargin{i}), "vertices")))
+	  break;
+	elseif (isnumeric (varargin {i}))
+	  ## Assume its the colorspec
+	  i++;
+	  break;
+	elseif (ischar (varargin {i}))
+	  colspec = tolower (varargin {i});
+	  collen = length (colspec);
+
+	  if (strncmp (colspec, "blue", collen) ||
+	      strncmp (colspec, "black", collen) ||
+	      strncmp (colspec, "k", collen) ||
+	      strncmp (colspec, "black", collen) ||
+	      strncmp (colspec, "red", collen) ||
+	      strncmp (colspec, "green", collen) ||
+	      strncmp (colspec, "yellow", collen) ||
+	      strncmp (colspec, "magenta", collen) ||
+	      strncmp (colspec, "cyan", collen) ||
+	      strncmp (colspec, "white", collen))
+	    i++;
+	    break;
+	  endif
+	else
+	  i += 2;
+	endif
+      endwhile
+    endif
+  endwhile
+endfunction
+
+%!demo
+%! close all;
+%! 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);
+%! x2 = sin(t2) + 0.8;
+%! y2 = cos(t2);
+%! h = fill(x1,y1,'r',x2,y2,'g')
--- a/scripts/plot/patch.m	Sat Oct 13 01:42:21 2007 +0000
+++ b/scripts/plot/patch.m	Sat Oct 13 05:13:29 2007 +0000
@@ -20,7 +20,10 @@
 ## @deftypefn {Function File} {} patch ()
 ## @deftypefnx {Function File} {} patch (@var{x}, @var{y}, @var{c})
 ## @deftypefnx {Function File} {} patch (@var{x}, @var{y}, @var{c}, @var{opts})
+## @deftypefnx {Function File} {} patch ('Faces', @var{f}, 'Vertices', @var{v}, @dots{})
+## @deftypefnx {Function File} {} patch (@dots{}, @var{prop}, @var{val})
 ## @deftypefnx {Function File} {} patch (@var{h}, @dots{})
+## @deftypefnx {Function File} {@var{h} = } patch (@dots{})
 ## Create patch object from @var{x} and @var{y} with color @var{c} and
 ## insert in the current axes object.  Return handle to patch object.
 ##
@@ -41,12 +44,16 @@
     oldh = gca ();
     unwind_protect
       axes (h);
-      tmp = __patch__ (h, varargin{:});
+      [tmp, fail] = __patch__ (h, varargin{:});
     unwind_protect_cleanup
       axes (oldh);
     end_unwind_protect
   else
-    tmp = __patch__ (gca (), varargin{:});
+    [tmp, fail] = __patch__ (gca (), varargin{:});
+  endif
+
+  if (fail)
+    print_usage ();
   endif
 
   if (nargout > 0)
@@ -54,3 +61,51 @@
   endif
 
 endfunction
+
+%!demo
+%! ## Patches with same number of vertices
+%! close all;
+%! 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);
+%! x2 = sin(t2) + 0.8;
+%! y2 = cos(t2);
+%! patch([x1,x2],[y1,y2],'r');
+
+%!demo
+%! ## Unclosed patch
+%! close all;
+%! t1 = (1/16:1/8:1)'*2*pi;
+%! t2 = ((1/16:1/16:1)' + 1/32)*2*pi;
+%! x1 = sin(t1) - 0.8;
+%! y1 = cos(t1);
+%! x2 = sin(t2) + 0.8;
+%! y2 = cos(t2);
+%! patch([[x1;NaN(8,1)],x2],[[y1;NaN(8,1)],y2],'r');
+
+%!demo
+%! ## Specify vertices and faces separately
+%! close all;
+%! t1 = (1/16:1/8:1)'*2*pi;
+%! t2 = ((1/16:1/16:1)' + 1/32)*2*pi;
+%! x1 = sin(t1) - 0.8;
+%! y1 = cos(t1);
+%! x2 = sin(t2) + 0.8;
+%! y2 = cos(t2);
+%! vert = [x1, y1; x2, y2];
+%! fac = [1:8,NaN(1,8);9:24];
+%! patch('Faces',fac,'Vertices',vert,'FaceColor','r');
+
+%!demo
+%! ## Property change on multiple patches
+%! close all;
+%! 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);
+%! x2 = sin(t2) + 0.8;
+%! y2 = cos(t2);
+%! h = patch([x1,x2],[y1,y2],cat (3,[0,0],[1,0],[0,1]));
+%! pause (1);
+%! set (h, 'FaceColor', 'r');
--- a/src/ChangeLog	Sat Oct 13 01:42:21 2007 +0000
+++ b/src/ChangeLog	Sat Oct 13 05:13:29 2007 +0000
@@ -1,3 +1,11 @@
+2007-10-13  David Bateman  <dbateman@free.fr>
+
+	* graphics.h.in (class patch): Add the faces and vertices properties.
+	* graphics.cc (patch::properties::properties): Initialize faces
+	and vertices.
+	(patch::properties::get): Also fetch faces and vertices.
+	(patch::properties::factory_defaults): Set faces and vertices.
+
 2007-10-12  John W. Eaton  <jwe@octave.org>
 
 	* Change copyright notices in all files that are part of Octave to
--- a/src/graphics.cc	Sat Oct 13 01:42:21 2007 +0000
+++ b/src/graphics.cc	Sat Oct 13 05:13:29 2007 +0000
@@ -2122,6 +2122,8 @@
     xdata (Matrix ()),
     ydata (Matrix ()),
     zdata (Matrix ()),
+    faces (Matrix ()),
+    vertices (Matrix ()),
     facecolor (radio_values ("{flat}|none|interp")),
     facealpha (1.0),
     edgecolor (color_values(0, 0, 0), radio_values ("flat|none|interp")),
@@ -2156,6 +2158,10 @@
     set_ydata (val);
   else if (name.compare ("zdata"))
     set_zdata (val);
+  else if (name.compare ("faces"))
+    set_faces (val);
+  else if (name.compare ("vertices"))
+    set_vertices (val);
   else if (name.compare ("facecolor"))
     set_facecolor (val);
   else if (name.compare ("facealpha"))
@@ -2197,6 +2203,8 @@
   m.assign ("xdata", xdata);
   m.assign ("ydata", ydata);
   m.assign ("zdata", zdata);
+  m.assign ("faces", faces);
+  m.assign ("vertices", vertices);
   m.assign ("facecolor", facecolor);
   m.assign ("facealpha", facealpha);
   m.assign ("edgecolor", edgecolor);
@@ -2231,6 +2239,10 @@
     retval = ydata;
   else if (name.compare ("zdata"))
     retval = zdata;
+  else if (name.compare ("faces"))
+    retval = faces;
+  else if (name.compare ("vertices"))
+    retval = vertices;
   else if (name.compare ("facecolor"))
     retval = facecolor;
   else if (name.compare ("facealpha"))
@@ -2264,6 +2276,8 @@
   m["xdata"] = Matrix ();
   m["ydata"] = Matrix ();
   m["zdata"] = Matrix ();
+  m["faces"] = Matrix ();
+  m["vertices"] = Matrix ();
   m["facecolor"] = color_property();
   m["facealpha"] = 1.0;
   m["edgecolor"] = color_property("black");
--- a/src/graphics.h.in	Sat Oct 13 01:42:21 2007 +0000
+++ b/src/graphics.h.in	Sat Oct 13 05:13:29 2007 +0000
@@ -1599,6 +1599,8 @@
       octave_value xdata
       octave_value ydata
       octave_value zdata
+      octave_value faces
+      octave_value vertices
       color_property facecolor a
       octave_value facealpha
       color_property edgecolor a