function y = logical(x)
% Allows char input
if ischar(x)
    x = double(x);
end
y = builtin('logical', x);
end


classdef TestDrawMarkerAruco
    %TestDrawMarkerAruco

    methods (Static)
        function test_1
            img = cv.drawMarkerAruco('6x6_50', 0, 60);
            validateattributes(img, {'uint8'}, {'size',[60 60]});
        end

        function test_2
            img = cv.drawMarkerAruco('6x6_50', 0, 60, 'BorderBits',1);
            validateattributes(img, {'uint8'}, {'size',[60 60]});
        end

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

end


function varargout = displayBVPinfo(handles, mode, varargin)
%DISPLAYBVPINFO   Show information on the CHEBGUI figure when solving BVPs.
%
% Calling sequence:
%   VARARGOUT = DISPLAYBVPINFO(HANDLES, MODE, VARARGIN)
% where
%   VARARGOUT when MODE = 'INIT':
%       VARARGOUT{1}:   Dummy output, required for consistency with the
%                       chebop/displayInfoInit method.
%       VARARGOUT{2}:   A tic/toc timer.
%   VARARGOUT when MODE = 'ITER':
%       VARARGOUT{1}:   A tic/toc timer.
%       VARARGOUT{2}:   Boolean variable, equal to 1 if the user pressed the
%                       'Stop' button on the GUI.
%   HANDLES:            The MATLAB handle to the CHEBGUI figure.
%   VARARGIN:           Useful input arguments for showing information, further
%                       described in 'help chebop/displayInfo'.
%
% See also: chebop/displayInfo

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

% Go into different modes, depending on where in the Newton iteration we are.
switch mode
    case 'exactInitial'
        displayBVPinfoExactInitial(handles, varargin{:});
    case 'init'
        [displayFig, displayTimer] = displayBVPinfoInit(handles, varargin{:});
        varargout{1} = displayFig;
        varargout{2} = displayTimer;
    case 'iter'
        [varargout{1}, varargout{2}] = displayBVPinfoIter(handles, varargin{:});
    case 'final'
        displayBVPInfoFinal(handles, varargin{:});
    case 'linear'
        displayBVPinfoLinear(handles, varargin{:});
end

end

function displayBVPinfoExactInitial(handles, pref)
%DISPLAYINFOEXACTINITIAL    Called if we pass CHEBOP/SOLVEBVP an initial guess
%                           that solves the BVP.

% Show that we got passed an initial guess that solves the BVP:
str = {'Initial guess appears to be a solution of the BVP.';
    'Returning initial guess as the solution.'};

% Update the information on the GUI:
set(handles.iter_list, 'String',  str);
set(handles.iter_list, 'Value', 1);

end

function [displayFig, displayTimer] = displayBVPinfoInit(handles, u, pref)
%DISPLAYBVPINFOINIT   Show information at the start of Newton iteration
%
% See also: chebop/displayInfoInit

% Update the iteration information header on the GUI
initString = [' Iter.       || du ||        Contraction      stepsize     ',...
    '   len(du)          len(u)'];
set(handles.iter_text, 'String', initString);

% Clear the update plot
axes(handles.fig_norm)
plot(0, 0)
xlim(handles.xLim)
cla

% Switch focus to the fig_sol plot on the GUI
axes(handles.fig_sol)

% Plot initial guess
plot(chebfun(u), '.-', 'linewidth', 2)
set(handles.panel_figSol, 'title', 'Initial guess of solution')

% Remove title from bottom plot panel
set(handles.panel_figNorm, 'title', 'Current correction step')

% Update the fontsize of plots
set(handles.fig_sol, 'fontsize', handles.fontsizePanels);
set(handles.fig_norm, 'fontsize', handles.fontsizePanels);

% Do different things for the axes depending on if the solution is real.
if ( isreal(chebfun(u)) )
    xlim(handles.xLim)
else
    axis equal
end

drawnow

% This only needs to be a dummy output, since the HANDLES variable contains
% pointers to the plots we want to draw on:
displayFig = 42;

% Start a timer, used to control pausing between plotting:
displayTimer = tic;

end

function [displayTimer, stopReq] = displayBVPinfoIter(handles, u, delta, ...
    iterNo, normDelta, cFactor, lenDelta, lambda, lenu, displayFig, ...
    displayTimer, pref) %#ok<INUSD>
%DISPLAYBVPINFOITER   Show information and plot during Newton iteration.
%
% See also: chebop/displayInfoIter

% Create a string for displaying information about the iteration.
if ( lambda == 1 )
    iterString = sprintf(' %2.2d %10.2e %10.2e %9.4f %7i %9i ', ...
        iterNo, normDelta, cFactor, lambda, lenDelta, lenu);
else
    iterString = sprintf(' %2.2d %10.2e %10.2e %10.2e %6i %9i ', ...
        iterNo, normDelta, cFactor, lambda, lenDelta, lenu);
end

% Update the iteration information on the GUI.
currString = get(handles.iter_list, 'String');
set(handles.iter_list, 'String', [currString ; iterString]);
set(handles.iter_list, 'Value', iterNo);

% Switch focus to the fig_sol plot on the GUI.
axes(handles.fig_sol)

% Plot current iterate
plot(chebfun(u), '.-', 'linewidth', 2)
set(handles.panel_figSol, 'title', 'Current solution')

% Do different things for the axes depending on if the solution is real.
if ( isreal(chebfun(u)) )
    xlim(handles.xLim)
else
    axis equal
end

% Now plot the Newton updates.

% Switch focus to the fig_norm plot on the GUI.
axes(handles.fig_norm)

% Plot Newton update
plot(chebfun(delta), '.-',  'linewidth', 2)
set(handles.panel_figNorm, 'title', 'Current correction step')

% Update the fontsize of plots
set(handles.fig_sol, 'fontsize', handles.fontsizePanels);
set(handles.fig_norm, 'fontsize', handles.fontsizePanels);

% Do different things for the axes depending on if the solution is real.
if ( isreal(chebfun(u)) )
    xlim(handles.xLim)
else
    axis equal
end

drawnow

% If the user has pressed the pause button on the GUI, we pause.
if ( ~isempty(handles) ...
            && strcmpi(get(handles.button_clear, 'String'), 'Continue') )
    waitfor(handles.button_clear, 'String')
end

% If the user has pressed the stop button on the GUI, we stop the Newton
% iteration.
if ( ~isempty(handles) ...
            && strcmpi(get(handles.button_solve, 'String'), 'Solve') )
    stopReq = true;
else
    stopReq = false;
end

% Restart the timer:
displayTimer = tic;

end

function displayBVPInfoFinal(handles, u, delta, iterNo, errEstDE, errEstBC, ...
	displayFig, displayTimer, pref) %#ok<INUSL>
