changeset 27727:b8684580dd23

smooth3.m: Overhaul function (bug #57276) * smooth3.m: Rewrite docstring. Add BIST test for bug #57276. * smooth3.m (__parse_smooth3_args__): Renamed from "__get_check_smooth3_args__". Use isinteger() and islogical() to validate input and convert to double type if found. Place most-common case first in switch statement for performance.
author Rik <rik@octave.org>
date Wed, 20 Nov 2019 17:22:01 -0800
parents b2c11742b7ec
children 5e92bff668d6
files scripts/plot/draw/smooth3.m
diffstat 1 files changed, 45 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/plot/draw/smooth3.m	Wed Nov 20 19:17:49 2019 +0100
+++ b/scripts/plot/draw/smooth3.m	Wed Nov 20 17:22:01 2019 -0800
@@ -23,49 +23,47 @@
 ## @deftypefnx {} {@var{smoothed_data} =} smooth3 (@var{data}, @var{method}, @var{sz}, @var{std_dev})
 ## Smooth values of 3-dimensional matrix @var{data}.
 ##
-## This function can be used, for example, to reduce the impact of noise in
+## This function may be used, for example, to reduce the impact of noise in
 ## @var{data} before calculating isosurfaces.
 ##
-## @var{data} must be a non-singleton 3-dimensional matrix.  The smoothed data
-## from this matrix is returned in @var{smoothed_data} which is of the same
-## size as @var{data}.
+## @var{data} must be a non-singleton 3-dimensional matrix.  The output 
+## @var{smoothed_data} is a matrix of the same size as @var{data}.
 ##
 ## The option input @var{method} determines which convolution kernel is used
 ## for the smoothing process.  Possible choices:
 ##
 ## @table @asis
 ## @item @qcode{"box"}, @qcode{"b"} (default)
-## to use a convolution kernel with sharp edges.
+## a convolution kernel with sharp edges.
 ##
 ## @item @qcode{"gaussian"}, @qcode{"g"}
-## to use a convolution kernel that is represented by a non-correlated
-## trivariate normal distribution function.
+## a convolution kernel that is represented by a non-correlated trivariate
+## normal distribution function.
 ## @end table
 ##
-## @var{sz} is either a vector of 3 elements representing the size of the
-## convolution kernel in x-, y- and z-direction or a scalar, in which case
-## the same size is used in all three dimensions.  The default value is 3.
+## @var{sz} is either a 3-element vector specifying the size of the
+## convolution kernel in the x-, y- and z-directions, or a scalar.  In the
+## scalar case the same size is used for all three dimensions
+## (@code{[@var{sz}, @var{sz}, @var{sz}]}).  The default value is 3.
 ##
-## When @var{method} is @qcode{"gaussian"}, @var{std_dev} defines the standard
-## deviation of the trivariate normal distribution function.  @var{std_dev} is
-## either a vector of 3 elements representing the standard deviation of the
-## Gaussian convolution kernel in x-, y- and z-directions or a scalar, in which
-## case the same value is used in all three dimensions.  The default value is
-## 0.65.
+## If @var{method} is @qcode{"gaussian"} then the optional input @var{std_dev}
+## defines the standard deviation of the trivariate normal distribution
+## function.  @var{std_dev} is either a 3-element vector specifying the
+## standard deviation of the Gaussian convolution kernel in x-, y- and
+## z-directions, or a scalar.  In the scalar case the same value is used for
+## all three dimensions.  The default value is 0.65.
 ##
 ## @seealso{isosurface, isonormals, patch}
 ## @end deftypefn
 
-## Author: mmuetzel
-
 function smoothed_data = smooth3 (data, method = "box", sz = 3, std_dev = 0.65)
 
   if (nargin < 1 || nargin > 4)
     print_usage ();
   endif
 
-  [data, conv_kernel, sz, std_dev] = ...
-                        __get_check_smooth3_args__ (data, method, sz, std_dev);
+  [data, kernel, sz, std_dev] = ...
+                        __parse_smooth3_args__ (data, method, sz, std_dev);
 
   ## Manually pad data by replicating the values at the edges.
   ## (convn would pad with zeros)
@@ -77,14 +75,22 @@
   endfor
   data_padded = data(idx{:});
 
-  smoothed_data = convn (data_padded, conv_kernel, "valid");
+  smoothed_data = convn (data_padded, kernel, "valid");
 
 endfunction
 
-function [data, conv_kernel, sz, std_dev] = __get_check_smooth3_args__ (data, method, sz, std_dev)
+function [data, conv_kernel, sz, std_dev] = __parse_smooth3_args__ (data, method, sz, std_dev)
+
+  if (ndims (data) != 3)
+    error ("smooth3: DATA must be a 3-D numeric matrix");
+  endif
 
-  if (! isnumeric (data) || ndims (data) != 3)
-    error ("smooth3: DATA must be a 3-D numeric matrix");
+  if (! isnumeric (data))
+    if (isinteger (data) || islogical (data))
+      data = double (data);
+    else
+      error ("smooth3: DATA must be a 3-D numeric matrix");
+    endif
   endif
 
   if (! ischar (method))
@@ -105,6 +111,9 @@
   endif
 
   switch (tolower (method))
+    case {"b", "box"}
+      conv_kernel = ones (sz) / prod (sz);
+
     case {"g", "gaussian"}
       ## check std_dev
       if (! isreal (std_dev))
@@ -118,9 +127,6 @@
 
       conv_kernel = __smooth3_gaussian3__ (sz, std_dev);
 
-    case {"b", "box"}
-      conv_kernel = ones (sz) / prod (sz);
-
     otherwise
       error ("smooth3: invalid METHOD '%s'", method);
 
@@ -165,6 +171,18 @@
 %! b = smooth3 (a);
 %! assert (size_equal (a, b), true);
 
+## data type of first input argument
+%!test <*57276>
+%! dt_a = {"double", "single", "uint8", "int8", "uint16", "int16", ...
+%!         "uint32", "int32", "uint64", "int64", "logical"};
+%! dt_b = {"double", "single", "double", "double", "double", "double", ...
+%!         "double", "double", "double", "double", "double"};
+%! for i = 1 : numel (dt_a)
+%!   a = ones (3, 4, 5, dt_a{i});
+%!   b = smooth3 (a);
+%!   assert (class (b), dt_b{i});
+%! endfor
+
 ## two input argument (method: "gaussian")
 %!test
 %! a = rand (5, 8, 7);