function varargout = setaxes(varargin)
%SETAXES   fixes common problems with MATLAB figures.
%
%   SETAXES(AX, ...) applies to the axes AX which, when not supplied, defaults to the current axes.
%
%
%    SETAXES('xoffset') [2-D view only] adjusts the axes position in the
%    horizontal direction to make up for any clipped (left or right) part
%    of the axes based on some default settings.
%
%    SETAXES('yoffset') [2-D view only] adjusts the axes position in the
%    vertical direction to make up for any clipped (lower or upper) part
%    of the axes based on some default settings.
%
%    SETAXES('axesmoveresize', [L B R T]) adds the array [L B -R -T] to the
%    'OuterPosition' property  of the axes.
%
%
%    SETAXES('xtick2text', OFFSET) [2-D view only] replaces the tick labels
%    on the X-Axis by text objects where OFFSET is the factor of the axis
%    height used as the vertical margin from the X-Axis.
%
%       When not supplied, OFFSET defaults to 0.03.
%
%    SETAXES('xtick2text',..., PROP1, VALUE1, PROP2, VALUE2, ...)
%       sets the values of the specified properties of the text objects.
%
%    HT = SETAXES('xtick2text',...) returns in HT the handles of the text objects.
%
%
%    SETAXES('ytick2text', OFFSET) [2-D view only] replaces the tick labels
%    on the Y-Axis by text objects where OFFSET is the factor of the axis
%    width used as the horizontal margin from the Y-Axis.
%
%       When not supplied, OFFSET defaults to 0.02.
%
%    SETAXES('ytick2text',..., PROP1, VALUE1, PROP2, VALUE2, ...)
%       sets the values of the specified properties of the text objects.
%
%    HT = SETAXES('ytick2text',...) returns in HT the handles of the text objects.
%
%
%    SETAXES('xlabelcorner') [2-D view only] places the XLABEL in an
%    appropriate corner. The most common corner is the right-bottom when
%    the X-Axis is to the bottom and the ticks are increasing from left to
%    right. The corner changes accordingly for other combinations of axes properties.
%
%    SETAXES('xlabelcorner', PROP1, VALUE1, PROP2, VALUE2, ...)
%    sets the values of the specified properties of the XLabel object.
%
%
%    SETAXES('ylabelcorner') [2-D view only] places the YLABEL in an
%    appropriate corner. The most common corner is the top-left when the
%    Y-Axis is to the left and the ticks are increasing upward. The corner
%    changes accordingly for other combinations of axes properties.
%
%    SETAXES('ylabelcorner', PROP1, VALUE1, PROP2, VALUE2, ...)
%    sets the values of the specified properties of the YLabel object.
%
%
%    SETAXES('axesarrows') [2-D view only] adds arrow annotation objects to
%    X- and Y-Axis. The default 'HeadLength' and 'HeadWidth' are both 5.
%    Line width and Color are inherited from the the corresponfing axis line.
%
%    SETAXES('axesarrows','xx') adds arrow annotation objects to X-Axis only.
%    SETAXES('axesarrows','yy') adds arrow annotation objects to Y-Axis only.
%
%    SETAXES('axesarrows',..., PROP1, VALUE1, PROP2, VALUE2, ...)
%    sets the values of the specified properties of the arrow objects.
%
%    HA = SETAXES('axesarrows',...) returns in HA the handles of the arrow objects.
%
%    Note that since SETAXES('axesarrows',...) changes the axes position property, any
%    annotation objects should be added after SETAXES('axesarrows',...).
%
%=======================================================================
%                   EXAMPLE trying to cover a few features:
%-----------------------------------------------------------------------
%
% figure('Units', 'centimeters', ...
%        'Position', [2 2 8 6], ...
%        'PaperUnits', 'centimeters', ...
%        'PaperSize', [8 6], ...
%        'PaperPositionMode', 'auto')
%
% ax = axes('FontSize', 8, ...
%            'LineWidth', 0.4, ...
%            'Box', 'off', ...
%            'TickDir', 'out' );
%
% hold all
%
% t = linspace(0,5,51);
% n = 1:49;
% rand('state', sum(100*clock));
% W = [0 cumsum(-log(rand(size(n)))./n)];
% hPlot(1) = stairs(W, [n 50], '-b');
% hPlot(2) = line(t, exp(t), 'LineStyle', '--', 'Color', 'r');
% axis([0 5 0 50])
%
% xlabel('$T=\mathrm{Exp}(\frac{1}{X})$', 'Interpreter','LaTeX');
% ylabel('$X$', 'Interpreter','LaTeX');
% legend(hPlot, {'sample $n$'; 'mean $\mu(T)$'}, 'Interpreter','LaTeX')
% set(ax, 'XTickLabel', {'$0$';'$\tau_1$';'$\tau_2$'; ...
%                          '$\tau_3$';'$\tau_4$';'$\tau_5$'}, ...
%         'YTickLabel', {'$0$';'$X_1$';'$X_2$';'$X_3$';'$X_4$';'$X_5$'} )
%
% setaxes('xtick2text')
% setaxes('ytick2text')
% setaxes('ylabelcorner')
% setaxes('yoffset')
% setaxes('axesarrows')
%
% [xfig,yfig] = dsxy2figxy([1 2], [45 45]);
% har = annotation('doublearrow', xfig , yfig);
% set(har, 'LineWidth', .25, 'Color', 'k', ...
%          'Head1Length', 3.5, 'Head2Length', 3.5, ...
%          'Head1Width', 3.5, 'Head2Width', 3.5, ...
%          'Head1Style', 'vback3', 'Head2Style', 'vback3')
%
% text(1.5, 48, '$\Delta \tau$', ...
%             'VerticalAlignment', 'bottom', ...
%             'HorizontalAlignment', 'center', 'Interpreter','LaTeX');
% print -dpdf setaxes_example.pdf
%
%
%=========================================================================

% Mukhtar Ullah
% mukhtar.ullah@informatik.uni-rostock.de
% First created: Sep 18, 2008
% Last modified: Oct 18, 2010
%
%=========================================================================

persistent SetAxes_CurrentAxes SetAxes_Functions SetAxes_ValidNames

[ax,argsmain,nIn] = axescheck(varargin{:});

error(nargchk(1, inf, nIn));

if isempty(ax)
    ax = gca;
else
    assert(~strcmp(get(ax,'Tag'),'legend'), 'Legend Axes not supported')
end

% Bring to focus
figure(get(ax, 'Parent'))
set(gcf, 'CurrentAxes', ax)

% first time run or a successive run for a different axes
if isempty(SetAxes_CurrentAxes) ||  ax~=SetAxes_CurrentAxes
    SetAxes_CurrentAxes = ax;
    SetAxes_Functions = {};
end

if isempty(SetAxes_Functions)
    oldaxunits = get(ax, 'Units');
    set(ax, 'Units', 'normalized')

    axprop = get(ax, {'Position', ...
        'OuterPosition', ...
        'LooseInset', ...
        'XTick', ...
        'YTick', ...
        'XLim', ...
        'YLim', ...
        'Xlabel', ...
        'Ylabel', ...
        'Title'} );
    set(ax, 'Units', oldaxunits)

    numvar = numel(axprop);

    axprop  = [axprop, get(ax, {'XAxisLocation', ...
        'YAxisLocation', ...
        'XDir', ...
        'YDir', ...
        'XScale', ...
        'YScale', ...
        'XTickLabelMode', ...
        'YTickLabelMode'} )];

    [axpos, outpos, looseinset, xtick, ytick, axlim(1:2), axlim(3:4), ...
        hxlab, hylab, htitle, xxloc, yyloc] = axprop{1:numvar+2};

    proptf = num2cell(strcmp(axprop(numvar+1:end), ...
        {'bottom', 'left', 'normal', 'normal', 'log', 'log', 'auto', 'auto'}));

    [isxxbottom, isyyleft, isxdirnormal, isydirnormal, ...
        isxxlog, isyylog, autoxticklab, autoyticklab] = proptf{:};

    [dxt, dyt, dxtfig, dytfig, xtickroom, ytickroom] = deal(0);
    isxlabelcorner = false;
    isylabelcorner = false;

    notxxloc = setdiff({'top', 'bottom'}, xxloc);
    notyyloc = setdiff({'left', 'right'}, yyloc);
    set([hxlab, hylab, htitle], {'Tag'}, {'XLabel'; 'YLabel'; 'Title'})
    xlabpos = get(hxlab, 'Position');
    ylabpos = get(hylab, 'Position');

    [axwidth, axheight, ...
        xlabhalign, ylabhalign, xlabvalign, ylabvalign] = falign();

    %----------------------------------------------------------------------

        SetAxes_ValidNames = {'axesmoveresize', 'legendmoveresize'};

        [az,el]=view(ax);
        camUp = get(ax,'CameraUpVector');
        if (az==0) && (el==90) && isequal(abs(camUp),[0 1 0]) % Is2D
            SetAxes_ValidNames = [ SetAxes_ValidNames, ...
                { 'xoffset', 'yoffset', ...
                'xtick2text', 'ytick2text', ...
                'xlabelcorner', 'ylabelcorner', 'axesarrows' } ];
        end

        SetAxes_Functions = cellfun(@(s) eval(['@', s]), SetAxes_ValidNames, 'UniformOutput', false);
end

funstr = validatestring(argsmain{1}, SetAxes_ValidNames);

fh = SetAxes_Functions{strcmp(funstr, SetAxes_ValidNames)};
nOut = nargout;

switch sprintf('%d',[nIn-1 nOut]>0)
    case '00'
        fh();
    case '10'
        fh(argsmain{2:end});
    case '01'
        [varargout{1:nOut}] = fh();
    otherwise
        [varargout{1:nOut}] = fh(argsmain{2:end});
end

%==========================================================================
    function xoffset()
        if ~isylabelcorner && get(hylab, 'Rotation')==0
            set(hylab, 'HorizontalAlignment', ylabhalign)
        end
        tightinset = get(ax, 'TightInset');
        set(ax, 'LooseInset', max(looseinset, tightinset))
        restoreleftright(hylab)
    end
%--------------------------------------------------------------------------
    function yoffset()
        tightinset = get(ax, 'TightInset');
        set(ax, 'LooseInset', max(looseinset, tightinset))
        restoreupdown(hxlab)
        restoreupdown(htitle)
    end
%--------------------------------------------------------------------------
    function axesmoveresize(offset)
        if nargin == 0
            disp('Drag a rectangle in the axes to define OuterPosition:')
            k = waitforbuttonpress;
            if k == 1
                return
            end
            % fig = gcf; if the figure is already in focus
            fig = get(ax, 'Parent');
            oldunits = get(fig, 'Units');
            set(fig, 'Units', 'normalized')
            outpos = rbbox;
            set(fig, 'Units', oldunits)
        else
            outpos = outpos + [1 1 -1 -1].*offset;
        end
        set(ax, 'OuterPosition', outpos)
        drawnow
        axpos = get(ax, 'Position');
    end
 %--------------------------------------------------------------------------
    function hxt = xtick2text(varargin)
        [xtickoffset, pvpairs] = extractoffset(.03, varargin{:});
        hxt = [];
        xticklab = cellstr(get(ax, 'XTickLabel'));
        xticklab = matchticks(xtick, xticklab);
        if ~isempty(xticklab)
            set(ax, 'XTickLabel', []);

            if xor(isxxbottom,isydirnormal)
                yloc = axlim(4) + xtickoffset*axheight;
            else
                yloc = axlim(3) - xtickoffset*axheight;
            end

            yloc = yloc(ones(size(xtick)));

            if isyylog
                yloc = 10.^yloc;
                xticklab = append10(xticklab, autoxticklab, pvpairs);
            end

            hxt = text(xtick, yloc, xticklab);

            set(hxt(strncmp('$', xticklab, 1)), 'Interpreter', 'latex')