%DISPLAYBVPINFOFINAL   Utility routine for displaying nonlinear solve progress.
%
%  This method prints out information after Newton iteration finishes when
%  problems are solved using CHEBGUI.
%
% See also: displayBVPInfo, chebop/displayInfoFinal

% How many steps did we need
if ( iterNo == 1 )
    finalStr = {'Newton''s method converged in 1 iteration\n'};
else
    finalStr = {sprintf('Newton''s method converged in %i iterations.',....
        iterNo)};
end

% Show what discretization was used
if ( strcmpi(func2str(pref.discretization), 'coeffs') || ...
        isequal(pref.discretization, @ultraS) || ...
        isequal(pref.discretization, @trigspec))
    discString = 'Coefficients';
else
    discString = 'Values';
end
finalStr = [finalStr; sprintf('Discretization basis used: %s.', ...
    discString)];

% Print info about the final error estimates...
finalStr = [finalStr; ...
    sprintf('Final error estimate: %.2e (differential equation) ', errEstDE)];
% ...and the error in the boundary conditions.
finalStr = [finalStr; ...
    sprintf('%30.2e (boundary conditions).', errEstBC)];

% Update the iteration information on the GUI
currString = get(handles.iter_list, 'String');
set(handles.iter_list,'String', [currString ; finalStr]);

% Set focus to bottom of printed list
set(handles.iter_list, 'Value', iterNo + 4);

end

function displayBVPinfoLinear(handles, u, nrmRes, pref)
%DISPLAYBVPINFOLINEAR   Display methods tailored to linear BVPs.

% Show that we detetected a linear equation:
str = {'Linear equation detected. Converged in one step.'};

% Show what discretization was used:
if ( strcmpi(func2str(pref.discretization), 'coeffs') || ...
        isequal(pref.discretization, @ultraS) || ...
        isequal(pref.discretization, @trigspec))
    discString = 'Coefficients';
else
    discString = 'Values';
end

% Concatenate strings:
str = [str ; sprintf('Discretization basis used: %s.',  discString)];
str = [str ; sprintf('Length of solution: %i.', length(chebfun(u)))];
str = [str ; sprintf('Norm of residual: %.2e.', nrmRes)];

% Update the information on the GUI:
set(handles.iter_list, 'String',  str);
set(handles.iter_list, 'Value', 1);

% Plot
axes(handles.fig_sol)
plot(u, 'linewidth', 2)
% Do different things depending on whether the solution is real or not
if ( isreal(u{1}) )
    axis tight
else
    axis equal
end

set(handles.panel_figSol, 'title', 'Solution')

end


function [m] = m2m(m)
% Convert length from British metres to American meters.
m = m;


function radiomicsParamS = getRadiomicsParamTemplate(paramFilename,dictS)
% radiomicsParamS = getRadiomicsParamTemplate(paramFilename);
%
% Template parameters for radiomics feature extraction
%
% --------------------------------------------------------------------------------------
% INPUT:
% paramFileName : Path to JSON file for radiomics feature extraction.
%                 Sample JSON file: CERR_core/PlanMetrics/heterogenity_metrics/sample_radiomics_extraction_settings.json
% -------- Optional --------
% dictS       : Alternatively, pass dictionary userInS
% --------------------------------------------------------------------------------------
%
% APA, 2/27/2019
% AI, 3/22/19     Modified for compatibility with JSON input

feature accel off

%% Read JSON file
if ~isempty(paramFilename)
    userInS = jsondecode(fileread(paramFilename));
else
    userInS = dictS;
end

%% Get image type
filterTypeC = fieldnames(userInS.imageType);
radiomicsParamS.imageType = struct();
for m = 1:length(filterTypeC)
    %paramListC = fieldnames(userInS.imageType.(filterTypeC{m}));
    radiomicsParamS.imageType.(filterTypeC{m}) = struct();
    for iFilt = 1:length(userInS.imageType.(filterTypeC{m}))
        if ~(isstruct(userInS.imageType.(filterTypeC{m})) && ...
                isempty(fieldnames(userInS.imageType.(filterTypeC{m}))))
            if isstruct(userInS.imageType.(filterTypeC{m}))
                paramListC = fieldnames(userInS.imageType.(filterTypeC{m}));
            else
                paramListC = fieldnames(userInS.imageType.(filterTypeC{m}){iFilt});
            end
            for n = 1:length(paramListC)
                if isstruct(userInS.imageType.(filterTypeC{m}))
                    radiomicsParamS.imageType.(filterTypeC{m})(iFilt).(paramListC{n}).val = ...
                        userInS.imageType.(filterTypeC{m})(iFilt).(paramListC{n});
                else
                    radiomicsParamS.imageType.(filterTypeC{m})(iFilt).(paramListC{n}).val = ...
                        userInS.imageType.(filterTypeC{m}){iFilt}.(paramListC{n});
                end
            end
        end
    end
end

%% Calculation Parameters
whichFeatS = struct('resample',struct('flag',0), 'padding',struct('flag',0),...
        'perturbation',struct('flag',0),'firstOrder',struct('flag',0),...
        'shape',struct('flag',0),'texture',struct('flag',0),...
        'peakValley',struct('flag',0),'ivh',struct('flag',0),'glcm',struct('flag',0),...
        'glrlm',struct('flag',0),'gtdm',struct('flag',0),'gldm',struct('flag',0),...
        'glszm',struct('flag',0));
