diff scripts/plot/draw/private/__patch__.m @ 30634:36d940c58c2e

Improve input validation for patch function (bug #61782) * patch.m: Avoid call to gca() before executing __patch__ as input validation may stop patch from being created leaving empty figure and axes objects. Add BIST tests for input validation. * __patch__.m: Remove second output of function (failed). Detect 3-input case with bad color specification and issue and emit an error. Add comments to clarify code about which input combination is being processed in long if/elseif tree. Call gca() if patch is validated but no axes has been specified. * fill.m: Re-write call to __patch__ to match new function with only one output.
author Rik <rik@octave.org>
date Tue, 11 Jan 2022 12:17:16 -0800
parents 796f54d4ddbf
children 597f3ee61a48
line wrap: on
line diff
--- a/scripts/plot/draw/private/__patch__.m	Tue Jan 11 20:43:58 2022 +0100
+++ b/scripts/plot/draw/private/__patch__.m	Tue Jan 11 12:17:16 2022 -0800
@@ -32,153 +32,154 @@
 ## Create patch object from x and y with color c and parent p.
 ## Return handle to patch object.
 
-function [h, failed] = __patch__ (p, varargin)
+function h = __patch__ (p, varargin)
 
   h = NaN;
-  failed = false;
+  nargin = nargin - 1;
 
   is_numeric_arg = cellfun (@isnumeric, varargin);
 
   if (isempty (varargin))
-    args = varargin;
+    args = {};
   elseif (is_numeric_arg(1))
     if (nargin < 3 || ! is_numeric_arg(2))
-      failed = true;
-    else
-      if (nargin > 4 && all (is_numeric_arg(1:4)))
-        x = varargin{1};
-        y = varargin{2};
+      print_usage ("patch");
+    endif
+
+    if (nargin >= 4 && all (is_numeric_arg(1:4)))
+      x = varargin{1};
+      y = varargin{2};
+      z = varargin{3};
+      c = varargin{4};
+      iarg = 5;
+    elseif (nargin >= 3 && all (is_numeric_arg(1:3)))
+      x = varargin{1};
+      y = varargin{2};
+      if (nargin > 3 && iscolorspec (varargin{4}))
         z = varargin{3};
         c = varargin{4};
         iarg = 5;
-      elseif (nargin > 3 && all (is_numeric_arg(1:3)))
-        x = varargin{1};
-        y = varargin{2};
-        if (nargin > 4 && iscolorspec (varargin{4}))
-          z = varargin{3};
-          c = varargin{4};
-          iarg = 5;
-        else
-          z = [];
-          c = varargin{3};
-          iarg = 4;
-        endif
-      elseif (nargin > 2 && all (is_numeric_arg(1:2)))
-        x = varargin{1};
-        y = varargin{2};
+      else
         z = [];
-        if (iscolorspec (varargin{3}))
-          c = varargin{3};
-          iarg = 4;
-        else
-          c = [];
-          iarg = 3;
-        endif
+        c = varargin{3};
+        iarg = 4;
       endif
+    elseif (nargin >= 3 && all (is_numeric_arg(1:2)))
+      x = varargin{1};
+      y = varargin{2};
+      z = [];
+      if (iscolorspec (varargin{3}))
+        c = varargin{3};
+        iarg = 4;
+      elseif (nargin == 3)
+        error ("patch: invalid color specification C");
+      else
+        c = [];
+        iarg = 3;
+      endif
+    endif
 
-      if (isvector (x))
-        x = x(:);
-        y = y(:);
-        z = z(:);
-        if (isnumeric (c))
-          if (isvector (c))
-            if (isequal (size (c), [1, 3]))
-              ## Do nothing, this is a single RGB color specification
-            elseif (numel (c) == numel (x))
-              c = c(:);
-            endif
-          elseif (rows (c) != numel (x) && columns (c) == numel (x))
-            c = c.';
+    if (isvector (x))
+      x = x(:);
+      y = y(:);
+      z = z(:);
+      if (isnumeric (c))
+        if (isvector (c))
+          if (isequal (size (c), [1, 3]))
+            ## Do nothing, this is a single RGB color specification
+          elseif (numel (c) == numel (x))
+            c = c(:);
           endif
+        elseif (rows (c) != numel (x) && columns (c) == numel (x))
+          c = c.';
         endif
       endif
-      args{1} = "xdata";
-      args{2} = x;
-      args{3} = "ydata";
-      args{4} = y;
-      args{5} = "zdata";
-      args{6} = z;
+    endif
+    args{1} = "xdata";
+    args{2} = x;
+    args{3} = "ydata";
+    args{4} = y;
+    args{5} = "zdata";
+    args{6} = z;
 
-      if (isnumeric (c))
+    if (isnumeric (c) && ! isempty (c))
 
-        if (ndims (c) == 3 && columns (c) == 1)
-          c = permute (c, [1, 3, 2]);
-        endif
+      if (ndims (c) == 3 && columns (c) == 1)
+        c = permute (c, [1, 3, 2]);
+      endif
 
-        if (isvector (c) && numel (c) == columns (x))
-          if (isnan (c))
-            args{7} = "facecolor";
-            args{8} = [1, 1, 1];
-            args{9} = "cdata";
-            args{10} = c;
-          elseif (isnumeric (c))
-            args{7} = "facecolor";
-            args{8} = "flat";
-            args{9} = "cdata";
-            args{10} = c;
-          else
-            error ("patch: color data C must be numeric");
-          endif
-        elseif (isrow (c) && numel (c) == 3)
+      if (isvector (c) && numel (c) == columns (x))
+        ## One color per face
+        if (isnan (c))
+          args{7} = "facecolor";
+          args{8} = [1, 1, 1];
+        else
           args{7} = "facecolor";
-          args{8} = c;
+          args{8} = "flat";
+        endif
+        args{9} = "cdata";
+        args{10} = c;
+      elseif (isrow (c) && numel (c) == 3)
+        ## One RGB color
+        args{7} = "facecolor";
+        args{8} = c;
+        args{9} = "cdata";
+        args{10} = [];
+      elseif (ndims (c) == 3 && size (c, 3) == 3)
+        ## CDATA is specified as 3-D RGB data
+        if ((rows (c) == 1 && columns (c) == 1) ...
+            || (rows (c) == 1 && columns (c) == columns (x)))
+          ## Single patch color or per-face color
+          args{7} = "facecolor";
+          args{8} = "flat";
+          args{9} = "cdata";
+          args{10} = c;
+        elseif (rows (c) == rows (x) && columns (c) == columns (x))
+          ## Per-vertex color
+          args{7} = "facecolor";
+          args{8} = "interp";
+          args{9} = "cdata";
+          args{10} = c;
+        else
+          error ("patch: invalid TrueColor data C");
+        endif
+      else
+        ## Color vectors
+        if (isempty (c))
+          args{7} = "facecolor";
+          args{8} = "interp";
           args{9} = "cdata";
           args{10} = [];
-        elseif (ndims (c) == 3 && size (c, 3) == 3)
-          ## CDATA is specified as RGB data
-          if ((rows (c) == 1 && columns (c) == 1) ...
-              || (rows (c) == 1 && columns (c) == columns (x)))
-            ## Single patch color or per-face color
-            args{7} = "facecolor";
-            args{8} = "flat";
-            args{9} = "cdata";
-            args{10} = c;
-          elseif (rows (c) == rows (x) && columns (c) == columns (x))
-            ## Per-vertex color
-            args{7} = "facecolor";
-            args{8} = "interp";
-            args{9} = "cdata";
-            args{10} = c;
-          else
-            error ("patch: Invalid TrueColor data C");
-          endif
+        elseif (size_equal (c, x) && size_equal (c, y))
+          args{7} = "facecolor";
+          args{8} = "interp";
+          args{9} = "cdata";
+          args{10} = c;
         else
-          ## Color Vectors
-          if (isempty (c))
-            args{7} = "facecolor";
-            args{8} = "interp";
-            args{9} = "cdata";
-            args{10} = [];
-          elseif (size_equal (c, x) && size_equal (c, y))
-            args{7} = "facecolor";
-            args{8} = "interp";
-            args{9} = "cdata";
-            args{10} = c;
-          else
-            error ("patch: size of X, Y, and C must be equal");
-          endif
+          error ("patch: size of X, Y, and C must be equal");
         endif
-      elseif (iscolorspec (c))
-        args{7} = "facecolor";
-        args{8} = tolower (c);
-        args{9} = "cdata";
-        args{10} = [];
-      else
-        args{7} = "facecolor";
-        args{8} = [0, 0, 0];
-        args{9} = "cdata";
-        args{10} = [];
       endif
+    elseif (iscolorspec (c))
+      ## Color specification is a string
+      args{7} = "facecolor";
+      args{8} = tolower (c);
+      args{9} = "cdata";
+      args{10} = [];
+    elseif (! isempty (c))
+      error ("patch: invalid color specification C");
+    endif
 
-      args = [args, varargin(iarg:end)];
-    endif
+    args = [args, varargin(iarg:end)];
+
   else
+    ## "Property"/Value pair input
     args = varargin;
   endif
 
-  if (! failed)
-    h = __go_patch__ (p, args{:});
+  if (isempty (p))
+    p = gca ();
   endif
+  h = __go_patch__ (p, args{:});
 
 endfunction