%             mathtick = ~cellfun(@isempty, ...
%                 regexp(xticklab, '\${1,2}[^\$]*\${1,2}', 'match', 'once'));
%             set(hxt(strncmp(mathtick), 'Interpreter', 'latex')

            set(hxt, 'HorizontalAlignment', 'center', ...
                     'VerticalALignment', xlabvalign, pvpairs{:});
            %--------------------------------------------------------------
            oldunits = get(hxt(1), 'Units');
            set(hxt, 'Units', 'normalized')
            xtickext = get(hxt, 'Extent');
            xtickroom = max(cellfun(@(x) x(4), xtickext));
            set(hxt, 'Units', oldunits)

            xtickext = get(hxt, 'Extent');
            xlabposnow = get(hxlab, 'Position');

            if isxxbottom
                xlabposnow(2) = ...
                    min(cellfun(@(x) x(2), xtickext)) + xtickoffset;
            else
                xlabposnow(2) = ...
                    max(cellfun(@(x) x(2)+x(4), xtickext)) + xtickoffset;
            end

            set(hxlab, 'Position', xlabposnow)

        end
    end
%--------------------------------------------------------------------------
    function hyt = ytick2text(varargin)
        [ytickoffset, pvpairs] = extractoffset(.02, varargin{:});
        hyt = [];
        yticklab = cellstr(get(ax, 'YTickLabel'));
        yticklab = matchticks(ytick, yticklab);
        if ~isempty(yticklab)
            set(ax, 'YTickLabel', []);

            if xor(isyyleft,isxdirnormal)
                xloc = axlim(2) + ytickoffset*axwidth;
            else
                xloc = axlim(1) - ytickoffset*axwidth;
            end

            xloc = xloc(ones(size(ytick)));

            if isxxlog
                xloc = 10.^xloc;
                yticklab = append10(yticklab, autoyticklab, pvpairs);
            end

            hyt = text(xloc, ytick, yticklab);

            set(hyt(strncmp('$', yticklab, 1)), 'Interpreter', 'latex')
%             mathtick = ~cellfun(@isempty, ...
%                 regexp(yticklab, '\${1,2}[^\$]*\${1,2}', 'match', 'once'));
%             set(hyt(strncmp(mathtick), 'Interpreter', 'latex')

            set(hyt, 'VerticalAlignment', 'middle', ...
                     'HorizontalALignment', ylabhalign, pvpairs{:})
            %--------------------------------------------------------------
            oldunits = get(hyt(1), 'Units');
            set(hyt, 'Units', 'normalized')
            ytickext = get(hyt, 'Extent');
            ytickroom = max(cellfun(@(x) x(3), ytickext));
            set(hyt, 'Units', oldunits)

            ytickext = get(hyt, 'Extent');
            ylabposnow = get(hylab, 'Position');

            if isyyleft
                ylabposnow(1) = min(cellfun(@(x) x(1), ytickext));
            else
                ylabposnow(1) = max(cellfun(@(x) x(1)+x(3), ytickext));
            end

            set(hylab, 'Position', ylabposnow)

        end
    end
%--------------------------------------------------------------------------
    function xlabelcorner(varargin)
        if isxxlog
            xlabpos(1:2) = 10.^xlabpos(1:2);
        end

        set(hxlab, ...
            'Position', xlabpos, ...
            'VerticalALignment', 'middle', ...
            'HorizontalALignment', xlabhalign, varargin{:});

        isxlabelcorner = true;
        axpos = get(ax, 'Position');
        restoreleftright(hxlab)
    end
%--------------------------------------------------------------------------
    function ylabelcorner(varargin)
        if isyylog
            ylabpos(1:2) = 10.^ylabpos(1:2);
        end

        set(hylab, ...
            'Position', ylabpos, ...
            'Rotation', 0, ...
            'VerticalALignment', ylabvalign, ...
            'HorizontalALignment', 'center', varargin{:});

        isylabelcorner = true;
        axpos = get(ax, 'Position');
        restoreupdown(hylab)
    end
%--------------------------------------------------------------------------
    function h = axesarrows(varargin)
        args = varargin;
        xxarrow = true;
        yyarrow = true;

        if nargin>0
            switch args{1}
                case 'xx'
                    yyarrow = false;
                    args(1) = [];
                case 'yy'
                    xxarrow = false;
                    args(1) = [];
                otherwise
                    error('Unknown option')
            end
        end

       [left, bottom, right, top] = deal(0);

        if xxarrow && ~isxlabelcorner
            if isyyleft
                right = dxtfig;
            else
                left = dxtfig;
            end
        end

        if yyarrow && ~isylabelcorner
            if isxxbottom
                top = dytfig;
            else
                bottom = dytfig;
            end
        end

        axesmoveresize([left, bottom, right, top])

        if isyyleft
            xxarx = axpos(1)+axpos(3)+[0 dxtfig];
            yyarx = axpos([1 1]);
        else
            xxarx = axpos(1)+[axpos(3) -dxtfig];
            yyarx = axpos([1 1]) + axpos([3 3]);
        end

        if isxxbottom
            yyary = axpos(2)+axpos(4)+[0 dytfig];
            xxary = axpos([2 2]);
        else
            yyary = axpos(2)+[axpos(4) -dytfig];
            xxary = axpos([2 2]) + axpos([4 4]);
        end

        if xxarrow
            h(1) = annotation('arrow', xxarx, xxary, ...
                                      'Color', get(ax, 'XColor'));
        end

        if yyarrow
            h(2) = annotation('arrow', yyarx, yyary, ...
                                      'Color', get(ax, 'YColor'));
        end

        set(nonzeros(h), 'HeadLength', 5, 'HeadWidth', 5, ...
                         'LineWidth', get(ax, 'LineWidth'), args{:})

    end

%==========================================================================
    function restoreupdown(lab)
        withlab = ~isempty(get(lab, 'String')) && ...
                            strcmp(get(lab, 'Visible'), 'on');
        if withlab
            oldunits = get(lab, 'Units');
            set(lab, 'Units', 'normalized')
            labext = get(lab, 'Extent');

            if strcmpi(get(lab, 'Tag'), 'YLabel')
                labext = labext.*axpos([3 4 4 3]);
            else
                labext = labext.*axpos([3 4 3 4]);
            end

            extroom = labext(4);

            if strcmpi(get(lab, 'Tag'), 'XLabel')
                set(lab, 'Visible', 'off')
                keyword = xxloc;
%                 extroom = 1.05*max(extroom, xtickroom*axpos(4));
                extroom = max(extroom, xtickroom*axpos(4));
            else
                keyword = notxxloc;
            end

            tightinset = get(ax, 'TightInset');
            set(lab, 'Visible', 'on', 'Units', oldunits)
            if strcmp(keyword, 'bottom')
                looseinset(2) = max(looseinset(2), tightinset(2) + extroom);
            else
                %                 looseinset(4) = max(looseinset(4), labext(2)+labext(4)-axpos(4));
                looseinset(4) = max(looseinset(4), tightinset(4) + extroom);
            end

            set(ax, 'LooseInset', looseinset)
            axpos = get(ax, 'Position');
        end
    end
%--------------------------------------------------------------------------
    function restoreleftright(lab)
        withlab = ~isempty(get(lab, 'String')) && ...
                                strcmp(get(lab, 'Visible'), 'on');
        if withlab
            oldunits = get(lab, 'Units');
            set(lab, 'Units', 'normalized')
            labext = get(lab, 'Extent');

            if strcmpi(get(lab, 'Tag'), 'YLabel')
                set(lab, 'Visible', 'off')
                labext = labext.*axpos([3 4 4 3]);
                if get(lab, 'Rotation')==90
                    extroom = labext(4);
                else
                    extroom = labext(3);
                end
                extroom = max(extroom, ytickroom*axpos(3));
                keyword = yyloc;
            else
                labext = labext.*axpos([3 4 3 4]);
                extroom = labext(3);
                keyword = notyyloc;
            end

%             extroom = 1.05*extroom;

            tightinset = get(ax, 'TightInset');
            set(lab, 'Visible', 'on', 'Units', oldunits)

            if strcmp(keyword, 'left')
                looseinset(1) = max(looseinset(1), tightinset(1) + extroom);
            else
                %                 looseinset(3) = max(looseinset(3), labext(1)+labext(3)-axpos(3));
                looseinset(3) = max(looseinset(3), tightinset(3) + extroom);
            end

            set(ax, 'LooseInset', looseinset)
            axpos = get(ax, 'Position');
        end
    end
%--------------------------------------------------------------------------
    function [ axwidth, axheight, xlabhalign, ylabhalign, ...
                                  xlabvalign, ylabvalign ] = falign()

        if isxxlog
            axlim(1:2) = log10(axlim(1:2));
            xlabpos(1) = log10(xlabpos(1));
        end

        if isyylog
            axlim(3:4) = log10(axlim(3:4));
            ylabpos(2) = log10(ylabpos(2));
        end

        axwidth = diff(axlim(1:2));
        axheight = diff(axlim(3:4));

        dxtfig = .02;
        dxt = max(0.05*axwidth, dxtfig*axwidth/axpos(3));
        dxtfig = dxt*axpos(3)/axwidth;

        dytfig = .02;
        dyt = max(0.05*axheight, dytfig*axheight/axpos(4));
        dytfig = dyt*axpos(4)/axheight;

        if isyyleft
            xlabhalign = 'left';
            ylabhalign = 'right';
            if isxdirnormal
                xlabpos(1) = axlim(2) + 1.5*dxt;
                ylabpos(1) = axlim(1);
            else
                xlabpos(1) = axlim(1) + 1.5*dxt;
                ylabpos(1) = axlim(2);
            end
        else
            xlabhalign = 'right';
            ylabhalign = 'left';
            if isxdirnormal
                xlabpos(1) = axlim(1) - 1.5*dxt;
                ylabpos(1) = axlim(2);
            else
                xlabpos(1) = axlim(2) - 1.5*dxt;
                ylabpos(1) = axlim(1);
            end
        end

        if isxxbottom
            xlabvalign = 'top';
            ylabvalign = 'bottom';
            if isydirnormal
                ylabpos(2) = axlim(4)  + 1.5*dyt;
                xlabpos(2) = axlim(3);
            else
                ylabpos(2) = axlim(3)  + 1.5*dyt;
                xlabpos(2) = axlim(4);
            end
        else
            xlabvalign = 'bottom';
            ylabvalign = 'top';
            if isydirnormal
                ylabpos(2) = axlim(3)  - 1.5*dyt;
                xlabpos(2) = axlim(4);
            else
                ylabpos(2) = axlim(4)  - 1.5*dyt;
                xlabpos(2) = axlim(3);
            end
        end

    end
%--------------------------------------------------------------------------
    function [tickoffset, pvpairs] = extractoffset(tickoffset, varargin)
        pvpairs = varargin;
        npv = nargin - 1;
        if npv>0 && isnumeric(pvpairs{1})
            tickoffset = pvpairs{1};
            pvpairs(1) = [];
            npv = npv - 1;
        end

%         validateattributes(npv, {'numeric'}, {'even'})
%
%         assert((rem(npv,2) == 0), 'Incorrect number of input arguments')

        textpropnames = {'FontAngle', 'FontName', ...
            'FontUnits', 'FontSize', 'FontWeight'};

        textpv = [textpropnames; get(ax, textpropnames)];
        pvpairs = [textpv(:)' pvpairs];
    end
%--------------------------------------------------------------------------
    function ticklab = matchticks(tick, ticklab)
        ntick = numel(tick);
        nticklab = numel(ticklab);
        q = floor(ntick/nticklab);
        r = rem(ntick,nticklab);
        ticklab = ticklab([repmat(1:nticklab, 1, q) 1:r]);
    end
%--------------------------------------------------------------------------
    function ticklab = append10(ticklab, autoticklab, pvpairs)
        if autoticklab
            interpreter = get(0, 'DefaultTextInterpreter');
            if ~isempty(pvpairs)
                tparams = pvpairs(1:2:end-1);
                tvals = pvpairs(2:2:end);
                k = strcmpi('interpreter', tparams);
                if any(k), interpreter = tvals{k}; end
            end
            if strcmpi(interpreter, 'tex')
                d = '';
            else
                d = '$';
            end
            ticklab = cellfun(@(x) [d '10^{' x '}' d], ticklab, 'UniformOutput', false);
        end
    end

end


function [ point, seed ] = p00_sample ( test, m, n, seed )

%*****************************************************************************80
%
%% P00_SAMPLE samples points from the region in a problem.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    10 April 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer TEST, the index of the test problem
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of points.
%
%    Input, integer SEED, a seed for the random number generator.
%
%    Output, real POINT(M,N), the coordinates of the points.
%
%    Output, integer SEED, a seed for the random number generator.
%
  if ( test == 1 )
    [ point, seed ] = p01_sample ( m, n, seed );
  elseif ( test == 2 )
    [ point, seed ] = p02_sample ( m, n, seed );
  elseif ( test == 3 )
    [ point, seed ] = p03_sample ( m, n, seed );
  elseif ( test == 4 )
    [ point, seed ] = p04_sample ( m, n, seed );
  elseif ( test == 5 )
    [ point, seed ] = p05_sample ( m, n, seed );
  elseif ( test == 6 )
    [ point, seed ] = p06_sample ( m, n, seed );
  elseif ( test == 7 )
    [ point, seed ] = p07_sample ( m, n, seed );
  elseif ( test == 8 )
    [ point, seed ] = p08_sample ( m, n, seed );
  elseif ( test == 9 )
    [ point, seed ] = p09_sample ( m, n, seed );
  elseif ( test == 10 )
    [ point, seed ] = p10_sample ( m, n, seed );
  elseif ( test == 11 )
    [ point, seed ] = p11_sample ( m, n, seed );
  elseif ( test == 12 )
    [ point, seed ] = p12_sample ( m, n, seed );
  elseif ( test == 13 )
    [ point, seed ] = p13_sample ( m, n, seed );
  elseif ( test == 14 )
    [ point, seed ] = p14_sample ( m, n, seed );
  elseif ( test == 15 )
    [ point, seed ] = p15_sample ( m, n, seed );
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P00_SAMPLE - Fatal error!\n' );
    fprintf ( 1, '  Input value of TEST is out of range.\n' );
    error ( 'P00_SAMPLE - Fatal error!' );
  end

  return
end


%% Get data from an HTML table straight into MATLAB
% Copyright 2008 - 2010 The MathWorks, Inc.

%% Navigate to a webpage with a table
% You have to use the MATLAB browser because this takes advantage of the
% matlabcolon (matlab:) protocol.
web('http://finance.yahoo.com/q/ks?s=GOOG')
% give it time to load the page
pause(3)
%% Call the function to grab the data
getTableFromWeb
%% Updated Browser
% This shows what the browser looks like.  This is just a screenshot but it
% would be whatever page you are on with MATLAB icons next to tables.
im = imread('mlPage.jpg');
imshow(im);
%% Select the table
% You can select the table interactively by clicking on the MATLAB icon or
% passing a number to the getTableFromWeb function.  I have selected to get
% the Valuation Measures
myTableData = getTableFromWeb(8)


function percent = parfor_progress(N,filenameParfor)
%PARFOR_PROGRESS Progress monitor (progress bar) that works with parfor.
%   PARFOR_PROGRESS works by creating a file called parfor_progress.txt in
%   your working directory, and then keeping track of the parfor loop's
%   progress within that file. This workaround is necessary because parfor
%   workers cannot communicate with one another so there is no simple way
%   to know which iterations have finished and which haven't.
%
%   PARFOR_PROGRESS(N) initializes the progress monitor for a set of N
%   upcoming calculations.
%
%   PARFOR_PROGRESS updates the progress inside your parfor loop and
%   displays an updated progress bar.
%
%   PARFOR_PROGRESS(0) deletes parfor_progress.txt and finalizes progress
%   bar.
%
%   To suppress output from any of these functions, just ask for a return
%   variable from the function calls, like PERCENT = PARFOR_PROGRESS which
%   returns the percentage of completion.
%
%   Example:
%
%      N = 100;
%      parfor_progress(N);
%      parfor i=1:N
%         pause(rand); % Replace with real code
%         parfor_progress;
%      end
%      parfor_progress(0);
%
%   See also PARFOR.

% By Jeremy Scheff - jdscheff@gmail.com - http://www.jeremyscheff.com/

%error(narginchk(0, 1, nargin, 'struct'));

if nargin < 2
    N = -1;
end

percent = 0;
w = 50; % Width of progress bar

if N > 0
    f = fopen(filenameParfor, 'w');
    if f<0
        error('Do you have write permissions for %s?', pwd);
    end
    fprintf(f, '%d\n', N); % Save N at the top of progress.txt
    fclose(f);

    if nargout == 0
        disp(['  0%[>', repmat(' ', 1, w), ']']);
    end
elseif N == 0
    delete(filenameParfor);
    percent = 100;

    if nargout == 0
        disp([repmat(char(8), 1, (w+9)), char(10), '100%[', repmat('=', 1, w+1), ']']);
    end
else
    if ~exist(filenameParfor, 'file')
        error([filenameParfor 'not found. Run PARFOR_PROGRESS(N) before PARFOR_PROGRESS to initialize' filenameParfor '.']);
    end

    f = fopen(filenameParfor, 'a');
    fprintf(f, '1\n');
    fclose(f);

    f = fopen(filenameParfor, 'r');
    progress = fscanf(f, '%d');
    fclose(f);
    percent = (length(progress)-1)/progress(1)*100;

    if nargout == 0
        perc = sprintf('%3.0f%%', percent); % 4 characters wide, percentage
        disp([repmat(char(8), 1, (w+9)), char(10), perc, '[', repmat('=', 1, round(percent*w/100)), '>', repmat(' ', 1, w - round(percent*w/100)), ']']);
    end
end


function DAT = read_excel(excelfilename, has_header_row)
% Reads each sheet of an Excel input file into a data structure DAT
%
% :Usage:
% ::
%
%     DAT = read_excel(excelfilename, has_header_row [1 or 0])
%
%  - reads multiple sheets
%  - adds fields named with variable names for easy access
%  - uses importdata <matlab internal> to do most of the work
%
% ..
%     Author and copyright information:
%     -------------------------------------------------------------------------
%     Copyright (C) 2015 Tor Wager
%
%     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 <http://www.gnu.org/licenses/>.
% ..
%
% :Input:
%
%   **excelfilename:**
%        Char array with full path of input filename
%
% :Outputs:
%
%   **DAT:**
%        Structure with DAT.(sheetname).(varname) data fields
%        DAT.(sheetname).varnames is cell array of var names
%
%   **behdat:**
%        Data structure as read in by importdata
%
% :Examples:
% ::
%
%    excelfilename = fullfile(basedir, 'data', 'SchulzNewcorn_regressor_demograph.xlsx');
%    has_header_row = 1;
%    [DAT, behdat] = read_excel(excelfilename, has_header_row)
%
% :See also:
% importdata, read_database, read_database2, read_edat_output_2008, read_physio_data
%
% ..
%    Programmers' notes:
%    Created by Tor, 7/2015
%    Updated by Tor, Dec 2021 - keep up with changes in importdata behavior
% ..

DAT = struct;

% Note: importdata is not handling blanks in Excel files well. Use xlsread below.
behdat = importdata(excelfilename); % read the original data

has_multiple_sheets = isstruct(behdat.data) || isstruct(behdat.textdata);

if has_multiple_sheets

    % % Sheet names
    % %-------------------
    mysheets = fieldnames(behdat.data);

    for s = 1:length(mysheets)

        [~, ~, raw] = xlsread(excelfilename, s);  % 2021: it doesn't extract data well with blank entries. Use raw and do it ourselves.

        [data_struct, data_table] = process_sheet(raw, has_header_row);

        DAT.(mysheets{s}).raw = raw;
        DAT.(mysheets{s}).data_struct = data_struct;
        DAT.(mysheets{s}).data_table = data_table;

        % DAT.(mysheets{s}).data_table = process_sheet(behdat.data.(mysheets{s}), behdat.textdata.(mysheets{s}), has_header_row);

    end

else
    % One sheet
    [~, ~, raw] = xlsread(excelfilename, 1);

    DAT.raw = raw;
    [DAT.data_struct, DAT.data_table] = process_sheet(raw, has_header_row);

    %     DAT.data_table = process_sheet(behdat.data, behdat.textdata, has_header_row);
end

end % main function

% ------------------------------------------------------------------------
% Subfunctions
% ------------------------------------------------------------------------

function [data_struct, data_table] = process_sheet(raw, has_header_row)
% Create a table object from raw data from xlsread

% % Variable names
if has_header_row

    varnames = raw(1, :);

else
    varnames = cell(1, size(raw, 2));  % textdata only seems to be full-width

    for i = 1:length(varnames)
        varnames{i} = sprintf('Var_%03d', i);
    end

end

varnames = matlab.lang.makeValidName(varnames);

% % Loop through columns
% --------------------

data_struct = struct();

for i = 1:length(varnames)

    fname = varnames{i};

    % figure out if is text and process (replace empty)
    mydat = raw((has_header_row+1):end, i); % skip first row if headers.

    % replace empty, convert to numeric if possible
    mydat = process_data_column(mydat);

    data_struct.(fname) = mydat;

end

data_table = struct2table(data_struct);

end

function mydat = process_data_column(mydat)

% Are some characters text?
is_char = any(cellfun(@ischar, mydat));

if ~is_char
    % already numeric. convert from cell.
    mydat = cat(1, mydat{:});
    return
end

% Below, some entries at least are char arrays. But may be numeric with
% missing values/empty cells

% some empty cells in text are read in as NaN, which can cause errors below
nanvec = false(size(mydat));
for i = 1:length(mydat)
    if isnan(mydat{i}), nanvec(i) = true; else nanvec(i) = false; end
end
mydat(nanvec) = {'NaN'};

% try to replace empty with 'NaN'. We will convert to numeric later.
wh_empty = cellfun(@isempty, mydat);
mydat(wh_empty) = {'NaN'};

% sometimes will read in mixed format: char and numeric.
% if so, we need to convert ALL to char.
% all-numeric is handled above, so here convert if mixed.
is_numeric = cellfun(@isnumeric, mydat);
for i = 1:length(mydat)
    if is_numeric(i)
        mydat{i} = num2str(mydat{i});
    end
end
% mydat{is_numeric} = cellfun(@num2str, mydat(is_numeric));

% try to convert to numeric
%     numdat = cellfun(@str2num, mydat);
numdat = cellfun(@str2num, mydat, 'UniformOutput', false);

% if any empty after replacing blanks, this is text (leave as cell)
istext = any(cellfun(@isempty, numdat));

if istext
    % Leave as cell array, but make NaN empty char
    mydat(wh_empty) = {' '};

else  % numeric
    mydat = cat(1, numdat{:});

end

end % process_data_column

%
%
%
% function data_table = process_sheet(data, textdata, has_header_row)
% % Create a table object from separate numeric data (data) and text data (textdata).
%
% % % Variable names
% if has_header_row
%
%     varnames = textdata(1, :);
%
% else
%     varnames = cell(1, size(textdata, 2));  % textdata only seems to be full-width
%
%     for i = 1:length(varnames)
%         varnames{i} = sprintf('Var_%03d', i);
%     end
%
% end
%
% varnames = matlab.lang.makeValidName(varnames);
%
% % % Get vector of text vs. numeric
% % --------------------
%
%
% % % All data
% % --------------------
%
% data_struct = struct();
%
% numeric_counter = 1;        % Numeric array has reduced number of columns
%
% for i = 1:length(varnames)
%
%     fname = varnames{i};
%
%     % figure out if is text
%     mytext = textdata((has_header_row+1):end, i); % skip first row if headers.
%     istext = ~all(cellfun(@isempty, mytext));
%
%     if istext
%
%         data_struct.(fname) = mytext;
%
%     else  % numeric
%
%         data_struct.(fname) = data(:, numeric_counter);
%         numeric_counter = numeric_counter + 1;
%
%     end
%
% end
%
% end
%


function S = tt_matrix2cellstr(M)
%TT_MATRIX2CELLSTR Convert a matrix to a cell array of strings.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2012) Sandia Corporation. Under the terms of Contract
% DE-AC04-94AL85000, there is a non-exclusive license for use of this
% work by or on behalf of the U.S. Government. Export of this data may
% require a license from the United States Government.
% The full license terms can be found in the file LICENSE.txt

fmt = get(0,'FormatSpacing');
format compact
S = evalc('disp(M)');
set(0,'FormatSpacing',fmt)
S = textscan(S,'%s','delimiter','\n','whitespace','');
S = S{1};
end


function test_bug3007

% WALLTIME 00:10:00
% MEM 2gb
% DEPENDENCY

cd(dccnpath('/home/common/matlab/fieldtrip/data/test/bug3007'))

load cfg
load eye_movs

[cfgout, movement] = ft_detect_movement(cfg, eye_movs);

assert(isstruct(cfgout));
assert(~isstruct(movement)); % should be Nx3 array


function obj = Make_f15( obj, ts, te, dt, varargin )
% obj = Make_f15(obj,ts, te, dt, varargin)
% Input a msh class object, the simulation start time, end times, timestep
% and any other optional arguments and get back a mesh class object with
% the f15 structure populated
%
%  Inputs:   1) A msh class obj (requires nodestrings if you want to get
%               the elevation specified boundary forcings), requires f13
%               populated to put in the NWP names if you want any f13 options.
%            2) ts: the simulation start time in datestring format e.g.
%               ts = '01-Jan-2018 03:00'
%            3) te: the simulation end time in datestring format e.g.
%               te = '01-Feb-2018 22:00'
%            4) dt: the simulation time step in seconds
%            5) Optional name-value arguments:
%
%               'const' : the harmonic constituents to use for the tidal
%               potential, elevation specified boundaries (if you have
%               nodestrings and a tidal database specified), and the
%               harmonic analysis. Give value as a cell array of characters
%               e.g: C = {'M2','S2','K1','O1'}; or a string array,
%               e.g: C = ["M2","S2","K1","O1"]; or u can put:
%                    C = "major8" to do all the major eight constituents
%               Note that the tidal nodal factors and so forth will be
%               automatically calculated based on ts and te.
%
%               'tidal_database' : the directory + filename tidal database of
%               elevations to interpolate to your boundaries.
%               This option requires the 'const' name-value pair input.
%               Use either:
%               a) TPXO9.1 (Netcdf), available for download at:
%                  http://volkov.oce.orst.edu/tides/global.html. The
%                  filename will be 'h_tpxo9.v1.nc'.
%               b) The TPXO Atlas (Netcdf) in which case the filename
%                  is 'h_**_tpxo9_atlas_30.nc' (for e.g., the tpxo9 atlas)
%                  where the wildcard is used in place of the constituent name
%
%               'sta_database' : a cell, where the first element contains
%               a character referring to a specific database. At the moment
%               it only handles CO-OPS/NOS/NOAA stations. The second
%               element contains a scalar either 1,2,3 corresponding to
%               elev, vel and met stations. e.g. set
%               ...('sta_database',{'CO-OPS',1,'NDBC',2,'NDBC',3}) to output
%               the CO-OPS stations for elevation and NDBC stations for velocity and
%               meteorological recording
%
%  Outputs:  1) msh class obj with f15 struct populated
%
%  Author:      William Pringle and Keith Roberts
%  Created:     March 15 2018
%  Updated:     July 15, 2021 by Shintaro Bunya and Keith Roberts
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Putting in default options if f15 isn't already populated
if isempty(obj.f15)
    % Run Description and ID
    f15dat.rundes = obj.title ;  % RUNDES
    f15dat.runid  = 'Run_001' ;  % RUNID
    % NFOVER
    f15dat.nfover = 1 ;
    % NABOUT
    f15dat.nabout = 0 ;
    % NSCREEN
    f15dat.nscreen = 0;
    % IHOT (cold start)
    f15dat.ihot = 0;
    % ICS
    if all(abs(obj.p(:,1))) <= 180 && all(abs(obj.p(:,2))) <= 90
        f15dat.ics = 2 ; % uses lat, lon (probably)
    else
        f15dat.ics = 1 ; % not lat, lon
    end
    % IM (default is explicit with smagorinsky)
    f15dat.im = 511112 ;
    f15dat.iden = [];
    % NOLIBF (normal bottom friction)
    f15dat.nolibf = 1 ;
    % NOLIFA (fininte amplitude terms and wetting-drying on)
    f15dat.nolifa = 2 ;
    % NOLICA (the advection terms on)
    f15dat.nolica = 1 ;
    % NOLICAT (the advection terms on)
    f15dat.nolicat = 1 ;
    % NWP
    f15dat.nwp = 0 ;
    % NCOR
    if f15dat.ics == 2
        f15dat.ncor = 1 ; %spatially varying coriolis from latitude
    else
        f15dat.ncor = 0 ; % read in Coriolis
    end
    % NTIP
    f15dat.ntip = 0 ;
    % NWS
    f15dat.nws = 0 ;
    f15dat.wtimnc = 0;
    % NRAMP
    f15dat.nramp = 0 ;
    % G
    f15dat.gravity = 9.81 ;
    % TAU0 (the automatic spatially varying tau0)
    f15dat.tau0 = -1 ;
    f15dat.tau0minmax = 0;
    % DTDP
    f15dat.dtdp = 0 ;
    % STATIM
    f15dat.statim = 0 ;
    % REFTIM
    f15dat.reftim = 0 ;
    % RNDY
    f15dat.rndy = 0;
    % DRAMP
    f15dat.dramp = 0;
    % A00, B00, C00
    f15dat.a00b00c00 = [0 1 0] ;
    % H0
    f15dat.h0 = [0.1 0 0 0.01];
    % SLAM0, SFEA0
    f15dat.slam = mean(obj.p) ;
    % CF
    f15dat.taucf = 0.0025 ;
    % ESLM (smag 0.05 coefficient)
    f15dat.elsm = -0.05;
    % CORI
    f15dat.cori = 0;
    % NTIF
    f15dat.ntif = 0;
    % NBFR
    f15dat.nbfr = 0 ;
    %  ANGINN
    f15dat.anginn = 90 ;
    % Normal flow external boundary condition (needs to be fixed)
    ibtype = [2 12 22 32 52] ;
    sm = 0 ;
    if ~isempty(obj.bd)
        for k = 1: length(ibtype)
            sm = sm + sum(~(obj.bd.ibtype - ibtype(k))) ;
        end
    end
    if ( sm > 0 )
        f15dat.nffr = 0 ;
    end
    % NOUTE, TOUTSE, TOUTFE, NSPOOLE
    f15dat.oute = zeros(1,4) ;
    f15dat.elvstaloc = [];
    % NSTAE
    f15dat.nstae = 0 ;
    % NOUTV, TOUTV, TOUTFV, NSPOOLV
    f15dat.outv = zeros(1,4);
    f15dat.velstaloc = [];
    % NSTAV
    f15dat.nstav = 0 ;
    % NSTAM, TOUSM, TOUFM, NSPOOLM
    f15dat.outm = zeros(1,4) ;
    f15dat.metstaloc = [];
    % NSTAM
    f15dat.nstam = 0 ;

    % NOUTGE
    f15dat.outge = zeros(1,4) ;
    % NOUTGV
    f15dat.outgv = zeros(1,4) ;
    % NOUTGM
    f15dat.outgm = zeros(1,4);
    % NFREQ
    f15dat.nfreq = 0 ;
    % THAS, THAF, NHAINC, FMV
    f15dat.outhar = zeros(1,4) ;
    % NHASE, NHASV, NHAGE, NHAGV
    f15dat.outhar_flag = zeros(1,4) ;
    % NHSTAR, NHSINC
    f15dat.nhstar = zeros(1,2) ;
    % ITITER, ISLDIA, CONVCR, ITMAX
    f15dat.ititer = [1 0 1e-10 25] ;
    % Extra lines for NETCDF
    f15dat.nextraline = 10;
    f15dat.extraline(1).msg = obj.title ;
    f15dat.extraline(2).msg = 'Affiliation';
    f15dat.extraline(3).msg = 'Made by OceanMesh2D';
    f15dat.extraline(4).msg = 'History: None';
    f15dat.extraline(5).msg = 'https://github.com/CHLNDDEV/OceanMesh2D/';
    f15dat.extraline(6).msg = 'Comments: None' ;
    f15dat.extraline(7).msg = 'Host: Name';
    f15dat.extraline(8).msg = 'Metric, Datum';
    f15dat.extraline(9).msg = 'name@instit.edu';
    f15dat.extraline(10).msg = '';

    % control lists
    % met
    f15dat.controllist(1).type = 'met';
    f15dat.controllist(1).var(1).name = 'WindDragLimit';
    f15dat.controllist(1).var(1).val = 0.0025;
    f15dat.controllist(1).var(2).name = 'PRBCKGRND';
    f15dat.controllist(1).var(2).val = 1013;
    f15dat.controllist(1).var(3).name = 'DragLawString';
    f15dat.controllist(1).var(3).val = 'default';
    f15dat.controllist(1).var(4).name = 'outputWindDrag';
    f15dat.controllist(1).var(4).val = 'F';
    f15dat.controllist(1).var(5).name = 'invertedBarometerOnElevationBoundary';
    f15dat.controllist(1).var(5).val = 'F';
    % dynamicwaterlevelcorrection control
    f15dat.controllist(2).type = 'dynamicWaterLevelCorrection';
    f15dat.controllist(2).var(1).name = [f15dat.controllist(2).type 'FileName'];
    f15dat.controllist(2).var(1).val = 'null';
    f15dat.controllist(2).var(2).name = [f15dat.controllist(2).type 'Multiplier'];
    f15dat.controllist(2).var(2).val = 1.0;
    f15dat.controllist(2).var(3).name = [f15dat.controllist(2).type 'RampStart'];
    f15dat.controllist(2).var(3).val = 0.0;
    f15dat.controllist(2).var(4).name = [f15dat.controllist(2).type 'RampEnd'];
    f15dat.controllist(2).var(4).val = 0.0;
    f15dat.controllist(2).var(5).name = [f15dat.controllist(2).type 'RampReferenceTime'];
    f15dat.controllist(2).var(5).val = 'coldstart';
    f15dat.controllist(2).var(6).name = [f15dat.controllist(2).type 'SkipSnaps'];
    f15dat.controllist(2).var(6).val = 0;

    % Put into the msh class
    obj.f15 = f15dat;