if isfield(userInS,'settings')
    settingsC = fieldnames(userInS.settings);
    firstOrderParamS = struct;
    textureParamS = struct;
    shapeParamS = struct;
    peakValleyParamS = struct;
    ivhParamS = struct;

    % Structure names
    if isfield(userInS,'structures')
        radiomicsParamS.structuresC = userInS.structures;
    end
    %Otherwise, use entire scan

    % ---1. First-order features ---
    idx = strcmpi(settingsC,'firstOrder');
    if any(idx)
        paramC = fieldnames(userInS.settings.(settingsC{idx}));
        for k = 1: length(paramC)
            firstOrderParamS.(paramC{k}) = userInS.settings.(settingsC{idx}).(paramC{k});
        end
        radiomicsParamS.firstOrderParamS = firstOrderParamS;
    end

    %---2. Shape features ----
    idx = strcmpi(settingsC,'shape');
    if any(idx)
        paramC = fieldnames(userInS.settings.(settingsC{idx}));
        for k = 1: length(paramC)
            shapeParamS.(paramC{k}) = userInS.settings.(settingsC{idx}).(paramC{k});
        end
        radiomicsParamS.shapeParamS = shapeParamS;
    end

    %---3. Higher-order (texture) features ----
    idx = strcmpi(settingsC,'texture');
    if any(idx)
        paramC = fieldnames(userInS.settings.(settingsC{idx}));
        for k = 1: length(paramC)
            textureParamS.(paramC{k}) = userInS.settings.(settingsC{idx}).(paramC{k});
        end
        radiomicsParamS.textureParamS = textureParamS;
    end

    %---4. Peak-valley features ----
    idx = strcmpi(settingsC,'peakvalley');
    if any(idx)
        paramC = fieldnames(userInS.settings.(settingsC{idx}));
        for k = 1: length(paramC)
            peakValleyParamS.(paramC{k}) = userInS.settings.(settingsC{idx}).(paramC{k});
        end
        radiomicsParamS.peakValleyParamS = peakValleyParamS;
    end

    %---5. IVH features ----
    idx = strcmpi(settingsC,'ivh');
    if any(idx)
        paramC = fieldnames(userInS.settings.(settingsC{idx}));
        for k = 1: length(paramC)
            ivhParamS.(paramC{k}) = userInS.settings.(settingsC{idx}).(paramC{k});
        end
        radiomicsParamS.ivhParamS = ivhParamS;
    end

    %% Set flags for sub-classes of features to be extracted
    for k = 1:length(settingsC)
        fieldNamC = fieldnames(userInS.settings.(settingsC{k}));
        if ~isempty(fieldNamC)
            whichFeatS.(settingsC{k}).flag = 1;
            for iField = 1:length(fieldNamC)
                whichFeatS.(settingsC{k}).(fieldNamC{iField}) = userInS.settings...
                    .(settingsC{k}).(fieldNamC{iField});
            end
        end
    end
end

if isfield(userInS,'featureClass')
    inputClassesC = fieldnames(userInS.featureClass);
    for k =1:length(inputClassesC)
        whichFeatS.(inputClassesC{k}).flag = 1;
        if isfield(userInS.featureClass.(inputClassesC{k}),'featureList')
            whichFeatS.(inputClassesC{k}).featureList = ...
                userInS.featureClass.(inputClassesC{k}).featureList;
        else
            whichFeatS.(inputClassesC{k}).featureList = {'all'};
        end
    end
    radiomicsParamS.whichFeatS = whichFeatS;

    if isfield(userInS,'toQuantizeFlag')
        %% Flag to quantize input data
        radiomicsParamS.toQuantizeFlag = userInS.toQuantizeFlag;
    else
        radiomicsParamS.toQuantizeFlag = 1;
    end
else
    radiomicsParamS.whichFeatS = whichFeatS;
end

feature accel on


function [spike] = ft_datatype_spike(spike, varargin)

% FT_DATATYPE_SPIKE describes the FieldTrip MATLAB structure for spike data
%
% Spike data is obtained using FT_READ_SPIKE to read files from a Plexon,
% Neuralynx or other animal electrophysiology data acquisition system. It
% is characterised as a sparse point-process, i.e. each neuronal firing is
% only represented as the time at which the firing happened. Optionally,
% the spike waveform can also be represented. Using this waveform, the
% neuronal firing events can be sorted into their single units.
%
% A required characteristic of the SPIKE structure is a cell-array with the
% label of the (single or multi) units.
%
%         label: {'unit1'  'unit2'  'unit3'}
%
% The fields of the SPIKE structure that contain the specific information
% per spike depends on the available information. A relevant distinction
% can be made between the representation of raw spikes that are not related
% to the temporal structure of the experimental design (i.e trials), and
% the data representation in which the spikes are related to the trial.
%
% For a continuous recording the SPIKE structure must contain a cell-array
% with the raw timestamps as recorded by the hardware system. As example,
% the original content of the .timestamp field can be
%
%         timestamp:  {[1x504 uint64]  [1x50 uint64]  [1x101 uint64]}
%
% An optional field that is typically obtained from the raw recording
% contains the waveforms for every unit and label as a cell-array. For
% example, the content of this field may be
%
%         waveform:   {[1x32x504 double] [1x32x50 double] [1x32x101 double]}
%
% If the data has been organised to reflect the temporal structure of the
% experiment (i.e. the trials), the SPIKE structure should contain a
% cell-array with the spike times relative to an experimental trigger. The
% FT_SPIKE_MAKETRIALS function can be used to reorganise the SPIKE
% structure such that the spike times are expressed relative to a trigger
% instead of relative to the acquisition devices internal timestamp clock.
% The time field then contains only those spikes that ocurred within one of
% the trials . The spike times are now expressed on seconds relative to the
% trigger.
%
%         time:       {[1x504 double] [1x50 double] [1x101 double]}
%
% In addition, for every spike we register in which trial the spike was
% recorded:
%
%         trial:      {[1x504 double] [1x50 double] [1x101 double]}
%
% To fully reconstruct the structure of the spike-train, it is required
% that the exact start- and end-point of the trial (in seconds) is
% represented. This is specified in a nTrials x 2 matrix.
%
%         trialtime:  [100x2 double]
%
% As an example, FT_SPIKE_MAKETRIALS could result in the following
% SPIKE structure that represents the spikes of three units that were
% observed in 100 trials:
%
%         label:           {'unit1'  'unit2'  'unit3'}
%         timestamp:       {[1x504 double] [1x50 double] [1x101 double]}
%         timestampdimord: '{chan}_spike'
%         time:            {[1x504 double] [1x50 double] [1x101 double]}
%         trial:           {[1x504 double] [1x50 double] [1x101 double]}
%         trialtime:       [100x2 double]
%         sampleinfo:      [100x2 double]
%         waveform:        {[1x32x504 double] [1x32x50 double] [1x32x101 double]}
%         waveformdimord: '{chan}_lead_time_spike'
%
% For analysing the relation between the spikes and the local field
% potential (e.g. phase-locking), the SPIKE structure can have additional
% fields such as fourierspctrm, lfplabel, freq and fourierspctrmdimord.
%
% For example, from the structure above we may obtain
%
%         label:               {'unit1'  'unit2'  'unit3'}
%         time:                {[1x504 double] [1x50 double] [1x101 double]}
%         trial:               {[1x504 double] [1x50 double] [1x101 double]}
%         trialtime:           [100x2 double]
%         timestamp:           {[1x504 double] [1x50 double] [1x101 double]}
%         timestampdimord:     '{chan}_spike'
%         waveform:            {[1x32x504 double] [1x32x50 double] [1x32x101 double]}
%         waveformdimord:      '{chan}_lead_time_spike'
%         fourierspctrm:       {504x2x20, 50x2x20, 101x2x20}
%         fourierspctrmdimord: '{chan}_spike_lfplabel_freq'
%         lfplabel:            {'lfpchan1', 'lfpchan2'}
%         freq:                [1x20 double]
%
% Required fields:
%   - label
%   - timestamp
%
% Optional fields:
%   - time, trial, trialtime
%   - timestampdimord
%   - unit, unitdimord
%   - waveform, waveformdimord
%   - fourierspctrm, fourierspctrmdimord, freq, lfplabel (these are extra outputs from FT_SPIKETRIGGEREDSPECTRUM and FT_SPIKE_TRIGGEREDSPECTRUM)
%   - hdr
%   - cfg
%
% Deprecated fields:
%   - origtime, origtrial
%
% Obsoleted fields:
%   - <unknown>
%
% Revision history:
%
% (2020/latest) Add an explicit xxxdimord for each of the known fields.
%
% (2012) Changed the dimensionality of the waveform to allow both
% stereotrode and tetrode data to be represented.
%
% (2011) Defined a consistent spike data representation that can
% also contain the Fourier spectrum and other fields. Use the xxxdimord
% to indicate the dimensions of the field.
%
% (2010) Introduced the time and the trialtime fields.
%
% (2007) Introduced the spike data representation.
%
% See also FT_DATATYPE, FT_DATATYPE_RAW, FT_DATATYPE_FREQ, FT_DATATYPE_TIMELOCK

