## Copyright (C) 2020 Adam H Aitkenhead <adamaitkenhead@hotmail.com>
## 
## This program 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.
## 
## This program 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 this program.  If not, see
## <https://www.gnu.org/licenses/>.

## -*- texinfo -*- 
## @deftypefn {Function File} {[@var{f1}] =} freqspace (@var{n})
## @deftypefnx {Function File} {[@var{f1,f2}] =} freqspace (@var{n})
## @deftypefnx {Function File} {[@var{f1,f2}] =} freqspace (@var{m,n})
## @deftypefnx {Function File} {[@var{f1,f2,f3,...}] =} freqspace (@var{m,n,o,...})
## @deftypefnx {Function File} {[@var{f1,f2}] =} freqspace (@var{m,n,'meshgrid'})
## @deftypefnx {Function File} {[@var{f1,f2}] =} freqspace (@var{m,n,'whole'})
##
## @code{freqspace} returns a vector @var{f1} of @var{n} evenly spaced values.
## The numerical inputs @var{m,n,o...} must have integer values, but may be of class single or double.
##
## If @var{n} is even, @code{freqspace} returns a vector @var{f1} containing the values: [-1 : 2/n : (n-2)/n].
##
## If @var{n} is odd, @code{freqspace} returns a vector @var{f1} containing the values: [(1-n)/n : 2/n : (n-1)/n].
##
## If the option 'whole' is applied, @code{freqspace} returns a vector @var{f1} containing the values: [0 : 2/n : 2*(n-1)/n].
##
## If the number of outputs @var{f1,f2,...} is greater than one and the option 'meshgrid' is applied, @code{freqspace} applies
## @code{meshgrid} to the outputs, returning @var{f1,f2} as arrays rather than vectors.  Note that if the
## number of outputs is greater than 2, the outputs @var{f1,f2,f3,...} have their first two dimensions ordered
## according to @code{meshgrid}, and not as would they would be ordered by @code{ndgrid}.
##
## If the number of numerical inputs @var{n} equals 1 and the number of outputs @var{f1,f2} is greater than one, all outputs are identical.
##
## @seealso{meshgrid}
## @end deftypefn

## Author: Adam Aitkenhead <adamaitkenhead@hotmail.com>
## Created: 2020-09-25

function varargout = freqspace (varargin)

  # Count the number of numeric input arguments
  narginnumeric = sum (cellfun (@isnumeric, varargin));

  # Check the number of input and output arguments
  if (nargout<narginnumeric) || (nargout>narginnumeric && narginnumeric~=1)
    error ('freqspace: Unsupported number of input or output arguments')
  end

  # Check that all numeric input arguments have integer values
  if (any (cellfun (@mod, varargin(1:narginnumeric), {1})))
    error ('freqspace: All numeric inputs must have integer values')
  end

  # Check that all string input arguments are either 'whole' or 'meshgrid'
  if (narginnumeric<nargin) && (~all (ismember (varargin(narginnumeric+1:end), {'whole','meshgrid'})))
    error ('freqspace: The only supported string inputs are ''whole'' or ''meshgrid''')
  end

  # Generate the outputs F1, F2...
  for i = 1:narginnumeric
    n = varargin{i};
    if (mod (n, 2) == 0)   # n is even
      varargout{i} = [-1 : 2/n : (n-2)/n];
    else                   # n is odd
      varargout{i} = [(1-n)/n : 2/n : (n-1)/n];
    endif
  endfor

  # Duplicate the output arguments if nargout>1 and nargin==1
  if (nargout>narginnumeric)
    for i = 2:nargout
      varargout{i} = varargout{1};
    endfor
  endif

  # Option: 'whole'
  if (nargin>narginnumeric) && (all (cellfun (@ischar, varargin(narginnumeric+1:end)))) && (any (cellfun ('strcmp', varargin(narginnumeric+1:end), {'whole'} )))
    minout = cellfun (@min, varargout);
    for i = 1:nargout
      varargout{i} = varargout{i} - minout(i);
    endfor
  endif

  # Option: 'meshgrid'
  if (nargin>narginnumeric) && (all (cellfun (@ischar, varargin(narginnumeric+1:end)))) && (any (cellfun ('strcmp', varargin(narginnumeric+1:end), {'meshgrid'} )))
    [varargout{:}] = ndgrid (varargout{:});
    for i = 1:nargout
      varargout{i} = permute (varargout{i}, [2,1,3:max(3, ndims (varargout{i}))]);
    endfor
  endif

endfunction