end

%% Changing following parameters based on standard require inputs and
%% populated properties of the msh class
% NSCREEN (once per simulation hour)
obj.f15.nscreen = round(3600/dt);
% DTDP (time step)
obj.f15.dtdp = dt ;
% Runday
obj.f15.rndy = datenum(te)-datenum(ts);

obj.f15.extraline(10).msg = datestr(ts, 'yyyy-mm-dd HH:MM:SS UTC');

% Checking f11
if ~isempty(obj.f11)
    % using WJP's new IM for a 2DDI Baroclinic run
    obj.f15.im = 511113 ;
    obj.f15.iden = 1;
end

% Checking f13
if ~isempty(obj.f13)
    obj.f15.nwp = obj.f13.nAttr ;
    if ( obj.f15.nwp > 0 )
        for l = 1: obj.f15.nwp
            obj.f15.AttrName(l).name = obj.f13.defval.Atr(l).AttrName ;
            if strfind(obj.f15.AttrName(l).name,'primitive')
                obj.f15.tau0 = -3; % change tau0 option
            end
        end
    end
end

%% Test optional arguments
% default
const = [];
tidal_database = [];
sta_database = [];
if ~isempty(varargin)
    names = {'const','tidal_database','NWS','WTIMNC','tau0','tau0minmax',...
             'sta_database'};
    for ii = 1:length(names)
        ind = find(~cellfun(@isempty,strfind(varargin(1:2:end),names{ii})));
        if ~isempty(ind)
            if ii == 1
                const = varargin{ind*2};
            elseif ii == 2
                tidal_database = varargin{ind*2};
            elseif ii == 3
                obj.f15.nws = varargin{ind*2};
            elseif ii == 4
                obj.f15.wtimnc = varargin{ind*2};
            elseif ii == 5
                obj.f15.tau0 = varargin{ind*2};
            elseif ii == 6
                obj.f15.tau0minmax = varargin{ind*2};
            elseif ii == 7
                sta_database = varargin{ind*2};
            end
        end
    end