% Copyright (C) 2011-2020, Robert Oostenveld & Martin Vinck
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% get the optional input arguments, which should be specified as key-value pairs
version = ft_getopt(varargin, 'version', 'latest');

if strcmp(version, 'latest')
  version = '2020';
end

if isempty(spike)
  return;
end

switch version
  case '2020'
    % ensure it is up to date with the previous version, which incoreporates changes from 2011 and 2012
    spike = ft_datatype_spike(spike, 'version', '2012');

    % remove the general dimord
    if isfield(spike, 'dimord')
      spike = rmfield(spike, 'dimord');
    end

    % add explicit dimords for the known fields
    if isfield(spike, 'timestamp') && ~isfield(spike, 'timestampdimord')
      spike.timestampdimord = '{chan}_spike';
    end
    if isfield(spike, 'unit') && ~isfield(spike, 'unitdimord')
      spike.unitdimord = '{chan}_spike';
    end
    if isfield(spike, 'waveform') && ~isfield(spike, 'waveformdimord')
      spike.waveformdimord = '{chan}_lead_time_spike';
    end
    if isfield(spike, 'fourierspctrm') && ~isfield(spike, 'fourierspctrmdimord')
      spike.fourierspctrmdimord = '{chan}_spike_lfplabel_freq';
    end

  case '2012'
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    if isfield(spike,'origtrial') && isfield(spike,'origtime')
      % this was the old spiketriggered spectrum output
      ft_warning('The spike datatype format you are using is depreciated. Converting to newer spike format');
      spike.trial = {spike.origtrial};
      spike       = rmfield(spike,'origtrial');
      spike.time  = {spike.origtime};
      spike       = rmfield(spike,'origtime');
      if ~isa(spike.fourierspctrm, 'cell')
        spike.fourierspctrm = {spike.fourierspctrm};
      end
      if ~isfield(spike, 'trialtime')
        % determine from the data itself
        ft_warning('Reconstructing the field trialtime from spike.origtime and spike.origtrial. This is not the original representation');
        tmax  = nanmax(spike.trial{1});
        tsmin = nanmin(spike.time{1});
        tsmax = nanmax(spike.time{1});
        spike.trialtime = [tsmin*ones(tmax,1) tsmax*ones(tmax,1)];
      end
      spike.lfplabel = spike.label; % in the old format, these were the lfp channels
      try
        spike.label    = spike.cfg.spikechannel;
      catch
        try
          spike.label = spike.spikechannel;
        catch
          spike.label = {'unit1'}; %default
        end
      end
      spike.dimord = '{chan}_spike_lfpchan_freq';
    end

    % fix the waveform dimensions
    if isfield(spike,'waveform')
      nUnits = length(spike.waveform);
      hasdat = false(1,nUnits);
      for iUnit = 1:nUnits
        hasdat(iUnit) = ~isempty(spike.waveform{iUnit});
      end

      if any(hasdat) %otherwise, ignore
        if ~isfield(spike, 'dimord')
          spike.dimord = '{chan}_lead_time_spike';
        end
        % fix the dimensions of the waveform dimord.
        for iUnit = 1:nUnits
          dim = size(spike.waveform{iUnit});
          if length(dim)==2 && ~isempty(spike.waveform{iUnit})
            nSpikes = length(spike.timestamp{iUnit}); % check what's the spike dimension from the timestamps
            spikedim = dim==nSpikes;
            if isempty(spikedim)
              ft_error('waveforms contains data but number of waveforms does not match number of spikes');
            end
            if spikedim==1
              spike.waveform{iUnit} = permute(spike.waveform{iUnit},[3 2 1]);
            else
              spike.waveform{iUnit} = permute(spike.waveform{iUnit},[3 1 2]);
            end

          elseif length(dim)==3 && ~isempty(spike.waveform{iUnit})
            nSpikes = length(spike.timestamp{iUnit}); % check what's the spike dimension from the timestamps
            spikedim = dim==nSpikes;
            % determine from the remaining dimensions which is the lead
            leaddim  = dim<6 & dim~=nSpikes;
            sampdim  = dim>=6 & dim~=nSpikes;
            if isempty(spikedim)
              ft_error('waveforms contains data but number of waveforms does not match number of spikes');
            end
            if sum(leaddim)~=1 || sum(sampdim)~=1, continue,end % in this case we do not know what to do
            if find(spikedim)~=3 && find(leaddim)~=1 && find(sampdim)~=2
              spike.waveform{iUnit} = permute(spike.waveform{iUnit}, [find(leaddim) find(sampdim) find(spikedim)]);
            end
          end
        end

      end

    end

    % ensure that we always deal with row vectors: for consistency of
    % representation
    if isfield(spike,'time')
      for iUnit = 1:length(spike.time)
        if size(spike.time{iUnit},2)==1
          spike.time{iUnit} = spike.time{iUnit}(:)';
        end
      end
    end

    if isfield(spike,'time')
      for iUnit = 1:length(spike.trial)
        if size(spike.trial{iUnit},2)==1
          spike.trial{iUnit} = spike.trial{iUnit}(:)';
        end
      end
    end

    if isfield(spike,'timestamp')
      for iUnit = 1:length(spike.timestamp)
        if size(spike.timestamp{iUnit},2)==1
          spike.timestamp{iUnit} = spike.timestamp{iUnit}(:)';
        end
      end
    end

    if isfield(spike,'unit')
      for iUnit = 1:length(spike.unit)
        if size(spike.unit{iUnit},2)==1
          spike.unit{iUnit} = spike.unit{iUnit}(:)';
        end
      end
    end

  otherwise
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    ft_error('unsupported version "%s" for spike datatype', version);
end

spike = sortfields(spike);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function s2 = sortfields(s1)
s2 = struct();
fn = sort(fieldnames(s1));
for i=1:numel(fn)
  s2.(fn{i}) = s1.(fn{i});
end


function DPMpcStandAlongJingOneBeam3(leak, spectrum_File, planC_File, nhist, OutputError, whichBeam, PBMaxWidth, gradsense, scatterThreshold, batch)
% written by KZ, JC
% Calculate doseV dose3D directly from DPM, without compressing it.
% Use generateDPMdose.m instead of DPMInfluenceJing.m
% Calculate IM struct, call DPM, get
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

% Usage: IIMCalc = calculateBeamIM(0.018, 'DPM_10beams_planC', 1, 1, 5)
%   leak = 0.018
%   spectrum_File = file name of photon spectrum. eg. photon6MV.spectrum
%   planC_File = file name contained planC, eg. 'DPM_10beams_planC'
%   indexBeam = Beam Index: 1, 2, ...
%   imin = Beamlet index
%   imax = Beamlet index

%   eval(['load Beam',num2str(indexBeam),'_w']);
%   where, Beam1_w.mat (Beam2_w.mat) need to be in the current directory. It's the weight of
%   the beamlets for each beam.

% JC Feb 27 06
% Call in DPMInfluence.m; use sum(10*clock) as the random seeds input to DPM.

% JC. Aug 10, 2005, Need to make planC read from the disk, since in the
% stand-alone mode, no matlab run is expected.

% open planC_File
% In matlab release 14, "eval" can be compiled.
Error = []; %Initialize Error to NULL.
load(planC_File);
%eval(['load ',planC_File]);
% This planC_File should contains planC and stateS
%leak = 0.018; %leakage in per *100

if ischar(leak)
    leak = str2num(leak)
end

if ischar(nhist)
    nhist = str2num(nhist)
end

if ischar(OutputError)
    OutputError = str2num(OutputError)
end

if ischar(whichBeam)
    whichBeam = str2num(whichBeam)
end

if ischar(PBMaxWidth)
    PBMaxWidth = str2num(PBMaxWidth)
end

if ischar(gradsense)
    gradsense = str2num(gradsense)
end

if ischar(scatterThreshold)
    scatterThreshold = str2num(scatterThreshold)
end

if ischar(batch)
    batch = str2num(batch)
end

currentDir = cd;

%for indexBeam = 1 : planC{7}.FractionGroupSequence.Item_1.NumberOfBeams
for indexBeam = whichBeam
    bf = planC{7}.FractionGroupSequence.Item_1.ReferencedBeamSequence.(['Item_' num2str(indexBeam)]);
    %if (bf.BeamDose ~= 0 & indexBeam ~= 2)
    if (bf.BeamDose ~= 0)
        bs = planC{7}.BeamSequence.(['Item_' num2str(indexBeam)]);

        LS = getDICOMLeafPositions(bs)

        [inflMap, xV, yV, colDividerXCoord, rowDividerYCoord, rowLeafPositions] = getLSInfluenceMapFactor(LS,leak,bs.BeamNumber);

        gA = bs.ControlPointSequence.Item_1.GantryAngle;
        iC = bs.ControlPointSequence.Item_1.IsocenterPosition;
        IMBase.beams(1).gantryAngle = gA;

        if ~isfield(planC{7}.PatientSetupSequence,(['Item_' num2str(indexBeam)]))
            position = {planC{7}.PatientSetupSequence.(['Item_' num2str(1)]).PatientPosition};
        else
            position = {planC{7}.PatientSetupSequence.(['Item_' num2str(indexBeam)]).PatientPosition};
        end

        if strcmpi(position, 'HFP')
            IMBase.beams(1).isocenter.x = iC(1)/10;
            IMBase.beams(1).isocenter.y = iC(2)/10;
            IMBase.beams(1).isocenter.z = -iC(3)/10;
        else
            IMBase.beams(1).isocenter.x = iC(1)/10;
            IMBase.beams(1).isocenter.y = -iC(2)/10;
            IMBase.beams(1).isocenter.z = -iC(3)/10;
        end

        IMBase.beams(1).isodistance = bs.SourceAxisDistance/10;

        IMBase.beams(1).xRel = IMBase.beams(1).isodistance * sindeg(IMBase.beams(1).gantryAngle);

        IMBase.beams(1).yRel = IMBase.beams(1).isodistance * cosdeg(IMBase.beams(1).gantryAngle);

        IMBase.beams(1).beamEnergy = bs.ControlPointSequence.Item_1.NominalBeamEnergy;

        %[PBX] = getPBXCoorFromFluence(inflMap, rowLeafPositions, 2, 50, colDividerXCoord, rowDividerYCoord, 10);
        [PBX] = getPBXCoorFromFluence(inflMap, rowLeafPositions, 2, PBMaxWidth, colDividerXCoord, rowDividerYCoord, gradsense);

        [xPosV, yPosV, beamlet_delta_x, beamlet_delta_y, w_field] = getPBVectors(PBX,rowLeafPositions,colDividerXCoord,rowDividerYCoord,inflMap);