end

%% Changing following parameters based on optional argument inputs
% WTIMINC
if obj.f15.nws > 0 %~mod(obj.f15.nws - 1,10) ||  ~mod(obj.f15.nws - 11,10) || obj.f15.nws == 8
    if obj.f15.wtimnc == 0
        error(['Must specify WTIMNC option with NWS = ' num2str(obj.f15.nws)])
    end
end

% Tau0FullDomainMin, Tau0FullDomainMax
if ( abs(obj.f15.tau0 + 5.D0) < 1e-10 )
    if obj.f15.tau0minmax == 0
        error(['Must specify tau0minmax with tau0 option = ' num2str(obj.f15.tau0)])
    end
end

% Tidal potential and harmonic analysis stuff
if ~isempty(const)
    % Get the tidal factors etc based on ts and te
    if ischar(const)
        const = {const};
    end
    obj = tide_fac(obj,ts,te,const);

    % Harmonic analysis stuff (copy in tidal potential)
    obj.f15.nfreq = obj.f15.ntif; K = [];
    for k = 1: obj.f15.nfreq
        obj.f15.harfreq(k).name = obj.f15.tipotag(k).name;
        % get only the frequencies, nodal factor and equilibrium argument
        obj.f15.harfreq(k).val = obj.f15.tipotag(k).val([2,4,5]);
        if isnan(obj.f15.tipotag(k).val(1))
            % get rid of this constituent from potential
            obj.f15.ntif = obj.f15.ntif - 1;
            K(end+1) = k;
        end
    end
    obj.f15.tipotag(K) = [];

    if obj.f15.ntip == 0
        disp('Setting ntip = 1')
        obj.f15.ntip = 1;
    end
end

% Elevation Specified Boundary Conditions (tides)
if ~isempty(const) && ~isempty(tidal_database)
    % copy in the harmonic analysis stuff
    obj.f15.nbfr = obj.f15.nfreq;
    for k = 1: obj.f15.nbfr
        obj.f15.bountag(k).name = obj.f15.harfreq(k).name;
        % get only the frequencies, nodal factor and equilibrium argument
        obj.f15.bountag(k).val = obj.f15.harfreq(k).val;
    end

    % Do the interpolation to the boundaries
    obj = tidal_data_to_ob(obj,tidal_database,{obj.f15.bountag.name});
end

if ~isempty(const)
   % Here for the SA tidal potential the equilibrium argument is now
   % corrected to be referenced to the vernal equinox (subtract of about
   % 77 deg). But the equilibrim argument for the boundary and the analysis
   % is kept as referenced to the Calender year.
   ii = find(startsWith({obj.f15.tipotag.name},'SA'));
   if ~isempty(ii)
       % need to refer to vernal equinox instead of calender year,
       % at least for the tidal potential (subtract about 76.9 deg);
       obj.f15.tipotag(ii).val(5) = obj.f15.tipotag(ii).val(5) - 78/365*360;
       if obj.f15.tipotag(ii).val(5) < 0
          obj.f15.tipotag(ii).val(5) = obj.f15.tipotag(ii).val(5) + 360;
       end
   end