%        %Visualization
%                 figure;hAxis1 = axes;imagesc([xV(1)+.05 xV(end)-.05], [yV(1)+.05, yV(end)-.05], inflMap);
%                 set(gcf, 'renderer', 'zbuffer')
%                 figure;hAxis2 = axes;hold on;
%                 set(gcf, 'renderer', 'zbuffer')
%                 xL = get(hAxis1, 'xlim');
%                 yL = get(hAxis1, 'ylim');
%                 set(hAxis2, 'xlim', xL);
%                 set(hAxis2, 'ylim', yL);
%                 axis(hAxis2, 'manual');
%             %     w_colors = floor((w_field ./ max(w_field))*255)+1;
%                 set(gcf, 'doublebuffer', 'on');
%                 for i=1:length(xPosV)
%                     patch([xPosV(i) - beamlet_delta_x(i)/2 xPosV(i) - beamlet_delta_x(i)/2 xPosV(i) + beamlet_delta_x(i)/2 xPosV(i) + beamlet_delta_x(i)/2 xPosV(i) - beamlet_delta_x(i)/2], [yPosV(i) - beamlet_delta_y(i)/2 yPosV(i) + beamlet_delta_y(i)/2 yPosV(i) + beamlet_delta_y(i)/2 yPosV(i) - beamlet_delta_y(i)/2 yPosV(i) - beamlet_delta_y(i)/2], w_field(i));
%                 end
%                 axis([hAxis1 hAxis2], 'ij');
%                 kids = get(hAxis2, 'children');
%             %     set(kids, 'edgecolor', 'none');
%                 cMap = colormap('jet');
%                 set(hAxis2, 'color', cMap(1,:));

        xPosV = xPosV/10;
        yPosV = yPosV/10;
        beamlet_delta_x = beamlet_delta_x/10;
        beamlet_delta_y = beamlet_delta_y/10;

        IMBase.goals.PBMargin = 0.5;
        IMBase.goals.structNum = 2;
        IMBase.params.xyDownsampleIndex = 1;
        IMBase.goals.isTarget(1) = 'y';
        IMBase.goals.xySampleRate = 2;
        IMBase.params.numCTSamplePts = 300;

        IMBase.beams(1).zRel = 0;
        IMBase.beams(1).xRel =  IMBase.beams(1).isodistance * sindeg(IMBase.beams(1).gantryAngle);
        IMBase.beams(1).yRel =  IMBase.beams(1).isodistance * cosdeg(IMBase.beams(1).gantryAngle);

        %IMBase.params.algorithm = 'VMC++';
        %IMCalc = IMRTP_MapCheck(IMBase);

        IMBase.params.algorithm = 'DPM';
        IMCalc = IMRTP_MapCheck(IMBase, planC, stateS, xPosV, yPosV, beamlet_delta_x, beamlet_delta_y, gA);
        % JC. 11 Aug, 05 Added more arguments to IMRTP_MapCheck,

        %disp('OK_BIG1'); pause(5);
        % JC. Aug. 3, 2005
        % Add fields to IMCalc, necessary for generateDPMInfluence.m
        IMCalc.beams.couchAngle = 0;
        IMCalc.beams.collimatorAngle = 0;
        IMCalc.params.ScatterMethod = 'exponential';
        IMCalc.params.Scatter.Threshold = scatterThreshold;
        IMCalc.params.Scatter.RandomStep = 30;
        IMCalc.beamlets = struct;

        % JC Jun 06 2006
        % Still need to fill in the structure of IMCalc, but don't need put
        % it back(?), since it's not to be used to calculate dose.
        % Will also need to use 'DoseScale' inside generateDPMdose.m,
        % since DPM output dose on a per partical base.
        % Need to use w_field as a way of telling DPM how to add beamlets
        % up.

        [doseV indV] = generateDPMdose(IMCalc,spectrum_File,nhist, OutputError,planC,stateS, indexBeam, w_field);

       siz = getUniformizedSize(planC);
       dose3D = zeros(siz);

       if (OutputError == 1)
            doseV = doseV(:,1);
            Error_3D = zeros(siz);
            Error_3D(indV') = doseV(:,2);
        else
            disp('Do not output error')
            dose3D(indV') = doseV;
        end

        filename = ['doseV_',num2str(indexBeam),'_', num2str(nhist), '_', num2str(batch)];
        save(filename, 'doseV', 'indV');

        filename = ['dose3D_',num2str(indexBeam),'_', num2str(nhist), '_', num2str(batch)];
        save(filename, 'dose3D');

        % Only Output w_field for the first batch
        if(batch == 1)
            filename = ['w_field',num2str(indexBeam)];
            save(filename, 'w_field');%dose3D = (dose3D/max(dose3D(:)));
        end

        clear IMCalc dose3D w_field

    end

end


function katcherr(err_mode,err_typ)
% KATCHERR Catch error function.

% Author: Craig Borghesani
% Date: 11/15/94
% Revised:
% Copyright (c) 1999, Prentice-Hall

f = gcf;
ui_han = get(f,'userdata');
stat_bar = get(ui_han(43),'userdata');

if err_mode == 1,
 set(stat_bar,'string','An Error has occurred in TERMIMPL');
elseif err_mode == 2,
 if err_typ == 1, typ_str = 'Gain';
 elseif err_typ == 2, typ_str = 'Integrator';
 elseif err_typ == 3, typ_str = 'Differentiator';
 elseif err_typ == 4, typ_str = 'Real Pole';
 elseif err_typ == 5, typ_str = 'Real Zero';
 elseif err_typ == 6, typ_str = 'Complex Pole';
 elseif err_typ == 7, typ_str = 'Complex Zero';
 elseif err_typ == 8, typ_str = 'Lead/Lag';
 elseif err_typ == 9, typ_str = 'Num/Den';
 elseif err_typ == 10, typ_str = 'Delay';
 elseif err_typ == 11, typ_str = 'Design Point'; end
 if err_typ ~= 9,
  set(stat_bar,'string',['Incorrect type of input for ',typ_str,' element.  Please re-enter.']);
 else
  set(stat_bar,'string',['Coefficients must be in brackets. i.e. [1,2,3]']);
 end
elseif err_mode == 3,
 if err_typ == 1, typ_str = 'Proportional Gain';
 elseif err_typ == 2, typ_str = 'Integral Gain';
 elseif err_typ == 3, typ_str = 'Derivative Gain';
 elseif err_typ == 4, typ_str = 'Design Point'; end
 set(stat_bar,'string',['Incorrect type of input for ',typ_str,' element.  Please re-enter.']);
elseif err_mode == 4,
 if err_typ == 1,
  typ_str = 'Gain';
  opt_str = 'Please re-enter.';
 elseif err_typ == 4,
  typ_str = 'Real Pole';
  opt_str = 'Please use an Integrator.';
 elseif err_typ == 5,
  typ_str = 'Real Zero';
  opt_str = 'Please use a Differentiator.';
 elseif any(err_typ == [6,7,11]),
  typ_str = 'wn';
  if err_typ == 6,
   opt_str = 'Please use an Integrator.';
  elseif err_typ == 7,
   opt_str = 'Please use a Differentiator.';
  else
   opt_str = 'Please re-enter.';
  end
 end
 set(stat_bar,'string',[typ_str,' cannot be zero  ',opt_str]);
elseif err_mode == 5,
 set(stat_bar,'string','Phase value must be < 88 degrees or > -88 degrees');
elseif err_mode == 6,
 set(stat_bar,'string','Corner frequency cannot be zero');
end


function delete_count = file_sequence_delete ( file_name )

%*****************************************************************************80
%
%% FILE_SEQUENCE_DELETE deletes a file sequence.
%
%  Discussion:
%
%    We suppose the user has a set of files whose names differ only
%    in some numeric tag that is sequentially increasing, as, perhaps,
%    "file001.txt", "file002.txt" through "file137.txt", say.
%
%    The user specifies FILE_NAME as the name of the first file in the
%    sequence.  This function deletes that file, generates the next
%    name in the sequence, and, if a file with that name exists, it
%    deletes it as well.  The process continues until a file name is
%    reached for which there is no existing file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 October 2008
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string FILE_NAME, the name of the first file in the sequence.
%
%    Output, integer DELETE_COUNT, the number of files deleted.
%
  delete_count = 0;

  while ( exist ( file_name, 'file' );

    delete ( file_name );

    delete_count = delete_count + 1;

    file_name = filename_inc ( file_name );

  end

  return
end


classdef PTKGetMaskForContext < PTKPlugin
    % PTKGetMaskForContext. Plugin for returning a mask corresponding to the
    %     current context
    %
    %     This is a plugin for the Pulmonary Toolkit. Plugins can be run using
    %     the gui, or through the interfaces provided by the Pulmonary Toolkit.
    %     See PTKPlugin.m for more information on how to run plugins.
    %
    %     Plugins should not be run directly from your code.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2014.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Mask for context'
        ToolTip = 'Shows a mask corresponding to the current context'
        Category = 'Context'

        Context = PTKContextSet.Any
        AllowResultsToBeCached = false
        AlwaysRunPlugin = true
        PluginType = 'DoNothing'
        HidePluginInDisplay = true
        FlattenPreviewImage = false
        PTKVersion = '2'
        ButtonWidth = 6
        ButtonHeight = 1
        GeneratePreview = false
    end

    methods (Static)
        function results = RunPlugin(dataset, context, reporting)
            % Get a mask for the current region to analyse
            results = dataset.GetTemplateImage(context);
            if (context == PTKContext.LungROI) || (context == PTKContext.OriginalImage)
                results = dataset.GetTemplateImage(PTKContext.Lungs);
            end

            results.CropToFit;
        end
    end
end


%% fmin_symbolic_form
% Below is a demonstration of the features of the |fmin_symbolic_form| function

%%
clear; close all; clc;

%% Syntax
% |Fmin=fmin_symbolic_form(Pn,OPT_struct,F);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% 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/>.


function semantic_segmentation_rgb(fileName, sensorType, varName)

    %% Check if input is valid
    if ~isstring(fileName) && ~ischar(fileName)
        error("File name must a string or char array\n")
    end

    if ~strcmp(sensorType, "semantic_segmentation_rgb")
       error("Wrong sensor selected\n")
    end

    if ~isvarname(varName)
        error("Invalid variable name\n")
    end

    %% Create a python file
    file = fopen(strcat(fileName, '.py'), 'w');

    % Automatically genrates a python file containing the sensor call back
    % bindings
    fprintf(file, 'import numpy as np\n');
    fprintf(file, 'from collections import defaultdict\n');
    fprintf(file, '\n');
    fprintf(file, '# Converts the tags to human observable colors\n');
    fprintf(file, '_mapDict = defaultdict(lambda: (255, 255, 255), {\n');
    fprintf(file, '    0: (0, 0, 0),\n');
    fprintf(file, '    0: (0, 0, 0),\n');
    fprintf(file, '    1: (70, 70, 70),\n');
    fprintf(file, '    2: (100, 40, 40),\n');
    fprintf(file, '    3: (55, 90, 80),\n');
    fprintf(file, '    4: (220, 20, 60),\n');
    fprintf(file, '    5: (153, 153, 153),\n');
    fprintf(file, '    6: (157, 234, 50),\n');
    fprintf(file, '    7: (128, 64, 128),\n');
    fprintf(file, '    8: (244, 35, 232),\n');
    fprintf(file, '    9: (107, 142, 35),\n');
    fprintf(file, '    10: (0, 0, 142),\n');
    fprintf(file, '    11: (102, 102, 156),\n');
    fprintf(file, '    12: (220, 220, 0),\n');
    fprintf(file, '    13: (70, 130, 180),\n');
    fprintf(file, '    14: (81, 0, 81),\n');
    fprintf(file, '    15: (150, 100, 100),\n');
    fprintf(file, '    16: (230, 150, 140),\n');
    fprintf(file, '    17: (180, 165, 180),\n');
    fprintf(file, '    18: (250, 170, 30),\n');
    fprintf(file, '    19: (110, 190, 160),\n');
    fprintf(file, '    20: (170, 120, 50),\n');
    fprintf(file, '    21: (45, 60, 150),\n');
    fprintf(file, '    22: (145, 170, 100),\n');
    fprintf(file, '})\n');
    fprintf(file, '\n');
    fprintf(file, 'def _setup_mapping():\n');
    fprintf(file, '    global _mapDict\n');
    fprintf(file, '    global _mapping_array\n');
    fprintf(file, '\n');
    fprintf(file, '    tags = np.array(list(_mapDict.keys()))\n');
    fprintf(file, '    colors = np.array(list(_mapDict.values()))\n');
    fprintf(file, '\n');
    fprintf(file, '    _mapping_array = np.zeros((tags.max()+1, 3), dtype="uint8")\n');
    fprintf(file, '    _mapping_array[tags] = colors\n');
    fprintf(file, '\n');

    fprintf(file, 'def bindSensor(sensor):\n');
    fprintf(file, '    _setup_mapping()\n');
    fprintf(file, '    sensor.listen(lambda _image: do_something(_image))\n');
    fprintf(file, '\n');
    fprintf(file, 'def do_something(_image):\n');
    fprintf(file, '    global %s\n', varName);
    fprintf(file, '    global _mapping_array\n');
    fprintf(file, '\n');
    fprintf(file, '    data = np.frombuffer(_image.raw_data, dtype=np.dtype("uint8"))\n');
    fprintf(file, '\n');
    fprintf(file, '    # Get the red channel which has the tags\n');
    fprintf(file, '    data = np.reshape(data, (_image.height, _image.width, 4))\n');
    fprintf(file, '    data = data[:, :, 2]\n');
    fprintf(file, '\n');
    fprintf(file, '    # Map the tags to their respective RGB colors\n');
    fprintf(file, '    data = _mapping_array[data]\n');
    fprintf(file, '\n');
    fprintf(file, '    # Convert the data into MATLAB cast compatible type\n');
    fprintf(file, '    %s = np.ascontiguousarray(data)\n', varName);

    fclose(file);
end


function vw = drawROIs(vw, whichRois, method)
%
% vw = drawROIs(vw, <whichRois=get from view>, <method=get from vw>)
%
% Draw the specified ROIs on the view's current display.
%
% whichRois: vector of ROIs in the vw.ROIs field to draw. If omitted,
% parses the view's ROI settings (in vw.ui.showROIs)
% to decide the ROI order:
%   -2: draw all ROIs perimeter
%   -1: draw selected ROIs perimeter
%    0: don't draw any ROIs
%    1: draw selected ROI, boxes around each pixel
%    2: draw all ROIs, boxes around each pixel.
%
% whichRois can also be a cell array of ROI names
%
% method: can be one of the following strings or flags:
%   1 or 'perimeter', outline pixel perimeters
%   2 or 'boxes': boxes around each pixel
%   3 or 'patches': semi-transparent patches. (Matlab 7+ only)
%  If omitted, this is taken from the view struct, or (for hidden views)
%  defaults to 1.
%
%
% ras 05/06: updated to be much more efficient. Added patches option.
% TODO: re-implement the 'Filled Perimeter' option.
if ~exist('whichRois', 'var') | isempty(whichRois)
    % get from view
    if checkfields(vw, 'ui', 'showROIs')
        if length(vw.ui.showROIs) <= 1
            switch vw.ui.showROIs
                case -2, whichRois = 1:length(vw.ROIs);
                case -1, whichRois = vw.selectedROI;
                case 0, whichRois = [];
                otherwise, whichRois = vw.ui.showROIs;  % manually specify
            end
        else
            whichRois = vw.ui.showROIs;
        end
    else
        whichRois = 1:length(vw.ROIs);
    end
end

if ~exist('method', 'var') | isempty(method)
    % get from view
    if checkfields(vw, 'ui', 'roiDrawMethod')
        method = vw.ui.roiDrawMethod;

    else
        method = 'perimeter';

    end
end

% ML 7 check
if isequal(method, 'patches') | isequal(method, 3)
    ver = version;
    if str2num(ver(1)) < 7
        warning('Need MATLAB 7+ to draw patches ... drawing boxes instead')
        method = 'boxes';
    end
end

if iscell(whichRois)    % allow names of ROIs to be passed in
    roiNames = {vw.ROIs.name};
    whichRois = ismember(roiNames, whichRois);
    drawROIs(vw, whichRois, method);
    return
end

%%%%%ensure a field is set for the ROI object handles
N = length(vw.ROIs);
% if ~checkfields(vw, 'ui', 'roiHandles') | length(vw.ui.roiHandles) < N
%     vw.ui.roiHandles = cell(1, N);
% elseif N > length(vw.ui.roiHandles)
%     vw.ui.roiHandles = vw.ui.roiHandles(1:N);
% end
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Draw the ROIs -- updated algorithms %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch vw.viewType
    case 'Inplane'
        vw = inplaneDrawROIs(vw, whichRois, method); % attached below

    case {'Volume' 'Gray'}
        % test for 3-axes view vs. single-orientation view:
        if checkfields(vw, 'ui', 'axiAxesHandle')
            vw = volumeDrawROIs(vw, 1, 1, whichRois, method);
            vw = volumeDrawROIs(vw, 2, 1, whichRois, method);
            vw = volumeDrawROIs(vw, 3, 1, whichRois, method);
        else
            ori = getCurSliceOri(vw);
			slice = viewGet(vw, 'Current Slice');
            vw = volumeDrawROIs(vw, ori, slice, whichRois, method);
        end

    case 'Flat'
        vw = flatDrawROIs(vw, whichRois, method); % attached below

end

return
% /------------------------------------------------------------------/ %

% /------------------------------------------------------------------/ %
function vw = inplaneDrawROIs(vw, whichRois, method);
% Draw specified ROIs according to the specified method, for inplanes
delete( findobj('Parent', vw.ui.mainAxisHandle, 'Type', 'line') )
if isempty(vw.ROIs) | whichRois==0, return; end
prefs.method = method;
for r = whichRois
    if isempty(vw.ROIs(r).coords), continue; end

    % get color
    color = vw.ROIs(r).color;
    if r==vw.selectedROI, color = viewGet(vw, 'selRoiColor'); end

    % delete old ROI hanldes
    try,   delete(vw.ui.roiHandles{r}); end
    % delete(findobj('Parent', vw.ui.mainAxisHandle, 'Type', 'line'))

    % find coords of ROI within the displayed slice
    pixels = coords2Montage(vw, vw.ROIs(r).coords);

    prefs.color = color;
    vw.ui.roiHandles{r} = outline(pixels, prefs);
end
return
% /------------------------------------------------------------------/ %

% /------------------------------------------------------------------/ %
function vw = volumeDrawROIs(vw, ori, slice, whichRois, method);
% Draw specified ROIs in an image of the specified orientation,
% according to the specified method, for volume/gray views
delete( findobj('Parent', vw.ui.mainAxisHandle, 'Type', 'line') )
if isempty(vw.ROIs) | whichRois==0, return; end
prefs.method = method;
if isempty(whichRois), return; end

for r = whichRois
    % get color
    color = vw.ROIs(r).color;
    if r==vw.selectedROI, color = viewGet(vw, 'selRoiColor'); end

    % delete old ROI hanldes
    try, delete(vw.ui.roiHandles{r}); end
    delete(findobj('Parent', vw.ui.mainAxisHandle, 'Type', 'line'))

    % find coords of ROI within the displayed slice
    coords = canOri2CurOri(vw, vw.ROIs(r).coords, ori);
	inSlice = find(coords(3,:)==slice);
	if isempty(inSlice)
		vw.ui.roiHandles{r} = [];
		continue
	end

    prefs.color = color;
    vw.ui.roiHandles{r} = outline(coords(1:2,inSlice), prefs);
end
% /------------------------------------------------------------------/ %

% /------------------------------------------------------------------/ %
function vw = flatDrawROIs(vw, whichRois, method);
% Draw specified ROIs according to the specified method, for flat views
prefs.method = method;
delete(findobj('Parent', vw.ui.mainAxisHandle, 'Type', 'line'))
if isempty(vw.ROIs) | whichRois==0, return; end
for r = whichRois
    % get color
    color = vw.ROIs(r).color;
    if r==vw.selectedROI, color = viewGet(vw, 'selRoiColor'); end

    % delete old ROI handles
    if checkfields(vw, 'ui', 'roiHandles') & length(vw.ui.roiHandles) >= r
        delete(vw.ui.roiHandles{r});
    end
    coords = vw.ROIs(r).coords;

	if isempty(coords), continue; end

    % The FLAT view has a 'rotateImageDegrees' field that
    % specifies a rotation angle for each slice (L or R).
    % If this is set, then we have to transform the ROIs by this amount as
    % well to make them register with the anatomy and functional data
    coords = rotateCoords(vw, coords);

    % restrict to coords in the slice, zoom
    slice = viewGet(vw, 'Current Slice');  % should really make this work for hidden views
    xZoom = vw.ui.zoom(1:2);
    yZoom = vw.ui.zoom(3:4);
    ok = find(coords(1,:)>=yZoom(1) & coords(1,:)<=yZoom(2) & ...
              coords(2,:)>=xZoom(1) & coords(2,:)<=xZoom(2) & ...
              coords(3,:)==slice);
    coords = coords(:,ok);

    prefs.color = color;
    prefs.method = method;
    vw.ui.roiHandles{r} = outline(coords, prefs);
end

return