end
%
if ~isempty(sta_database)
    % parse the station reader
    obj = tidal_stations_parser(obj,string(sta_database(1:2:end-1)),...
                                sta_database(2:2:end));
end
%
% % NOUTGC
% if ( f15dat.im == 10 )
%     f15dat.outgc = readlinevec( fid ) ;
% end
%
% % NOUTGW
% if ( f15dat.nws ~= 0 )
%     f15dat.outgw = readlinevec( fid ) ;
% end

end


classdef TestCvtColor
    %TestCvtColor

    properties (Constant)
        im = fullfile(mexopencv.root(),'test','img001.jpg');
    end

    methods (Static)
        function test_1
            img = imread(TestCvtColor.im);
            [h,w,~] = size(img);
            result = cv.cvtColor(img, 'RGB2GRAY');
            validateattributes(result, {class(img)}, {'2d', 'size',[h,w]});
        end

        function test_2
            img = imread(TestCvtColor.im);
            result = cv.cvtColor(img, 'RGB2GRAY', 'DstCn',0);
        end

        function test_3
            img = cv.imread(TestCvtColor.im, 'Grayscale',true);
            result = cv.cvtColor(img, 'GRAY2RGB');
            validateattributes(result, {class(img)}, ...
                {'3d', 'size',[NaN NaN 3]});
        end

        function test_4
            codes = {'RGB2BGR', 'RGB2XYZ', 'RGB2YCrCb', 'RGB2YUV', ...
                'RGB2HSV', 'RGB2HLS', 'RGB2Lab', 'RGB2Luv'};
            img = imread(TestCvtColor.im);
            [h,w,~] = size(img);
            for i=1:numel(codes)
                result = cv.cvtColor(img, codes{i});
                validateattributes(result, {class(img)}, ...
                    {'3d', 'size',[h,w,3]});
            end
        end

        function test_error_argnum
            try
                cv.cvtColor();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


function len = s_len_trim ( s )

%*****************************************************************************80
%
%% S_LEN_TRIM returns the length of a string to the last nonblank.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 June 2003
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string S, the string to be measured.
%
%    Output, integer LEN, the length of the string up to the last nonblank.
%
  len = length ( s );

  while ( 0 < len )
    if ( s(len) ~= ' ' )
      return
    end
    len = len - 1;
  end

  return
end


function region = p14_region ( )

%*****************************************************************************80
%
%% P14_REGION returns the name of the integration region for problem 14.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string REGION, the name of the integration region.
%
  region = 'box';

  return
end


%kkmsquish 'Compress Map to One Column by Means of Average, RMS, or MAX'
% This MatLab function was automatically generated by a converter (KhorosToMatLab) from the Khoros kmsquish.pane file
%
% Parameters:
% InputFile: i 'Input ', required: 'First Input data object'
% MultiChoice: t 'Squishing scheme', default: 1: 'squishing scheme (1)average, (2)RMS, (3)Maximum'
%    Choices are:
%   1: 'Average of map columns'
%   2: 'RMS value of map columns'
%   3: 'Maximum value of mape columns'
% OutputFile: o 'Output', required: 'Resulting output data object'
%
% Example: o = kkmsquish(i, {'i','';'t',1;'o',''})
%
% Khoros helpfile follows below:
%
%  PROGRAM
% kmsquish - Compress Map to One Column by Means of Average, RMS, or MAX
%
%  DESCRIPTION
% kmsquish compresses a map down to one column, effectively
% converting the map to a "greyscale" map. An example of
% this operation is encountered when trying to print a
% pseudocolor RGB image on a B/W laser printer: the RGB
% color information must be somehow converted to greyscale
% in order for the printer to know how to dither the image
% during printing.
%
% kmsquish is very happy to operate on simple 3-column
% maps, such as would be encountered when processing a
% color image in any of the standard coordinate systems
% (ntscRGB, etc). However, kmsquish is not limited to 3 column
% maps - it will operate on maps with any number of cloumns.
%
% The conversion from multiple columns to a single column
% is done by computing a grey level for each row of the map,
% one at a time.  For t=1, the grey level for a row is the
% average of the columns in the row. For t=2, the grey
% level is the RMS value of the columns in the row. For t=3,
% the grey level is the maximum value found in the colums of
% the row. Clearly, these schemes are not optimal in any sense,
% but one of them will usually give an acceptable result.
%
% Ordinarily (map=0), the map is the only part of the input
% object that is modified. The value data is not touched; it
% still points to various rows in the map just as before the
% compression. If map=1, the value data is pulled thru the
% map and the map segment itself is removed. If mask data
% is present, then this operation proceeds as described in
% the man page for kmapdata(1).
%
%
%
%  EXAMPLES
%
% Squishing and mapping an image that is to be printed.
% kmsquish -i ball.xv.color -o ball.ready.to.print
% here, -m pand -t do not need to be specified since the defaults are
% set correctly.
%
%  "SEE ALSO"
% igamut(1), kmapdata(1)
%
%  RESTRICTIONS
% Complex data is not supported.
%
%  REFERENCES
%
%  COPYRIGHT
% Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI")  All rights reserved.
%

function varargout = kkmsquish(varargin)
if nargin ==0
  Inputs={};arglist={'',''};
elseif nargin ==1
  Inputs=varargin{1};arglist={'',''};
elseif nargin ==2
  Inputs=varargin{1}; arglist=varargin{2};
else error('Usage: [out1,..] = kkmsquish(Inputs,arglist).');
end
if size(arglist,2)~=2
  error('arglist must be of form {''ParameterTag1'',value1;''ParameterTag2'',value2}')
 end
narglist={'i', '__input';'t', 1;'o', '__output'};
maxval={0,0,0};
minval={0,0,0};
istoggle=[0,0,0];
was_set=istoggle * 0;
paramtype={'InputFile','MultiChoice','OutputFile'};
% identify the input arrays and assign them to the arguments as stated by the user
if ~iscell(Inputs)
Inputs = {Inputs};
end
NumReqOutputs=1; nextinput=1; nextoutput=1;
  for ii=1:size(arglist,1)
  wasmatched=0;
  for jj=1:size(narglist,1)
   if strcmp(arglist{ii,1},narglist{jj,1})  % a given argument was matched to the possible arguments
     wasmatched = 1;
     was_set(jj) = 1;
     if strcmp(narglist{jj,2}, '__input')
      if (nextinput > length(Inputs))
        error(['Input ' narglist{jj,1} ' has no corresponding input!']);
      end
      narglist{jj,2} = 'OK_in';
      nextinput = nextinput + 1;
     elseif strcmp(narglist{jj,2}, '__output')
      if (nextoutput > nargout)
        error(['Output nr. ' narglist{jj,1} ' is not present in the assignment list of outputs !']);
      end
      if (isempty(arglist{ii,2}))
        narglist{jj,2} = 'OK_out';
      else
        narglist{jj,2} = arglist{ii,2};
      end

      nextoutput = nextoutput + 1;
      if (minval{jj} == 0)
         NumReqOutputs = NumReqOutputs - 1;
      end
     elseif isstr(arglist{ii,2})
      narglist{jj,2} = arglist{ii,2};
     else
        if strcmp(paramtype{jj}, 'Integer') & (round(arglist{ii,2}) ~= arglist{ii,2})
            error(['Argument ' arglist{ii,1} ' is of integer type but non-integer number ' arglist{ii,2} ' was supplied']);
        end
        if (minval{jj} ~= 0 | maxval{jj} ~= 0)
          if (minval{jj} == 1 & maxval{jj} == 1 & arglist{ii,2} < 0)
            error(['Argument ' arglist{ii,1} ' must be bigger or equal to zero!']);
          elseif (minval{jj} == -1 & maxval{jj} == -1 & arglist{ii,2} > 0)
            error(['Argument ' arglist{ii,1} ' must be smaller or equal to zero!']);
          elseif (minval{jj} == 2 & maxval{jj} == 2 & arglist{ii,2} <= 0)
            error(['Argument ' arglist{ii,1} ' must be bigger than zero!']);
          elseif (minval{jj} == -2 & maxval{jj} == -2 & arglist{ii,2} >= 0)
            error(['Argument ' arglist{ii,1} ' must be smaller than zero!']);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} < minval{jj})
            error(['Argument ' arglist{ii,1} ' must be bigger than ' num2str(minval{jj})]);
          elseif (minval{jj} ~= maxval{jj} & arglist{ii,2} > maxval{jj})
            error(['Argument ' arglist{ii,1} ' must be smaller than ' num2str(maxval{jj})]);
          end
        end
     end
     if ~strcmp(narglist{jj,2},'OK_out') &  ~strcmp(narglist{jj,2},'OK_in')
       narglist{jj,2} = arglist{ii,2};
     end
   end
   end
   if (wasmatched == 0 & ~strcmp(arglist{ii,1},''))
        error(['Argument ' arglist{ii,1} ' is not a valid argument for this function']);
   end
end
% match the remaining inputs/outputs to the unused arguments and test for missing required inputs
 for jj=1:size(narglist,1)
     if  strcmp(paramtype{jj}, 'Toggle')
        if (narglist{jj,2} ==0)
          narglist{jj,1} = '';
        end;
        narglist{jj,2} = '';
     end;
     if  ~strcmp(narglist{jj,2},'__input') && ~strcmp(narglist{jj,2},'__output') && istoggle(jj) && ~ was_set(jj)
          narglist{jj,1} = '';
          narglist{jj,2} = '';
     end;
     if strcmp(narglist{jj,2}, '__input')
      if (minval{jj} == 0)  % meaning this input is required
        if (nextinput > size(Inputs))
           error(['Required input ' narglist{jj,1} ' has no corresponding input in the list!']);
        else
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        end
      else  % this is an optional input
        if (nextinput <= length(Inputs))
          narglist{jj,2} = 'OK_in';
          nextinput = nextinput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end;
     else
     if strcmp(narglist{jj,2}, '__output')
      if (minval{jj} == 0) % this is a required output
        if (nextoutput > nargout & nargout > 1)
           error(['Required output ' narglist{jj,1} ' is not stated in the assignment list!']);
        else
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
          NumReqOutputs = NumReqOutputs-1;
        end
      else % this is an optional output
        if (nargout - nextoutput >= NumReqOutputs)
          narglist{jj,2} = 'OK_out';
          nextoutput = nextoutput + 1;
        else
          narglist{jj,1} = '';
          narglist{jj,2} = '';
        end;
      end
     end
  end
end
if nargout
   varargout = cell(1,nargout);
else
  varargout = cell(1,1);
end
global KhorosRoot
if exist('KhorosRoot') && ~isempty(KhorosRoot)
w=['"' KhorosRoot];
else
if ispc
  w='"C:\Program Files\dip\khorosBin\';
else
[s,w] = system('which cantata');
w=['"' w(1:end-8)];
end
end
[varargout{:}]=callKhoros([w 'kmsquish"  '],Inputs,narglist);


% AddTextToImageWithBorderDemo is a script to demonstrate what
% AddTextToImageWithBorder does.
% It takes about 45 seconds to run on my desktop PC - most of that time is
% spent generating the fonts and displaying the images.
%
% Daniel Warren
% Particle Therapy Cancer Research Institute
% University of Oxford

Image = ones([500 500 3]);

Iterations = 200;

Strings = {'text','image'};

FontNames = {'Arial','Times New Roman','Comic Sans MS','Century Gothic',...
         'Script MT Bold','Courier New','OCR A Extended','Verdana',...
         'Gill Sans MT','Calibri','Cambria'};

FontSizes = 10:20:150;

ThickestBorder = 4;

k = 0;
Fonts = cell(1,length(FontNames)*length(FontSizes));
for i = 1:length(FontNames)
    for j = 1:length(FontSizes)
        k = k+1;
        Fonts{k} = BitmapFont(FontNames{i},FontSizes(j),unique([Strings{:}]));
    end
end

StringIndices = ceil(rand(Iterations,1)*length(Strings));
FontIndices = ceil(rand(Iterations,1)*length(Fonts));
Colors = hsv2rgb([rand(Iterations,1) 0.7+0.3*rand(Iterations,1) 0.9+0.1*rand(Iterations,1)]);
BorderColors = 0.5-(Colors-0.5);
BorderWidths = round(rand(Iterations,1)*ThickestBorder);
XPositions = ceil((-0.2+1.2*rand(1,Iterations))*size(Image,1));
YPositions = ceil((-0.1+1.1*rand(1,Iterations))*size(Image,2));

figure('Units','Pixels','Position',[50 50 50+size(Image,1) 50+size(Image,2)]);
handle = image(Image);
set(gca,'Units','Normalized','Position',[0 0 1 1]);
axis off image;
for i = 1:Iterations
    Image = AddTextToImageWithBorder(Image,Strings{StringIndices(i)},[XPositions(i) YPositions(i)],Colors(i,:),Fonts{FontIndices(i)},[],BorderWidths(i),BorderColors(i,:));
    set(handle,'CData',Image);
    drawnow;
end


% Simple functino for visualizing the trajectory
% of a motor program M
function simpleViz(M)

    cell_traj = M.motor_warped;
    ns = numel(cell_traj);

    hold on
    for sid=1:ns
        stroke = cell_traj{sid};
        nsub = length(stroke);
        for b=1:nsub
            plot_traj(cell_traj{sid}{b});
        end
    end

    xlim([0 105]);
    ylim([-105 0]);
    box on
end

function plot_traj(T)
    plot(T(:,1),T(:,2),'k','LineWidth',2);
end


% -------------------------------------------------------------------------
%
%     Demo software for V-BM4D volumetric data denoising
%               Release ver. 1.0  (11 December 2014)
%
% -------------------------------------------------------------------------
%
% The software implements the V-BM4D denoising algorithm described in:
%
%    M. Maggioni, G. Boracchi, A. Foi, K. Egiazarian, "Video Denoising
%      Using Separable 4D Nonlocal Spatiotemporal Transforms",
%      Proc. SPIE Electronic Imaging 2011, San Francisco, CA, USA.
%
%    M. Maggioni, G. Boracchi, A. Foi, K. Egiazarian, "Video Denoising,
%      Deblocking and Enhancement Through Separable 4-D Nonlocal
%      Spatiotemporal Transforms", IEEE Trans. on Image Proc.,
%      Vol. 21, No. 9, Sep. 2012. doi:10.1109/TIP.2012.2199324
%
% -------------------------------------------------------------------------
%
% authors:               Matteo Maggioni
%                        Alessandro Foi
%
% web page:              http://www.cs.tut.fi/~foi/GCF-BM3D
%
% contact:               firstname.lastname@tut.fi
%
% -------------------------------------------------------------------------
% Copyright (c) 2010-2014 Tampere University of Technology.
% All rights reserved.
% This work should be used for nonprofit purposes only.
% -------------------------------------------------------------------------
%
% Disclaimer
% ----------
%
% Any unauthorized use of these routines for industrial or profit-oriented
% activities is expressively prohibited. By downloading and/or using any of
% these files, you implicitly agree to all the terms of the TUT limited
% license (included in the file Legal_Notice.txt).
% -------------------------------------------------------------------------

clear all;close all;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Modifiable parameters
file_name = '';      % Video file name. If empty, a prompt dialog will appear
sigma     = 25;      % Noise standard deviation. it should be in the same
                     % intensity range of the video
profile = 'lc';      % V-BM4D parameter profile
                     %  'lc' --> low complexity
                     %  'np' --> normal profile
do_wiener = 1;       % Wiener filtering
                     %   1 --> enable Wiener filtering
                     %   0 --> disable Wiener filtering
sharpen = 1;         % Sharpening
                     %   1 --> disable sharpening
                     %  >1 --> enable sharpening
deflicker = 1;       % Deflickering
                     %   1 --> disable deflickering
                     %  <1 --> enable deflickering
verbose = 1;         % Verbose mode

est_noise = 0;       % Enable noise estimation

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%       MODIFY BELOW THIS POINT ONLY IF YOU KNOW WHAT YOU ARE DOING       %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% If no file_name is given, let the user select a file from local disk
if isempty(file_name)
    [ file_name, folder ] = uigetfile({'*.avi'}, 'Select Video');
    if isequal(file_name,0)
        error('No file selected.')
    end
    file_name = [folder,file_name];
end
if strcmpi(file_name(end-2:end),'mat')
    % if a matlab file is given, the noise-free video is assumed to be
    % saved as a 3-D matrix called "y"
    load(file_name)
else
    % video formats mast be readable by VideoReader ('help VideoReader')
    y = read_video(file_name);
end

% Scaling data
S = 255;
I_MAX = 255/S;
% Create synthetic Gaussian noise
randn('seed',0);
y = cast(y, 'single')/S;
sigma = sigma/S;
z = y + sigma*randn(size(y));
% Set sigma to -1 to enable noise estimation
if est_noise
    sigma = -1;
end

% V-BM4D filtering
disp('Denoising started')
tic;
y_est = vbm4d( z, sigma, profile, do_wiener, sharpen, deflicker, verbose );
time = toc;
PSNR = 10*log10(I_MAX^2/mean((y(:)-y_est(:)).^2));
fprintf('Denoising completed (%.1fs / %.1ffps): PSNR %.2fdB \n', time, size(z,ndims(z))/time, PSNR);

% Show results
f = round(size(y,3)/2);
figure,imshow([y(:,:,f) z(:,:,f) y_est(:,:,f)],[])


function map = tab20c(N)
% Qualitative colormap from MatPlotLib, for plots using the line ColorOrder.
% In MatPlotLib 2 it is named VEGA20C, for MatPlotLib 3 was renamed TAB20C.
%
% Copyright (c) 2017-2020 Stephen Cobeldick
%
%%% Syntax:
%  map = tab20c
%  map = tab20c(N)
%
% For MatPlotLib 2.0 improved colormaps were created for plot lines of
% categorical data. The new colormaps are introduced here:
% <http://matplotlib.org/2.0.0rc2/users/dflt_style_changes.html>
% VEGA10/TAB10 is the default Line Color Order for MatPlotLib 2 and 3.
%
% MATLAB axes ColorOrder (note that this is NOT the axes COLORMAP):
% <https://www.mathworks.com/help/matlab/creating_plots/defining-the-color-of-lines-for-plotting.html>
% <https://www.mathworks.com/help/matlab/graphics_transition/why-are-plot-lines-different-colors.html>
%
%% Examples %%
%
%%% PLOT using matrices:
% N = 20;
% axes('ColorOrder',tab20c(N),'NextPlot','replacechildren')
% X = linspace(0,pi*3,1000);
% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N);
% plot(X,Y, 'linewidth',4)
%
%%% PLOT in a loop:
% N = 20;
% set(0,'DefaultAxesColorOrder',tab20c(N))
% X = linspace(0,pi*3,1000);
% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N);
% for n = 1:N
%     plot(X(:),Y(:,n), 'linewidth',4);
%     hold all
% end
%
%%% LINE using matrices:
% N = 20;
% set(0,'DefaultAxesColorOrder',tab20c(N))
% X = linspace(0,pi*3,1000);
% Y = bsxfun(@(x,n)sqrt(n)*cos(x+2*n*pi/N), X(:), 1:N);
% line(X(:),Y)
%
%% Input and Output Arguments %%
%
%%% Inputs (*=default):
% N = NumericScalar, N>=0, an integer to define the colormap length.
%   = *[], use the length of the current figure's colormap (see COLORMAP).
%
%%% Outputs:
% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1.
%
% See also TAB10 TAB20 TAB20B SET TWILIGHT VIRIDIS LINES COLORMAP PARULA

if nargin<1 || isnumeric(N)&&isequal(N,[])
	N = size(get(gcf,'colormap'),1);
else
	assert(isscalar(N)&&isfinite(N)&&isreal(N),...
		'SC:tab20c:N:NotRealFiniteScalarNumeric',...
		'First argument <N> must be a real finite numeric scalar.')
end
%
hex = ['#3182bd';'#6baed6';'#9ecae1';'#c6dbef';'#e6550d';'#fd8d3c';'#fdae6b';'#fdd0a2';'#31a354';'#74c476';'#a1d99b';'#c7e9c0';'#756bb1';'#9e9ac8';'#bcbddc';'#dadaeb';'#636363';'#969696';'#bdbdbd';'#d9d9d9'];
raw = sscanf(hex.','#%2x%2x%2x',[3,Inf]).';
%
map = raw(1+mod(0:N-1,size(raw,1)),:) / 255;
%
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%tab20c


classdef TestNiBlackThreshold
    %TestNiBlackThreshold

    properties (Constant)
        im = fullfile(mexopencv.root(),'test','sudoku.jpg');
    end

    methods (Static)
        function test_1
            img = cv.imread(TestNiBlackThreshold.im, 'Grayscale',true);
            out = cv.niBlackThreshold(img, -0.2);
            validateattributes(out, {class(img)}, {'size',size(img)});
        end

        function test_2
            img = cv.imread(TestNiBlackThreshold.im, 'Grayscale',true);
            out = cv.niBlackThreshold(img, 0.2, ...
                'Type','Binary', 'BlockSize',7, 'MaxValue',255);
            validateattributes(out, {class(img)}, {'size',size(img)});
        end

        function test_error_argnum
            try
                cv.niBlackThreshold();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


function datwrite(filename, x, t)
%DATWRITE Write data to ascii file.
%
%	Description
%
%	DATWRITE(FILENAME, X, T) takes a matrix X of input vectors and a
%	matrix T of target vectors and writes them to an ascii file named
%	FILENAME. The file format is as follows: the first row contains the
%	string NIN followed by the number of inputs, the second row contains
%	the string NOUT followed by the number of outputs, and the third row
%	contains the string NDATA followed by the number of data vectors.
%	Subsequent lines each contain one input vector followed by one output
%	vector, with individual values separated by spaces.
%
%	See also
%	DATREAD
%

%	Copyright (c) Ian T Nabney (1996-2001)

nin = size(x, 2);
nout = size(t, 2);
ndata = size(x, 1);

fid = fopen(filename, 'wt');
if fid == -1
  error('Failed to open file.')
end

if size(t, 1) ~= ndata
  error('x and t must have same number of rows.');
end

fprintf(fid, ' nin   %d\n nout  %d\n ndata %d\n', nin , nout, ndata);
for i = 1 : ndata
  fprintf(fid, '%13e ', x(i,:), t(i,:));
  fprintf(fid, '\n');
end

flag = fclose(fid);
if flag == -1
  error('Failed to close file.')
end


function [mergedImage, newDimLabel] = ...
    merge(this, mergeDims, varargin)
% Merges multiple dimensions into one dimensions
%
%   Y = MrImage()
%   mergedImage = Y.merge({'echo', 't'})
%
% This is a method of class MrImage.
%
% IN
%   mergeDims       which dims should be merged into one dim
%                   can be numeric [1,4] or character {'coil', 't'}
%                   Note that the order of mergeDims in the input
%                   determines their order in the mergedImage, i.e.
%                   I.merge({'coil', 't'}) is different from I.merge({'t',
%                   'coil'}). Also, the mergedDim is always the last in the
%                   new image; use permute to change that.
%
%   varargin        prop/val pairs to describe the new dimension
%                   including resolutions, ranges, dimLabels, units,
%                   samplingPoints, samplingWidths
%                   defaults:   samplingPoints = 1:nSamples
%                               dimLabels = [oldDimLabels(1), '_', ...
%                               '_', olDimLabels(end)]
%                               units = ''
% OUT
%
% EXAMPLE
%   merge
%
%   See also MrImage

% Author:   Saskia Bollmann & Lars Kasper
% Created:  2019-12-23
% Copyright (C) 2019 Institute for Biomedical Engineering
%                    University of Zurich and ETH Zurich
%
% This file is part of the TAPAS UniQC Toolbox, which is released
% under the terms of the GNU General Public License (GPL), version 3.
% You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version).
% For further details, see the file COPYING or
%  <http://www.gnu.org/licenses/>.

mergedImage = this.copyobj();
newDimLabel = [];
if ~isempty(mergeDims)
    % create merged dimInfo first - this also give the new labels and sampling
    % points
    [mergedDimInfo, ~, newDimLabel] = this.dimInfo.merge(mergeDims, varargin);

    % only split if more than one mergeDim is actually given
    if numel(mergeDims) > 1
        % split into individual images
        split_array = this.split('splitDims', mergeDims);
        split_array = reshape(split_array, 1, []);

        % overwrite the sampling points to the newly created ones
        for n = 1:numel(split_array)
            split_array{n}.dimInfo = mergedDimInfo.select(newDimLabel, n);
        end

        % use combine to merge image along non-singleton dimension
        mergedImage = split_array{1}.combine(split_array);
    else % otherwise just change the dimLabel
        mergedImage.dimInfo = mergedDimInfo;
    end
end
end


function jed = epoch_to_jed_roman ( )

%*****************************************************************************80
%
%% EPOCH_TO_JED_ROMAN returns the epoch of the Roman calendar as a JED.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%     15 June 2012
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real JED, the Julian Ephemeris Date of the epoch.
%
  jed = 1446389.5;

  return
end


function c = typeadj(a,TYPE)
%TYPEADJ      typecast of  a  to type TYPE
%
%   c = typeadj(a,TYPE)
%
%For details, see intval\typeof and intval\typeadj.
%

% written  12/06/98     S.M. Rump
% modified 04/04/04     S.M. Rump  set round to nearest for safety
% modified 04/06/05     S.M. Rump  rounding unchanged
%

% slope\@slope\typeadj:  a  must be slope
  switch TYPE
    case 'slope',          c = a;
  otherwise
    error('invalid type in call of typeadj')
  end


 function varargout = num2list(x)
%function varargout = num2list(x)
%
% convert a numeric vector input into a comma separated list of output values
% DOES NOT WORK!

if nargin < 1, num2list_test, ir_usage, end
%nargout
%nargout = numel(x)
%varargout = cell(size(x));

for ii=1:numel(x)
	varargout{ii} = x(ii);
end

function num2list_test
zeros(num2list([2 3 4 5]))


function varargout = plot(f, varargin)
%PLOT   Basic linear plot for TRIGTECH objects.
%   PLOT(F) plots the TRIGTECH object F.
%
%   PLOT(F, S) allows various line types, plot symbols, and colors to be used
%   when S is a character string made from one element from any or all the
%   following 3 columns:
%
%            b     blue          .     point              -     solid
%            g     green         o     circle             :     dotted
%            r     red           x     x-mark             -.    dashdot
%            c     cyan          +     plus               --    dashed
%            m     magenta       *     star             (none)  no line
%            y     yellow        s     square
%            k     black         d     diamond
%            w     white         v     triangle (down)
%                                ^     triangle (up)
%                                <     triangle (left)
%                                >     triangle (right)
%                                p     pentagram
%                                h     hexagram
%
%   The entries from the centre columns are plotted at TRIGPTS being
%   used to represent F. If no options from this column are chosen, 'o' is
%   chosen by default if LENGTH(F) < 256.
%
%   The X,Y pairs, or X,Y,S triples, can be followed by parameter/value pairs to
%   specify additional properties of the lines. For example,
%            f = trigtech.constructor(@sin);
%            plot(f, 'LineWidth', 2, 'Color', [.6 0 0])
%   will create a plot with a dark red line width of 2 points.
%
%   H1 = PLOT(F) returns a column vector of handles to lineseries objects, one
%   handle per plotted line (in the case of array-valued TRIGTECH objects).
%   [H1, H2] returns a second vector of column handles, this time for each of
%   the marker plots.
%
% See also PLOT3, PLOTDATA.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Deal with an empty input:
if ( isempty(f) )
    if ( nargout == 1 )
        varargout{1} = plot([]);
    end
    return
end

% Store the hold state of the current axis:
holdState = ishold;

%%
% Get the data for plotting from PLOTDATA():
if ( nargin > 1 && isa(varargin{1}, 'trigtech') )
    % Deal with plot(f, g);
    g = varargin{1};
    varargin(1) = [];
    % We can only plot real against real:
    f = real(f);
    g = real(g);
    % Call PLOTDATA():
    data = plotData(f, g);
else
    g = [];
    data = plotData(f);
end

%%
% Plot the curve:
if ( isreal(f) )
    h1 = plot(real(data.xLine), real(data.yLine), varargin{:});
else
    h1 = plot(data.yLine, varargin{:});
end
set(h1, 'Marker', 'none')
hold on

%%
% Plot the points:
if ( isreal(f) )
    h2 = plot(real(data.xPoints), real(data.yPoints), varargin{:});
else
    h2 = plot(data.yPoints, varargin{:});
end

% Change the style accordingly:
set(h2,'LineStyle', 'none')
if ( all(strcmp(get(h2, 'Marker'), 'none')) && (length(f) < 257) )
    set(h2, 'Marker', 'o')
end

%%

% Return hold state to what it was before:
if ( ~holdState )
    hold off
end

% Give an output if one was requested:
if ( nargout > 0 )
    varargout{1} = h1;
    varargout{2} = h2;
end

end


function [results_table_pos, results_table_neg, r, excluded_region_table, r_excluded, region_list] = table_of_atlas_regions_covered(r, varargin)
% Make a table of which atlas parcels are covered by a set of regions or map identified in a study
%
% [results_table_pos, results_table_neg, r, excluded_region_table, r_excluded, region_list] = table_of_atlas_regions_covered(r, [atlas_obj])
%
% fMRI activation maps often include large suprathreshold areas that span
% multiple brain regions.  Traditional tables divide areas by contiguous
% regions ("blobs"), but this type of division is not useful if blobs cannot
% be easily summarized by a single anatomical label. A complementary approach
% is to identify which areas defined in a standard brain atlas ("parcels")
% are covered by the activation map. Parcels can be defined based on anatomy
% (e.g., cytoarchitecture) or function (e.g., resting-state fMRI).
% For example, a large blob may span the insula, claustrum, and putamen.
% This can be described in a table that lists all of these regions, along with
% the percentage of each parcel covered by the activation map.
%
% This function uses the object method subdivide_by_atlas() to create such
% a table, which is dividided into two tables with positive and negative average
% statistic values (results_table_pos, results_table_neg). These are Matlab
% table-class objects.  It also returns a region-class object for reference
% and rendering the subdivided blobs on brain slices or surfaces.
%
% The default threshold for coverage is 25% or more of the atlas parcel
% covered by the activation map.
%
% You can enter any atlas-class object as a 2nd argument. If you don't,
% a default atlas object will be used.
%
% Examples:
% -----------------------------------------------------------------
% % Load a thresholded map:
% % (Note: You must have Neuroimaging_Pattern_Masks repo with subfolders on your path)
% % This is a predictive map for drug craving (Koban et al. 2022, Nat Neurosci)
%
% ncsthr = fmri_data(which('NCS_multithr_001k5_005_05_pruned.nii'), 'noverbose');
%
% % Convert to region object:
% r = region(ncsthr);
%
% [results_table_pos, results_table_neg, r, excluded_region_table, table_legend_text] = table_of_atlas_regions_covered(r);
% montage(r, 'regioncenters', 'colormap');
%
% % Also see large blobs that didn't sufficiently cover any one atlas parcel:
% montage(r_excluded(cat(1, r_excluded.numVox) > 20), 'regioncenters', 'colormap');
%
% % You can use the image_vector method to apply this to a single-image
% % thresholded map:
% [results_table_pos, results_table_neg, r, excluded_region_table, r_excluded, region_labels] = table_of_atlas_regions_covered(ncsthr);
%
% Note: For a key to labels when using the Glasser 2016 Nature atlas, or the
% CANlab combined atlas (which uses Glasser), see GlasserTableS1.pdf in the
% original paper or CANlab github, or http://braininfo.rprc.washington.edu/
%
% see also region.table, for autolabeling of regions with an atlas and more
% detailed table output.
%
% Tor Wager, Feb 2023

n_cols = 140;                       % 140 good for HTML reports
sep_str = repmat('_', 1, n_cols);   % see textwrap

dosep = true;
dolegend = true;
table_legend_text = '';

[results_table_pos, results_table_neg] = deal(table());

if isempty(r) || length(r) == 0
    disp('No regions to display');
    return
end

if ~isempty(varargin)

    atlas_obj = varargin{1};
    if ~isa(atlas_obj, 'atlas'), error('2nd input must be an atlas-class object'), end
else

    atlas_obj = load_atlas('canlab2018_2mm');

end

[r, percent_coverage] = subdivide_by_atlas(r, atlas_obj);

% attach this so we can deal with reordering of regions
for i = 1:length(r)
    r(i).custom_info2 = percent_coverage(i);
    r(i).custom_info2_descrip = 'atlas parcel coverage';
end

% Separate subregions with positive and negative values if requested
% -------------------------------------------------------------------------
if dosep
    % separate pos and neg
    [poscl, negcl] = posneg_separate(r);

    r = [poscl negcl];
    ispos = [true(1, length(poscl)) false(1, length(negcl))]; % logical for splitting combined cl later

    clear poscl negcl

    fprintf('\n%s\nPositive Effects\n', sep_str)

else

    fprintf('\n%s\nTable of all regions\n', sep_str)
end

% Volume in mm^3
% count per cubic mm - voxel count * voxel volume
get_vox_volume_in_mm = @(r) size(r.XYZ, 2) .* prod(abs(diag(r.M(1:3, 1:3))));

Volume = zeros(length(r), 1);

for i = 1:length(r)

    Volume(i, 1) = get_vox_volume_in_mm(r(i));

end

results_table = table({r.shorttitle}', 'VariableNames', {'Region'});

results_table.Volume = Volume;

results_table.XYZ = round(cat(1, r.mm_center));

results_table = [results_table get_signed_max(r, 'Z', 'maxZ')];  % use function because may be empty, handle if so

results_table.Properties.VariableNames{4} = 'maxVal';

atlas_region_coverage = cat(1, r.custom_info2);

results_table = addvars(results_table, round(atlas_region_coverage), 'NewVariableNames', 'Coverage');

% Exclude
wh_exclude = cat(1, r.numVox) < 2 | atlas_region_coverage < 25;

excluded_region_table = results_table(wh_exclude, :);

results_table(wh_exclude, :) = [];

ispos(wh_exclude) = [];
r_excluded = r(wh_exclude);

r(wh_exclude) = [];

if dosep

    results_table_pos = results_table(ispos, :);
    results_table_neg = results_table(~ispos, :);

end

% Legend info

voxvol = prod(abs(diag(r(1).M(1:3, 1:3))));

table_legend_text = {'Note: XYZ values are Montreal Neurologic Institute coordinates in mm.'};
table_legend_text{2} = sprintf('Voxel volume is %3.2fmm^3', voxvol);
table_legend_text{3} = 'maxVal is maximum positive or negatively-valued value in the .Z field. Its meaning varies across analyses. For a t-test, it usually reflects the maximum t-value.';
table_legend_text{4} = 'Coverage: Percentage of voxels in the labeled atlas parcel covered by the identified activation region.';
table_legend_text{5} = 'Regions shown are those with >1 voxel and >=25% coverage of the atlas parcel. See excluded_region_table for additional regions excluded in this way.';

% Now split into positive and neg sub-tables and display
if dosep
    % Tables for pos and neg results separately

    if any(ispos)
        disp(results_table_pos)
    else
        disp('No regions to display');
    end

    fprintf('\nNegative Effects\n')
    if any(~ispos)
        disp(results_table_neg)
    else
        disp('No regions to display');
    end

else
    % No separation

    if size(results_table, 1) > 0
        disp(results_table)
    else
        disp('No regions to display');
    end

end % dosep

% Get region list
% -------------------------------------------------------------
region_list = cell(4, 1);
for i = 1:4, region_list{i} = ''; end
region_list{1} = 'Positive effects:';
region_list{3} = 'Negative effects:';

for i = 1:size(results_table_pos, 1)
    region_list{2} = [region_list{2} sprintf('%s (%2.0f%%), ', results_table_pos.Region{i}, results_table_pos.Coverage(i))];
end

for i = 1:size(results_table_neg, 1)
    region_list{4} = [region_list{4} sprintf('%s (%2.0f%%), ', results_table_neg.Region{i}, results_table_neg.Coverage(i))];
end

if dolegend == false || isempty(table_legend_text)

    return

else
    % Print legend text

    canlab_print_legend_text(table_legend_text{:});
end

disp('')
disp('List of regions covered:')
for i = 1:4
    disp(region_list{i});
end

% clean up text for legend
% if length(table_legend_text) > 2
%     table_legend_text(2:3) = [];
% end

end % main function

function val_table = get_signed_max(cl, myfield, tablevarname)
% Returns a table with var "MaxZ" nregions x 1, or empty if cl.Z is empty

%maxZ = @(i) max(double(cl(i).Z));

smax = @(i) signedmax(cl(i).(myfield));

for i = 1:length(cl)

    if ~isempty(cl(i).(myfield))
        myZ(i, 1) = smax(i);
    else
        myZ(i, 1) = NaN;
    end

    %if isinf(smax(i)), keyboard, end

end

% Fix infinite vals - only for .Z . so this is not generalizable beyond
% this function without modifications:
maxZ = norminv(1 - 1E-12);
myZ(myZ > maxZ) = maxZ;

if all(isnan(myZ))
    val_table = [];
else
    val_table = table(myZ,  'VariableNames', {tablevarname});
end

end % function

function val = signedmax(vals)

vals = double(vals);
[maxabs, wh] = max(abs(vals));

val = sign(vals(wh)) .* maxabs;

end


function rxnFBS = diffexprs2rxnFBS(model, diff_exprs, Vref, varargin)
% Returns Forward - Backward - Unchanged (+1;0;-1) for each reaction.
% (+1)R_f    (-1)R_b     (0)unchanged
%
% USAGE:
%
%    rxnFBS = diffexprs2rxnFBS(model, diff_exprs, Vref, 'SeparateTranscript', '', 'logFC', 0, 'pval',0.05)
%
% INPUT:
%    model:             The COBRA Model structure
%    diff_exprs:        MATLAB Table including the information of the
%                       differentially expressed genes.
%                       Required columns (with theses names):
%                           - gene ( ID of gene, same as in the meabolic model)
%                           - logFC (SOURCE VS TARGET)
%                           - pval (p-value or adjusted-p-value)
%    Vref:              Reference flux of the model
%
% OPTIONAL INPUTS:
%    varargin:          `ParameterName` value pairs with the following options:
%
%                           - `SeparateTranscript`: Character used to separate different transcripts of a gene. (default: '')
%                           - `logFC`: minimum log2 (fold change) requiered (default = 0)
%                           - `pval`: maximum p-value admited (default = 0.05)
%
% OUTPUT:
%    rxnFBS:             array containting the information of altered
%                       reactions: Forward - Backward - Unchanged
%                       (+1;0;-1);
%
% .. Note:
%    It is highly recommended to use as diff_exprs the TopTable result from
%    limma in R and change names if neccesary.
%    In the tutorial there is further information to load data from GEO or
%    using R to conduct absolute and differential gene expression analysis.
%
% .. Authors:
%       - Luis V. Valcarcel, 25/06/2015, University of Navarra, CIMA & TECNUN School of Engineering.
%       - Luis V. Valcarcel, 26/10/2018, University of Navarra, CIMA & TECNUN School of Engineering.
%       - Francisco J. Planes, 26/10/2018, University of Navarra, TECNUN School of Engineering.

p = inputParser; % check input information
p.CaseSensitive = false;
addParameter(p, 'SeparateTranscript', '', @(x)ischar(x));
addParameter(p, 'logFC', 0, @(x)isnumeric(x)&&isscalar(x));
addParameter(p, 'pval', 0.05, @(x)isnumeric(x)&&isscalar(x));
parse(p, varargin{:});
SeparateTranscript = p.Results.SeparateTranscript;
logFC = p.Results.logFC;
pval = p.Results.pval;

% Traslate omics data from gene level to reaction level
if ~isempty(SeparateTranscript)
    aux_table = table(strtok(model.genes,SeparateTranscript),model.genes,'VariableNames',{'gene' 'transcript'});
    diff_exprs = innerjoin(aux_table, diff_exprs, 'Keys','gene');
	diff_exprs.gene = diff_exprs.transcript;
end

% Check that genes are in the model
assert(sum(ismember(diff_exprs.gene,model.genes))>0,...
    'Gene ID are not in the model. Revise gene ID in input table or SeparateTranscript option parameter')

% Minimun Fold Change to admit the changes
idx = abs(diff_exprs.logFC) > logFC;
diff_exprs = diff_exprs(idx,:);

% Maximum p-value to admit the changes
idx = abs(diff_exprs.pval) <= pval;
diff_exprs = diff_exprs(idx,:);

pos_up = diff_exprs.logFC > 0;     % source state bigger than target state
pos_down = diff_exprs.logFC < 0;   % source state smaller than target state

% As we cannot map the reaction to genes, we can discretize thess values as
% (+1, 0 -1), to create geneFBS
geneFBS_aux = zeros(size(diff_exprs,1),1);
geneFBS_aux(pos_up) = +1;
geneFBS_aux(pos_down) = -1;

% Generate geneFBS for all genes in the model
geneFBS = zeros(length(model.genes),1);
[~,idx] = ismember(diff_exprs.gene,model.genes);
geneFBS_aux = geneFBS_aux(idx~=0);
idx= idx(idx~=0);
geneFBS(idx) = geneFBS_aux;

% If a gene is down-regulated in the source state,the flux activity should
% be increased. Similarly, if a gene is up-regulated in the source state,
% the flux activity should be decreased.
% For this reason we change the sign of geneFBS (target vs source here).
geneFBS = -geneFBS;

% Change to Cobra format
geneFBS = struct('gene',{model.genes},'value',geneFBS);

if isempty(SeparateTranscript)
    fprintf('\tGene expression changes calculated\n');
    fprintf('\tThere are %u genes that are differentially expressed\n',sum(geneFBS.value~=0));
else
    fprintf('\tGene expression changes calculated\n');
    fprintf('\tThere are %u trainscripts that are differentially expressed\n',sum(geneFBS.value~=0));
    [~,idx] = unique(strtok(geneFBS.gene,SeparateTranscript));
    fprintf('\tThere are %u genes that are differentially expressed\n',sum(geneFBS.value(idx)~=0));
end

% Transform geneFBS into rxnFBS
% in order to produce changes, all changes must be in the same sense
minSum = false;
parsedGPR = GPRparser(model,minSum);

% Calculate changes to produce more flux
geneFBS_plus = geneFBS;
geneFBS_plus.value(geneFBS_plus.value<=0) = 0;
geneFBS_plus.value(geneFBS_plus.value>0) = +1;
[gene_id_plus, gene_expr_plus] = findUsedGenesLevels(model,geneFBS_plus);
rxnFBS_plus = selectGeneFromGPR(model, gene_id_plus, gene_expr_plus, parsedGPR, minSum);

% Calculate changes to produce less flux
geneFBS_minus = geneFBS;
geneFBS_minus.value(geneFBS_minus.value>=0) = 0;
geneFBS_minus.value(geneFBS_minus.value<0) = +1;
[gene_id_minus, gene_expr_minus] = findUsedGenesLevels(model,geneFBS_minus);
rxnFBS_minus = selectGeneFromGPR(model, gene_id_minus, gene_expr_minus, parsedGPR, minSum);

% all changes in same sense or they neglect each other
rxnFBS_plus(rxnFBS_plus<=0) = 0;
rxnFBS_minus(rxnFBS_minus<=0) = 0;
rxnFBS = rxnFBS_plus - rxnFBS_minus;
rxnFBS(strcmp(model.grRules,'')) = 0; % non-mapped reactions have no change in activity

% We have considered all reactions as Forward reactions. GeneFBS gives the
% information whatever a reaction should increase activity in absolute
% values.
% For Forward reactions, (+1) increase flux, (-1) decrease flux
% For Backward reactions, (+1) decrease flux (increase in absolute values),
% (-1) increase flux, (decrease in absolute values)
rxnFBS(Vref < 0) = - rxnFBS(Vref < 0);
fprintf('\tReaction expression changes calculated\n');
fprintf('\tThere are %u reactions that are differentially expressed\n',sum(rxnFBS~=0));

end


function region = p12_region ( )

%*****************************************************************************80
%
%% P12_REGION returns the name of the integration region for problem 12.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    18 March 2007
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, string REGION, the name of the integration region.
%
  region = 'box';

  return
end


function image = changeclass(class, varargin)
%CHANGECLASS Changes the storage class of an image.
%  I2 = CHANGECLASS(CLASS, I);
%  RGB2 = CHANGECLASS(CLASS, RGB);
%  BW2 = CHANGECLASS(CLASS, BW);
%  X2 = CHANGECLASS(CLASS, X, 'indexed');
%
%   Copyright 2002-2020 Gatesmark
%
%   This function, and other functions in the DIPUM Toolbox, are based
%   on the theoretical and practical foundations established in the
%   book Digital Image Processing Using MATLAB, 3rd ed., Gatesmark
%   Press, 2020.
%
%   Book website: http://www.imageprocessingplace.com
%   License: https://github.com/dipum/dipum-toolbox/blob/master/LICENSE.txt

%  Copyright 1993-2002 The MathWorks, Inc.  Used with permission.

switch class
case 'uint8'
   image = im2uint8(varargin{:});
case 'uint16'
   image = im2uint16(varargin{:});
case 'double'
   image = im2double(varargin{:});
otherwise
   error('Unsupported IPT data class.');
end


% std_topomovie - make movie in the frequency domain
%
% Usage:
%  >> [STUDY] = std_movie(STUDY, ALLEEG, key1, val1, key2, val2, ...);
%
% Inputs:
%   STUDY      - STUDY structure comprising some or all of the EEG datasets in ALLEEG.
%   ALLEEG     - vector of EEG dataset structures for the dataset(s) in the STUDY,
%                typically created using LOAD_ALLEEG.
%   'channels' - [numeric vector]  specific channel group to plot. By
%                default, the grand mean channel spectrum is plotted (using the
%                same format as for the cluster component means described above)
%   'moviemode' - ['erp'|'spec'|'ersptime'] movie mode. Currently only
%                 'spec' is implemented.
%   'erspfreq'  - [min max] frequency range when making movie of ERSP. The
%                 ERSP values are averaged over the selected frequency
%                 range. Not implemented
%   'limitbeg'  - [min max] limits at the beginning of the movie
%   'limitend'  - [min max] limits at the end of the movie
%   'freqslim'  - [freqs] array of landmark frequencies to set color
%                 limits.
%   'movieparams' - [low inc high] lower limit, higher limit and increment. If
%                increment is omitted, movie is generate at every possible
%                increment (max freq resolution or max time resolution)
%
% Authors: Arnaud Delorme, CERCO, August, 2006
%
% See also: STD_SPECPLOT, STD_ERPPPLOT, STD_ERSPPLOT

% Copyright (C) Arnaud Delorme, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [STUDY, M] = std_movie(STUDY, ALLEEG, varargin);

if nargin < 2
    help std_specplot;
    return;
end

[opt addparams ] = finputcheck( varargin, ...
                             { 'erspfreq'    'real'    [] [];
                               'movieparams' 'real'    [] [];
                               'channels'    'cell'    [] {};
                               'freqslim'    'real'    [] [];
                               'limitbeg'    'real'    [] [];
                               'limitend'    'real'    [] [];
                               'moviemode'   'string'  { 'ersptime','erp','spec' } 'spec' }, 'std_movie', 'ignore');

if ischar(opt), error(opt); end
tmpchanlocs =  ALLEEG(1).chanlocs;
if isempty(opt.channels), opt.channels = { tmpchanlocs.labels }; end
if ~strcmpi(opt.moviemode, 'spec'), error('Only spec has been implemented so far'); end

% read data once
% --------------
STUDY = std_specplot(STUDY, ALLEEG, 'channels', opt.channels, 'topofreq', [10 11]); close;

% find first data channel with info
% ---------------------------------
for cind = 1:length(STUDY.changrp)
    if ~isempty(STUDY.changrp(cind).specdata), break; end
end

% generate movie
% --------------
if isempty(opt.movieparams),
    opt.movieparams(1) = STUDY.changrp(cind).specfreqs(1);
    opt.movieparams(2) = STUDY.changrp(cind).specfreqs(end);
end
if length(opt.movieparams) == 2
    opt.movieparams(3) = opt.movieparams(2);
    opt.movieparams(2) = STUDY.changrp(cind).specfreqs(2)-STUDY.changrp(cind).specfreqs(1);
end
if length(opt.movieparams) == 3
    opt.movieparams = [opt.movieparams(1):opt.movieparams(2):opt.movieparams(3)];
end

% find limits
% -----------
if isempty(opt.limitbeg)
    [STUDY specdata] = std_specplot(STUDY, ALLEEG, 'channels', opt.channels, 'topofreq', opt.movieparams(1)); close;
    opt.limitbeg = [ min(specdata{1}) max(specdata{1}) ];
    [STUDY specdata] = std_specplot(STUDY, ALLEEG, 'channels', opt.channels, 'topofreq', opt.movieparams(end)); close;
    opt.limitend = [ min(specdata{1}) max(specdata{1}) ];
end
lowlims  = linspace(opt.limitbeg(1), opt.limitend(1), length(opt.movieparams));
highlims = linspace(opt.limitbeg(2), opt.limitend(2), length(opt.movieparams));

% limits at specific frequencies
% ------------------------------
if ~isempty(opt.freqslim)
    if opt.freqslim(1)   ~= opt.movieparams(1)  , opt.freqslim = [ opt.movieparams(1) opt.freqslim ]; end
    if opt.freqslim(end) ~= opt.movieparams(end), opt.freqslim = [ opt.freqslim opt.movieparams(end) ]; end

    for ind = 1:length(opt.freqslim)
        [tmp indf(ind)] = min(abs(opt.freqslim(ind) - opt.movieparams));
        [STUDY specdata] = std_specplot(STUDY, ALLEEG, 'channels', opt.channels, 'topofreq', opt.movieparams(indf(ind))); close;
        minimum(ind) = min(specdata{1});
        maximum(ind) = max(specdata{1});
    end
    indf(1)  = 0;
    lowlims  = [ ];
    highlims = [ ];
    for ind = 2:length(opt.freqslim)
        lowlims  = [lowlims linspace(minimum(ind-1), minimum(ind), indf(ind)-indf(ind-1)) ];
        highlims = [highlims linspace(maximum(ind-1), maximum(ind), indf(ind)-indf(ind-1)) ];
    end
end

% make movie
% ----------
for ind = 1:length(opt.movieparams)
    STUDY = std_specplot(STUDY, ALLEEG, 'channels', opt.channels, 'topofreq', opt.movieparams(ind), 'caxis', [lowlims(ind) highlims(ind)]);
    pos = get(gcf, 'position');
    set(gcf, 'position', [pos(1) pos(2) pos(3)*2 pos(4)*2]);
    M(ind) = getframe(gcf);
    close;
end
figure; axis off; movie(M);