% ==============================================================================
%
%    Software License Agreement (BSD License)
%    Copyright (c) 2019
%    (www.aimlab.wpi.edu)
%
%    All rights reserved.
%
%    Redistribution and use in source and binary forms, with or without
%    modification, are permitted provided that the following conditions
%    are met:
%
%    * Redistributions of source code must retain the above copyright
%    notice, this list of conditions and the following disclaimer.
%
%    * 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.
%
%    * Neither the name of authors nor the names of its contributors may
%    be used to endorse or promote products derived from this software
%    without specific prior written permission.
%
%    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 OWNER 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.
%
%    \author:    <http://www.aimlab.wpi.edu>
%    \author:    <amunawar@wpi.edu>
%    \author:    Adnan Munawar
%    \version:   0.1$
% ==============================================================================

function benchmarkRRT

clc;
close all;
clear all;

num_of_runs =1;
run_RRTconnect =0;
run_RRTextend = 0;
run_LazyRRT = 0;
run_RRTstar = 1;

dim = 2;
stepsize = [5];

random_world = 0;
radius = 10;
samples = 4000;

show_output = 1;
show_benchmark_results = 0;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

t_lazy = [];
t_extend = [];
t_connect = [];
t_star = [];

l_lazy = [];
l_extend = [];
l_connect = [];
l_star = [];

p_lazy = [];
p_extend = [];
p_connect = [];
p_star = [];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

for sits = 1:size(stepsize,2)
    segmentLength = stepsize(sits);
    if run_LazyRRT == 1
        time = 0;
        avg_its = 0;
        avg_path = 0;

        for i = 1:num_of_runs

            [n_its path_n run_time] =  LazyRRT3D(dim,segmentLength,random_world,show_output);
            time = time + run_time;
            avg_its = avg_its + n_its;
            avg_path = avg_path + path_n;
        end

        str1 = ['The time taken by Lazy RRT for ', num2str(num_of_runs), ' runs is ', num2str(time)];
        str2 = ['The averagae time taken by Lazy RRT for each run is ', num2str(time/num_of_runs)];
        str3 = ['The averagae number of states explored by Lazy RRT for each run is ', num2str(avg_its/num_of_runs)];
        str4 = ['The averagae number of state in Path by Lazy RRT for each run is ', num2str(avg_path/num_of_runs)];

        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
        disp(str1);
        disp(str2);
        disp(str3);
        disp(str4);
        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');

        t_lazy = [t_lazy time/num_of_runs];
        l_lazy = [l_lazy avg_its/num_of_runs];
        p_lazy = [p_lazy avg_path/num_of_runs];

    end

    if run_RRTstar == 1
        time = 0;
        avg_its = 0;
        avg_path = 0;
        for i = 1:num_of_runs
            [n_its path_n,run_time] = RRTstar3D(dim,segmentLength,radius,random_world,show_output,samples);
            time = time + run_time;
            avg_its = avg_its + n_its;
            avg_path = avg_path + path_n;
        end

        str1 = ['The time taken by RRT-Star for ', num2str(num_of_runs), ' runs is ', num2str(time)];
        str2 = ['The averagae time taken by RRT_Star for each run is ', num2str(time/num_of_runs)];
        str3 = ['The averagae number of states explored by RRT_Star for each run is ', num2str(avg_its/num_of_runs)];
        str4 = ['The averagae number of state in Path by RRT-Star for each run is ', num2str(avg_path/num_of_runs)];

        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
        disp(str1);
        disp(str2);
        disp(str3);
        disp(str4);
        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');

        t_star = [t_star time/num_of_runs];
        l_star = [l_star avg_its/num_of_runs];
        p_star = [p_star avg_path/num_of_runs];

    end

    if run_RRTextend == 1
        time = 0;
        avg_its = 0;
        avg_path = 0;
        for i = 1:num_of_runs
            [n_its path_n,run_time] = RRTextend3D(dim,segmentLength,random_world,show_output);
            time = time + run_time;
            avg_its = avg_its + n_its;
            avg_path = avg_path + path_n;
        end

        str1 = ['The time taken by RRT-Extend for ', num2str(num_of_runs), ' runs is ', num2str(time)];
        str2 = ['The averagae time taken by RRT_Extend for each run is ', num2str(time/num_of_runs)];
        str3 = ['The averagae number of states explored by RRT_Extend for each run is ', num2str(avg_its/num_of_runs)];
        str4 = ['The averagae number of state in Path by RRT-Extend for each run is ', num2str(avg_path/num_of_runs)];

        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
        disp(str1);
        disp(str2);
        disp(str3);
        disp(str4);
        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');

        t_extend = [t_extend time/num_of_runs];
        l_extend = [l_extend avg_its/num_of_runs];
        p_extend = [p_extend avg_path/num_of_runs];

    end

    if run_RRTconnect == 1

        time = 0;
        avg_its = 0;
        avg_path = 0;

        for i = 1:num_of_runs
            [n_its path_n,run_time] =  RRTconnect3D(dim,segmentLength,random_world,show_output);
            time = time + run_time;
            avg_its = avg_its + n_its;
            avg_path = avg_path + path_n;
        end

        str1 = ['The time taken by RRT-Connect for ', num2str(num_of_runs), ' runs is ', num2str(time)];
        str2 = ['The averagae time taken by RRT-Connect for each run is ', num2str(time/num_of_runs)];
        str3 = ['The averagae number of states explored by RRT-Connect for each run is ', num2str(avg_its/num_of_runs)];
        str4 = ['The averagae number of state in Path by RRT-Connect for each run is ', num2str(avg_path/num_of_runs)];

        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
        disp(str1);
        disp(str2);
        disp(str3);
        disp(str4);
        disp('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');

        t_connect = [t_connect time/num_of_runs];
        l_connect = [l_connect avg_its/num_of_runs];
        p_connect = [p_connect avg_path/num_of_runs];
    end
end

if show_benchmark_results == 1

    figure;
    hold on;
    plot(stepsize,t_lazy,'r','LineWidth',2);
    plot(stepsize,t_extend,'g','LineWidth',2);
    plot(stepsize,t_connect,'b','LineWidth',2);
    ylabel('Computational Time');
    xlabel('Step Size');
    dim_str = sprintf('Comparison of computational time for %d Dimensional C-Space',dim);
    title(dim_str)
    hold off;

    figure;
    hold on;
    plot(stepsize,l_lazy,'r','LineWidth',2);
    plot(stepsize,l_extend,'g','LineWidth',2);
    plot(stepsize,l_connect,'b','LineWidth',2);
    ylabel('Number of States Explored');
    xlabel('Step Size');
    dim_str = sprintf(' Comparison of number of states explored for %d Dimensional C-Space',dim);
    title(dim_str)
    hold off;

    figure;
    hold on;
    plot(stepsize,p_lazy,'r','LineWidth',2);
    plot(stepsize,p_extend,'g','LineWidth',2);
    plot(stepsize,p_connect,'b','LineWidth',2);
    ylabel('Number of States in Path');
    xlabel('Step Size');
    dim_str = sprintf('Comparison for number of states in path for %d Dimensional C-Space',dim);
    title(dim_str)
    hold off;

end

%     t_lazy
%     l_lazy
%     p_lazy
%
%
%
%     t_extend
%     l_extend
%     p_extend
%
%     t_connect
%     l_connect
%     p_connect

end


function computeAllModelChoice_batchHN(pathExperiments,maxOrder,nBoot,imbalance,nBatch,matlabPATH,seed)
% -------------------------------------------------------------------------
% function computeAllModelChoice_batchHN(pathWORK,fSetName,outcomes,freedomMat,maxOrder,nBoot,imbalance,nBatch,matlabPATH)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function computes feature set selection for all feature set types
% and for all experiments with different degrees of freedom. See ref. [1,2]
% for more details.
% -------------------------------------------------------------------------
% REFERENCES:
% [1] Vallieres, M. et al. (2015). FDG-PET/CT radiomics models for the
%     early prediction of different tumour outcomes in head and neck cancer.
%     The Journal of Nuclear Medicine, aa(bb), xxx-yyy.
%     doi:
% [2] Vallieres, M. et al. (2015). A radiomics model from joint FDG-PET and
%     MRI texture features for the prediction of lung metastases in soft-tissue
%     sarcomas of the extremities. Physics in Medicine and Biology, 60(14),
%     5471-5496. doi:10.1088/0031-9155/60/14/5471
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathExperiments: Full path to where all experiments need to be
%                     performed.
%                     --> Ex: /myProject/WORKSPACE/RESULTS
% 2. expNumber: Number of the single experiment to perform
%                  --> Ex: 4
% 3. maxOrder: Integer specifying the maximal model order to construct.
%              --> Ex: 10
% 4. nBoot: Number of bootstrap samples to use.
%           --> Ex: 100
% 5. imbalance: String specifying the type of imbalance-adjustement strategy
%               employed. Either 'IABR' for imbalance-adjusted bootstrap
%               resampling (see ref.[1]), or 'IALR' for imbalance-adjusted
%               logistic regression (see ref.[2]).
%               --> Ex: 'IALR'
% 6. nBatch: Number of parallel batch.
%            --> Ex: 8
% 7. matlabPATH: Full path to the MATLAB excutable on the system.
%                --> 'matlab' if a symbolic link to the matlab executable
%                     was previously created.
% 9. seed: Numerical number to use as seed for bootstrapping experiment
%          --> Ex: 54288
% -------------------------------------------------------------------------
% OUTPUTS: Mutivariable models are saved in a folder named 'MODELS' in the
% corresponding folder of each experiment (e.g. 'Experiment1', 'Experiment2', etc.)
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: March 2016
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015  Martin Vallieres
%
%    This package 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 package 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 package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

startpath = pwd;

% INITIALIZATON
time = 60; % Number of seconds to wait before checking if parallel computations are done
cd(pathExperiments), load('training')
pathSet = fullfile(pwd,'FSET'); mkdir('MODELS'), cd('MODELS'), pathModels = pwd;
mkdir('batchLog_Models'), cd('batchLog_Models'), pathBatch = pwd;
nameOutcomes = fieldnames(training); nOutcomes = numel(nameOutcomes);
for o = 1:nOutcomes
    outcomes.(nameOutcomes{o}) = training.(nameOutcomes{o}).outcome;
end
setNames = fieldnames(training.(nameOutcomes{1}).text);
[param] = batchExperiments(setNames,outcomes,nBatch); nBatch = length(param);

% PRODUCE BATCH COMPUTATIONS
save('workspace','pathSet','pathModels','training','param','maxOrder','nBoot','imbalance','seed'), pause(5);
for i = 1:nBatch
    nameScript = ['batch',num2str(i),'_script.m'];
    fid = fopen(nameScript,'w');
    fprintf(fid,'load(''workspace'')\n');
    for j = 1:numel(param{i})
        fprintf(fid,['computeAllModelChoice_HN(pathSet,pathModels,training,param{',num2str(i),'}{',num2str(j),'},maxOrder,nBoot,imbalance,seed)\n']);
    end
    fprintf(fid,['system(''touch batch',num2str(i),'_end'');\n']);
    fprintf(fid,'clear all');
    fclose(fid);
    system([matlabPATH,' -nojvm -nodisplay -nodesktop -nosplash < ',nameScript,' >& ',nameScript(1:end-1),'log &']);
end

% WAITING LOOP
waitBatch(pathBatch,time,nBatch)
delete('workspace.mat')

cd(startpath)
end


function produceVASARIplot_LGG(pathResults,nameOutcomes,maxOrder,pathFig)
% -------------------------------------------------------------------------
% function produceVASARIplot_LGG(pathResults,nameOutcomes,maxOrder,pathFig)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function produce the Figure 4 of the LGG study.
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathResults: Full path to the directory containing all experiments.
%                     --> Ex: '/myProject/WORKSPACE/VASARI/RESULTS'
% 2. nameOutcomes: Cell of strings specifying the outcome names to analyze.
%                  --> Ex: {'nonIDH1','IDHcodel','progression','lowGrade'}
% 3. maxOrder: Integer specifying the maximal multivariable model order.
%              --> Ex: 10
% 4. pathFig: (optional).  Full path to where figure is saved without
%             displaying it. Put '' for displaying the figure and not
%             saving it to 'pathFig' (default).
%             --> Ex: ''
% -------------------------------------------------------------------------
% OUTPUTS: Final prediction models saved in a folder named
%          '/myProject/WORKSPACE/VASARI/FINAL_MODELS/nameOutcome/fSetName'
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: January 2017
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015-2017  Martin Vallieres
%
%    This package 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 package 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 package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

startpath = pwd;
cd(pathResults)

if nargin < 4
    pathFig = '';
end

signs = {'-r',':b','--g','-.y'};
nOutcomes = numel(nameOutcomes);

if isempty(pathFig)
    figure
else
    h = figure('visible','off');
end
for o = 1:nOutcomes
    nameOutcome = nameOutcomes{o};
    plotAllPredictionResults_VASARI_LGG(pathResults,nameOutcome,{'VASARI'},'AUC632',maxOrder,signs{o})
    hold on
end
legend(nameOutcomes)
title(['VASARI'],'FontSize',30,'FontWeight','bold')

if ~isempty(pathFig)
    cd(pathFig)
    saveas(h,['VASARI_PLOT'],'fig')
end

cd(startpath)
end


% Codes for CVPR-15 work `Face Alignment by Coarse-to-Fine Shape Searching'
% Any question please contact Shizhan Zhu: zhshzhutah2@gmail.com
% Released on July 25, 2015

function newImages = transImagesFwd(oldImages,T,rows,cols)
%newImages = transImagesFwd(oldImages)
%   images are all cell array.

m = length(oldImages);
if m~=length(T),error('size(oldImages,1) must equal to length(T)!');end;

if (m<100) || (matlabpool('size')==0)
    newImages = arrayfun(@(i)imtransform(oldImages{i},T(i),'XData',...
        [1 cols],'YData',[1 rows]),1:m,'UniformOutput',false);
    if (m>=100)
        warning('Please launch matlabpool to speed up your program!');
    end
else
    newImages = cell(m,1);
    parfor i = 1:m
        newImages{i} = imtransform(oldImages{i},T(i),'XData',...
            [1 cols],'YData',[1 rows]);
    end
end
for i = 1:m, if size(newImages{i},1)~=rows || size(newImages{i},2)~=cols, newImages{i} = imresize(newImages{i},[rows,cols]);end;end;

end


function chooseBestModels_HN(pathExperimentsBinary,pathExperimentsTime,fSetNames,nameOutcomes,metric,maxOrder)
% -------------------------------------------------------------------------
% function chooseBestModels_HN(pathWORK,nExp,fSetName,nameOutcomes,maxOrder)
% -------------------------------------------------------------------------
% DESCRIPTION:
% This function requires user input to choose the set types and model orders
% providing the best parsimonious models for all outcomes analyzed in the
% HN study. See ref.[1] for more details.
% -------------------------------------------------------------------------
% REFERENCE:
% [1] Vallieres, M. et al. (2015). FDG-PET/CT radiomics models for the
%     early prediction of different tumour outcomes in head and neck cancer.
%     The Journal of Nuclear Medicine, aa(bb), xxx-yyy.
%     doi:
% -------------------------------------------------------------------------
% INPUTS:
% 1. pathExperiments: Full path to the directory containing all experiments.
%                     --> Ex: '/myProject/WORKSPACE/CV-BASED_RESULTS'
% 2. nExp: Numerical value specifying the number of experiments to analyze.
%          --> Ex: 10
% 3. fSetName: Cell of strings specifying the name of the type of feature
%              set analyzed.
%              --> Ex: {'PET','CT','SEPARATE','FUSED'}
% 4. nameOutcomes: Cell of strings specifying the outcome names to analyze.
%                  --> Ex: {'Failure','Locoregional','Distant','Death'}
% 5. maxOrder: Integer specifying the maximal multivariable model order.
%              --> Ex: 10
% -------------------------------------------------------------------------
% OUTPUTS: Final prediction models saved in a folder named 'FINAL_MODELS/nameOutcome/fSetName'
%          in the given experiment folder.
% -------------------------------------------------------------------------
% AUTHOR(S): Martin Vallieres <mart.vallieres@gmail.com>
% -------------------------------------------------------------------------
% HISTORY:
% - Creation: March 2016
%--------------------------------------------------------------------------
% STATEMENT:
% This file is part of <https://github.com/mvallieres/radiomics/>,
% a package providing MATLAB programming tools for radiomics analysis.
% --> Copyright (C) 2015  Martin Vallieres
%
%    This package 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 package 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 package.  If not, see <http://www.gnu.org/licenses/>.
% -------------------------------------------------------------------------

startpath = pwd;
cd(pathExperimentsBinary)
nOutcomes = length(nameOutcomes);
nType = length(fSetNames);

fprintf('\n')
cd(pathExperimentsTime), pathExperimentTime = pathExperimentsTime;
cd(pathExperimentTime), mkdir('FINAL_MODELS'), cd('FINAL_MODELS'), pathFinalModelsTime = pwd;
cd(pathExperimentsBinary), pathExperimentBinary = pathExperimentsBinary;
cd(pathExperimentBinary), mkdir('FINAL_MODELS'), cd('FINAL_MODELS'), pathFinalModelsBinary = pwd;
for o = 1:nOutcomes
    cd(pathFinalModelsTime), mkdir(nameOutcomes{o}), cd(fullfile(pathFinalModelsTime,nameOutcomes{o})), pathOutcomeTime = pwd;
    cd(pathFinalModelsBinary), mkdir(nameOutcomes{o}), cd(fullfile(pathFinalModelsBinary,nameOutcomes{o})), pathOutcomeBinary = pwd;
    plotPredictionResults_HN(fullfile(pathExperimentBinary,'RESULTS'),nameOutcomes{o},fSetNames,metric,maxOrder)
    fprintf('\n======== DISPLAYING PREDICTION RESULTS FOR "%s" OUTCOME, "%s" METRIC  ========\n',nameOutcomes{o},metric)
    for f = 1:nType
        cd(pathOutcomeTime), mkdir(fSetNames{f}), cd(fullfile(pathOutcomeTime,fSetNames{f})), pathFinalTime = pwd;
        cd(pathOutcomeBinary), mkdir(fSetNames{f}), cd(fullfile(pathOutcomeBinary,fSetNames{f})), pathFinalBinary = pwd;
        while 1
            order = input(['Which model order of the ',fSetNames{f},' feature set provides the best parsimonious model? \n' ...
                           '--> Type a number between 1 to ',num2str(maxOrder),' and press ENTER \n' ...
                           'ANSWER: ']);
            fprintf('\n')
            if isnumeric(order) && order <= maxOrder && order >= 1
                break
            end
        end
        cd(fullfile(pathExperimentBinary,'RESULTS'))
        results = load(['RESULTS_',fSetNames{f},'_',nameOutcomes{o}]); results = struct2cell(results); results = results{1};
        finalModel = results.(['Order',num2str(order)]);
        finalModel.Order = order;
        finalModel.outcome = nameOutcomes{o};
        cd(pathFinalBinary), save('finalModel','finalModel')
        cd(pathFinalTime), save('finalModel','finalModel')
    end
    close all
end

cd(startpath)
end


function vw = er_groupScans(vw,scans,assignFlag,dt)
% vw = er_groupScans(vw,[scans],[assignFlag],[datatype])
%
% Create a functional grouping of scans for future
% analyses / plotting.
%
% This is useful if you have run more than one different
% scan type in a session, and want to plot the concatenated
% tSeries from similar scans together, or apply analyses (like
% GLM) to them, without manually selecting them each time.
%
% Note that the assignment can cross data type: you can group
% a bunch of Original scans together, then assign that group
% to the average of those scans in Averages, for instance. Then
% you can e.g. look at a corAnal from the average scan, invoke
% time course UI to look at the time series from the original scans,
% and not have to switch back to the Originals data type.
%
% scans: which scans to group. default: prompt for scans.
%
% assignFlag: flag describing which scans to assign the scan
% group to. 1 -- assign to current scan; 2 -- assign
% to each scan in the group. [Default: 2]
%
% datatype: # or name of the data type in dataTYPES to which the grouped
% scans belong. If choosing the scans with a dialog, you can choose
% this as well. Otherwise, defaults to the current data type.
%
% written by ras 2004.04.07.
global dataTYPES HOMEDIR;

names = {dataTYPES.name};

cdt = vw.curDataType;

if ieNotDefined('assignFlag'),assignFlag = 2; end

% if dt hasn't already been assigned, set to current
if ieNotDefined('dt'), dt = cdt; end

% if a string specified for dt, find # of data type
if ischar(dt), dt = existDataType(dt); end

if ieNotDefined('scans')
    % get scans w/ dialog:

    % first choose data type
    if assignFlag==2, dt = menu('Group scans in which data type?',names);
    else              dt = vw.curDataType; end

    % get list of scans in this data type
    vw.curDataType = dt;
    scans = er_selectScans(vw);
    vw.curDataType = cdt;
end

switch assignFlag
    case 1, tgtScans = viewGet(vw, 'curScan');
        tgtDt = cdt;
    case 2, tgtScans = scans;
        tgtDt = dt;
    otherwise,
        error('assignFlag must be 1 or 2.');
end

% check if there's already a scanGroup field
% in dataTYPES.scanParams for the tgt data type:
for j = 1:length(dataTYPES)
    if ~isfield(dataTYPES(j).scanParams(end),'scanGroup')
        dataTYPES(j).scanParams(end).scanGroup = [];
    end
end

% assign the scans to the scanGroup field for the relevant
% scans:
grpTxt = sprintf('%s: %s',dataTYPES(dt).name,num2str(scans));
for s = tgtScans
    dataTYPES(tgtDt).scanParams(s).scanGroup = grpTxt;
end

mrSessPath = fullfile(HOMEDIR,'mrSESSION.mat');
save(mrSessPath,'dataTYPES','-append');

return


function xyzhumanevaGenerateMovie(Z,filename)

% XYZHUMANEVAGENERATEMOVIE
%
% COPYRIGHT : Carl Henrik Ek and Neil Lawrence, 2008

% MOCAP

if(nargin<2)
  filename = 'humaneva_movie';
end

% front view
mov = avifile(strcat(filename,'_front.avi'));
h = xyzhumanevaVisualise(Z(1,:),1);
F = getframe(gca);
mov = addframe(mov,F);
for(i = 2:1:size(Z,1))
  xyzhumanevaModify(h,Z(i,:));
  F = getframe(gca);
  mov = addframe(mov,F);
end
mov = close(mov);
clf(gcf,'reset');
% isometric view
mov = avifile(strcat(filename,'_3d.avi'));
h = xyzhumanevaVisualise3d(Z(1,:),1);
F = getframe(gca);
mov = addframe(mov,F);
for(i = 2:1:size(Z,1))
  xyzhumanevaModify(h,Z(i,:));
  F = getframe(gca);
  mov = addframe(mov,F);
end
mov = close(mov);

return


function hh = rotateXLabels( ax, angle, varargin )
%rotateXLabels: rotate any xticklabels
%
%   hh = rotateXLabels(ax,angle) rotates all XLabels on axes AX by an angle
%   ANGLE (in degrees). Handles to the resulting text objects are returned
%   in HH.
%
%   hh = rotateXLabels(ax,angle,param,value,...) also allows one or more
%   optional parameters to be specified. Possible parameters are:
%     'MaxStringLength'   The maximum length of label to show (default inf)
%
%   Examples:
%   >> bar( hsv(5)+0.05 )
%   >> days = {'Monday','Tuesday','Wednesday','Thursday','Friday'};
%   >> set( gca(), 'XTickLabel', days )
%   >> rotateXLabels( gca(), 45 )
%
%   See also: GCA
%             BAR

%   Copyright 2006-2010 The MathWorks Ltd.
%   $Revision: 52 $
%   $Date: 2010-09-30 11:19:49 +0100 (Thu, 30 Sep 2010) $

error( nargchk( 2, inf, nargin ) );
if ~isnumeric( angle ) || ~isscalar( angle )
    error( 'RotateXLabels:BadAngle', 'Parameter ANGLE must be a scalar angle in degrees' )
end
angle = mod( angle, 360 );

[maxStringLength] = parseInputs( varargin{:} );

% Get the existing label texts and clear them
[vals, labels] = findAndClearExistingLabels( ax, maxStringLength );

% Create the new label texts
h = createNewLabels( ax, vals, labels, angle );

% Reposition the axes itself to leave space for the new labels

%repositionAxes( ax );

% If an X-label is present, move it too
%repositionXLabel( ax );

% Store angle
setappdata( ax, 'RotateXLabelsAngle', angle );

% Only send outputs if requested
if nargout
    hh = h;
end

%-------------------------------------------------------------------------%
    function [maxStringLength] = parseInputs( varargin )
        % Parse optional inputs
        maxStringLength = inf;
        if nargin > 0
            params = varargin(1:2:end);
            values = varargin(2:2:end);
            if numel( params ) ~= numel( values )
                error( 'RotateXLabels:BadSyntax', 'Optional arguments must be specified as parameter-value pairs.' );
            end
            if any( ~cellfun( 'isclass', params, 'char' ) )
                error( 'RotateXLabels:BadSyntax', 'Optional argument names must be specified as strings.' );
            end
            for pp=1:numel( params )
                switch upper( params{pp} )
                    case 'MAXSTRINGLENGTH'
                        maxStringLength = values{pp};

                    otherwise
                        error( 'RotateXLabels:BadParam', 'Optional parameter ''%s'' not recognised.', params{pp} );
                end
            end
        end
    end % parseInputs
%-------------------------------------------------------------------------%
    function [vals,labels] = findAndClearExistingLabels( ax, maxStringLength )
        % Get the current tick positions so that we can place our new labels
        vals = get( ax, 'XTick' );

        % Now determine the labels. We look first at for previously rotated labels
        % since if there are some the actual labels will be empty.
        ex = findall( ax, 'Tag', 'RotatedXTickLabel' );
        if isempty( ex )
            % Store the positions and labels
            labels = get( ax, 'XTickLabel' );
            if isempty( labels )
                % No labels!
                return
            else
                if ~iscell(labels)
                    labels = cellstr(labels);
                end
            end
            % Clear existing labels so that xlabel is in the right position
            set( ax, 'XTickLabel', {}, 'XTickMode', 'Manual' );
            setappdata( ax, 'OriginalXTickLabels', labels );
        else
            % Labels have already been rotated, so capture them
            labels = getappdata( ax, 'OriginalXTickLabels' );
            delete(ex);
        end
        % Limit the length, if requested
        if isfinite( maxStringLength )
            for ll=1:numel( labels )
                if length( labels{ll} ) > maxStringLength
                    labels{ll} = labels{ll}(1:maxStringLength);
                end
            end
        end

    end % findAndClearExistingLabels

%-------------------------------------------------------------------------%
    function textLabels = createNewLabels( ax, vals, labels, angle )
        % Work out the ticklabel positions
%         ylim = get(ax,'YLim');
%         y = ylim(1);
        zlim = get(ax,'ZLim');
        z = zlim(1);

        % We want to work
        % in normalised coords, but switch to normalised after setting
        % position causes positions to be rounded to the nearest pixel.
        % Instead we can do the calculation by hand.
        xlim = get( ax, 'XLim' );
        normVals = (vals-xlim(1))/(xlim(2)-xlim(1));
        y = 0;

        % Now create new text objects in similar positions.
        textLabels = -1*ones( numel( vals ), 1 );
        for ll=1:numel(vals)
            textLabels(ll) = text( ...
                'Units', 'Normalized', ...
                'Position', [normVals(ll), y, z], ...
                'String', labels{ll}, ...
                'Parent', ax, ...
                'Clipping', 'off', ...
                'Rotation', angle, ...
                'Tag', 'RotatedXTickLabel', ...
                'UserData', vals(ll) );
        end

        % Now copy font properties into the texts
        updateFont();

        % Depending on the angle, we may need to change the alignment. We change
        % alignments within 5 degrees of each 90 degree orientation.
        if 0 <= angle && angle < 5
            set( textLabels, 'HorizontalAlignment', 'Center', 'VerticalAlignment', 'Top' );
        elseif 5 <= angle && angle < 85
            set( textLabels, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'Top' );
        elseif 85 <= angle && angle < 95
            set( textLabels, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'Middle' );
        elseif 95 <= angle && angle < 175
            set( textLabels, 'HorizontalAlignment', 'Right', 'VerticalAlignment', 'Bottom' );
        elseif 175 <= angle && angle < 185
            set( textLabels, 'HorizontalAlignment', 'Center', 'VerticalAlignment', 'Bottom' );
        elseif 185 <= angle && angle < 265
            set( textLabels, 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Bottom' );
        elseif 265 <= angle && angle < 275
            set( textLabels, 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Middle' );
        elseif 275 <= angle && angle < 355
            set( textLabels, 'HorizontalAlignment', 'Left', 'VerticalAlignment', 'Top' );
        else % 355-360
            set( textLabels, 'HorizontalAlignment', 'Center', 'VerticalAlignment', 'Top' );
        end
    end % createNewLabels

%-------------------------------------------------------------------------%
    function repositionAxes( ax )
        % Reposition the axes so that there's room for the labels
        % Note that we only do this if the OuterPosition is the thing being
        % controlled
        if ~strcmpi( get( ax, 'ActivePositionProperty' ), 'OuterPosition' )
            return;
        end

        % Work out the maximum height required for the labels
        textLabels = findall( ax, 'Tag', 'RotatedXTickLabel' );
        maxHeight = 0;
        for ii=1:numel(vals)
            ext = get( textLabels(ii), 'Extent' );
            if ext(4) > maxHeight
                maxHeight = ext(4);
            end
        end

        % Remove listeners while we mess around with things, otherwise we'll
        % trigger redraws recursively
        removeListeners( ax );

        % Change to normalized units for the position calculation
        oldUnits = get( ax, 'Units' );
        set( ax, 'Units', 'Normalized' );

        % Not sure why, but the extent seems to be proportional to the height of the axes.
        % Correct that now.
        set( ax, 'ActivePositionProperty', 'Position' );
        pos = get( ax, 'Position' );
        axesHeight = pos(4);
        % Make sure we don't adjust away the axes entirely!
        heightAdjust = min( (axesHeight*0.9), maxHeight*axesHeight );

        % Move the axes
        if isappdata( ax, 'OriginalAxesPosition' )
            pos = getappdata( ax, 'OriginalAxesPosition' );
        else
            pos = get(ax,'Position');
            setappdata( ax, 'OriginalAxesPosition', pos );
        end
        setappdata( ax, 'PreviousYLim', get( ax, 'YLim' ) );
        set( ax, 'Position', pos+[0 heightAdjust 0 -heightAdjust] )
        set( ax, 'Units', oldUnits );
        set( ax, 'ActivePositionProperty', 'OuterPosition' );

        % Make sure we find out if axes properties are changed
        addListeners( ax );

    end % repositionAxes

%-------------------------------------------------------------------------%
    function repositionXLabel( ax )
        % Try to work out where to put the xlabel

        removeListeners( ax );
        textLabels = findall( ax, 'Tag', 'RotatedXTickLabel' );
        maxHeight = 0;
        for ll=1:numel(vals)
            ext = get( textLabels(ll), 'Extent' );
            if ext(4) > maxHeight
                maxHeight = ext(4);
            end
        end

        % Use the new max extent to move the xlabel
        xlab = get(ax,'XLabel');
        set( xlab, 'Units', 'Normalized', 'Position', [0.5 -maxHeight 0] );
        addListeners( ax );
    end % repositionXLabel

%-------------------------------------------------------------------------%
    function updateFont()
        % Update the rotated text fonts when the axes font changes
        properties = {
            'FontName'
            'FontSize'
            'FontAngle'
            'FontWeight'
            'FontUnits'
            };
        propertyValues = get( ax, properties );
        textLabels = findall( ax, 'Tag', 'RotatedXTickLabel' );
        set( textLabels, properties, propertyValues );
    end % updateFont

%-------------------------------------------------------------------------%
    function onAxesFontChanged()
        updateFont();
        repositionAxes( ax );
        repositionXLabel( ax );
    end % onAxesFontChanged

%-------------------------------------------------------------------------%
    function onAxesPositionChanged()
        % We need to accept the new position, so remove the appdata before
        % redrawing
        if isappdata( ax, 'OriginalAxesPosition' )
            rmappdata( ax, 'OriginalAxesPosition' );
        end
        if isappdata( ax, 'OriginalXLabelPosition' )
            rmappdata( ax, 'OriginalXLabelPosition' );
        end
        repositionAxes( ax );
        repositionXLabel( ax );
    end % onAxesPositionChanged

%-------------------------------------------------------------------------%
    function onAxesLimitsChanged()
        % The limits have moved, so make sure the labels are still ok
        textLabels = findall( ax, 'Tag', 'RotatedXTickLabel' );
        xlim = get( ax, 'XLim' );
        for tt=1:numel( textLabels )
            xval = get( textLabels(tt), 'UserData' );
            pos(1) = (xval-xlim(1)) / (xlim(2)-xlim(1));
            pos(2) = 0;
            % If the tick is off the edge, make it invisible
            if xval<xlim(1) || xval>xlim(2)
                set( textLabels(tt), 'Visible', 'off', 'Position', pos )
            elseif ~strcmpi( get( textLabels(tt), 'Visible' ), 'on' )
                set( textLabels(tt), 'Visible', 'on', 'Position', pos )
            else
                % Just set the position
                set( textLabels(tt), 'Position', pos );
            end
        end

        repositionXLabel( ax );

%         xlab = get(ax,'XLabel');
%         if ~strcmpi( get( xlab, 'Units' ), 'Data' )
%             set( xlab, 'Units', 'data' );
%         end
%         pos = get( xlab, 'Position' );
%         orig_yrange = diff( orig_ylim );
%         new_yrange = diff( ylim );
%         offset = (pos(2)-orig_ylim(1)) / orig_yrange;
%         pos(2) = offset * new_yrange + ylim(1);
%         pos(1) = mean( xlim );
%         set( xlab, 'Position', pos );
%         setappdata( ax, 'PreviousYLim', ylim );
    end % onAxesPositionChanged

%-------------------------------------------------------------------------%
    function addListeners( ax )
        % Create listeners. We store the array of listeners in the axes to make
        % sure that they have the same life-span as the axes they are listening to.
        axh = handle( ax );
        listeners = [
            handle.listener( axh, findprop( axh, 'FontName' ), 'PropertyPostSet', @onAxesFontChanged )
            handle.listener( axh, findprop( axh, 'FontSize' ), 'PropertyPostSet', @onAxesFontChanged )
            handle.listener( axh, findprop( axh, 'FontWeight' ), 'PropertyPostSet', @onAxesFontChanged )
            handle.listener( axh, findprop( axh, 'FontAngle' ), 'PropertyPostSet', @onAxesFontChanged )
            handle.listener( axh, findprop( axh, 'FontUnits' ), 'PropertyPostSet', @onAxesFontChanged )
            handle.listener( axh, findprop( axh, 'OuterPosition' ), 'PropertyPostSet', @onAxesPositionChanged )
            handle.listener( axh, findprop( axh, 'XLim' ), 'PropertyPostSet', @onAxesLimitsChanged )
            handle.listener( axh, findprop( axh, 'YLim' ), 'PropertyPostSet', @onAxesLimitsChanged )
            ];
        setappdata( ax, 'RotateXLabelsListeners', listeners );
    end % addListeners

%-------------------------------------------------------------------------%
    function removeListeners( ax )
        % Rempove any property listeners whilst we are fiddling with the axes
        if isappdata( ax, 'RotateXLabelsListeners' )
            delete( getappdata( ax, 'RotateXLabelsListeners' ) );
            rmappdata( ax, 'RotateXLabelsListeners' );
        end
    end % removeListeners

end % EOF


function [u, ind, baseDataTYPE] = getScanGroups(vw, baseDT, confirm)
% Group the scans within a dataTYPE into subgroups with identical annotations.
% The number of subgroups equals the number of scans with unique
% annotations.
%
% [u, ind, baseDataTYPE] = getScanGroups(vw, baseDT)
%
% Purpose:
%   Return the list of unique scan annotatons (u) and the corresponding scan
%   numbers (ind). This is useful if you want to do calculations on all
%   scans with the same annotation (e.g., you might want to make averages
%   of these scans, etc.).
%
% Example
%   [u, ind, baseDataTYPE] = getScanGroups;

% var check
mrGlobals;
%----------------------------------------------------------------------
% variable check
if notDefined('vw'),      vw = getCurView;                       end
if notDefined('baseDT'),  baseDT = viewGet(vw, 'curdatatype');   end
if notDefined('confirm'), confirm = false;                       end
%----------------------------------------------------------------------

% set view to base dataTYPE
vw = viewSet(vw, 'currentDataTYPE', baseDT);

% get the dataTYPE name
baseDataTYPE = dtGet(dataTYPES(baseDT), 'name');

% count the scans
nScans = viewGet(vw, 'nScans');

% get the annotation for each scan
annotation = cell(1,nScans);
for scan = 1:nScans;
    annotation{scan} =  dtGet(dataTYPES(baseDT), 'annotation', scan);
end

% get a list of the unique scan annotations
u = unique(annotation);

% count them
nGroups = length(u);

% get the scan numbers that correspond to each unique scan
ind = cell(1,nGroups);
for scan =1:nGroups;
    ind{scan} = find(strcmp(u{scan},annotation));
end

% confirm the groupings
if confirm
    for group = 1:nGroups
        q{group}  = [u{group} sprintf('\n') ...
            sprintf('%s scans ', baseDataTYPE)...
            num2str(ind{group})...
            sprintf(' -> Group %d\n', group)];
    end
    theanswer = questdlg(q, mfilename);
    if ~isequal(theanswer, 'Yes')
        fprintf('[%s]: Aborting....\n', mfilename);
        u = []; ind = []; baseDataTYPE =[];
    end
end

return


function [mesh, cfg] = ft_prepare_mesh(cfg, data)

% FT_PREPARE_MESH creates a triangulated surface mesh or tetrahedral/hexahedral
% volume mesh that can be used as geometrical description for a volume conduction
% model. The mesh can either be created manually from anatomical MRI data or can be
% generated starting from a segmented MRI. This function can also be used to create a
% cortex hull, i.e. the smoothed envelope around the pial surface created by
% freesurfer.
%
% Use as
%   mesh = ft_prepare_mesh(cfg)
%   mesh = ft_prepare_mesh(cfg, mri)
%   mesh = ft_prepare_mesh(cfg, seg)
% where the mri input argument is the result from FT_READ_MRI, FT_VOLUMEREALIGN or
% FT_VOLUMERESLICE and the seg input argument is from FT_VOLUMESEGMENT. If you
% specify an anatomical MRI, it will be segmented on the fly.
%
% The cfg argument is a structure that can contain:
%   cfg.method      = string, can be 'interactive', 'projectmesh', 'iso2mesh', 'isosurface',
%                     'headshape', 'hexahedral', 'tetrahedral', 'cortexhull' or 'fittemplate'
%   cfg.tissue      = cell-array with strings representing the tissue types, or numeric vector with integer values
%   cfg.numvertices = numeric vector, should have same number of elements as the number of tissues
%
% When providing an anatomical MRI or a segmentation, you should specify
%   cfg.downsample  = integer number (default = 1, i.e. no downsampling), see FT_VOLUMEDOWNSAMPLE
%   cfg.spmversion  = string, 'spm2', 'spm8', 'spm12' (default = 'spm12')
%
% For method 'headshape' you should specify
%   cfg.headshape   = a filename containing headshape, a Nx3 matrix with surface
%                     points, or a structure with a single or multiple boundaries
%
% For method 'cortexhull' you should not give input data, but specify
%   cfg.headshape   = string, filename containing the pial surface computed by freesurfer recon-all
%
% For method 'fittemplate' you should specify
%   cfg.headshape   = a filename containing headshape
%   cfg.template    = a filename containing headshape
% With this method you are fitting the headshape from the configuration to the template;
% the resulting affine transformation is applied to the input mesh (or set of meshes),
% which is subsequently returned as output variable.
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
%   cfg.outputfile  =  ...
% If you specify one of these (or both) the input data will be read from a *.mat
% file on disk and/or the output data will be written to a *.mat file. These mat
% files should contain only a single variable, corresponding with the
% input/output structure.
%
% Example
%   mri             = ft_read_mri('Subject01.mri');
%
%   cfg             = [];
%   cfg.output      = {'scalp', 'skull', 'brain'};
%   segmentation    = ft_volumesegment(cfg, mri);
%
%   cfg             = [];
%   cfg.tissue      = {'scalp', 'skull', 'brain'};
%   cfg.numvertices = [800, 1600, 2400];
%   mesh            = ft_prepare_mesh(cfg, segmentation);
%
%   cfg             = [];
%   cfg.method      = 'cortexhull';
%   cfg.headshape   = '/path/to/surf/lh.pial';
%   cfg.fshome      = '/path/to/freesurfer dir';
%   cortex_hull     = ft_prepare_mesh(cfg);
%
% See also FT_VOLUMESEGMENT, FT_PREPARE_HEADMODEL, FT_PLOT_MESH

% Undocumented functionality: at this moment it allows for either
%   mesh = ft_prepare_mesh(cfg)             or
%   mesh = ft_prepare_mesh(cfg, headmodel)
% but more consistent would be to specify a volume conduction model with
%   cfg.headmodel     = structure with volume conduction model, see FT_PREPARE_HEADMODEL
%   cfg.headshape     = name of file containing the volume conduction model, see FT_READ_HEADMODEL
%
% Undocumented options, I have no clue why they exist
%   cfg.method = {'singlesphere' 'concentricspheres' 'localspheres'}

% Copyrights (C) 2009-2012, Robert Oostenveld & Cristiano Micheli
% Copyrights (C) 2012-2013, Robert Oostenveld & Lilla Magyari
%
% 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$

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble debug
ft_preamble loadvar data
ft_preamble provenance data

% the ft_abort variable is set to true or false in ft_preamble_init
if ft_abort
  return
end

% we cannot use nargin, because the data might have been loaded from cfg.inputfile
hasdata = exist('data', 'var');

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'forbidden', {'numcompartments', 'outputfile', 'sourceunits', 'mriunits'});

% get the options
cfg.downsample  = ft_getopt(cfg, 'downsample', 1);            % default is no downsampling
cfg.numvertices = ft_getopt(cfg, 'numvertices', 3000, true);  % set the default, [] is also a meaningful value
cfg.smooth      = ft_getopt(cfg, 'smooth');                   % no default
cfg.spmversion  = ft_getopt(cfg, 'spmversion', 'spm12');

% Translate the input options in the appropriate default for cfg.method
if isfield(cfg, 'headshape') && ~isempty(cfg.headshape)
  cfg.method = ft_getopt(cfg, 'method', 'headshape');
elseif hasdata && ~strcmp(ft_headmodeltype(data), 'unknown')
  cfg.method = ft_getopt(cfg, 'method', ft_headmodeltype(data));
elseif hasdata
  cfg.method = ft_getopt(cfg, 'method', 'projectmesh');
else
  cfg.method = ft_getopt(cfg, 'method', []);
end

if hasdata && cfg.downsample~=1
  % optionally downsample the anatomical volume and/or tissue segmentations
  tmpcfg = keepfields(cfg, {'downsample', 'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
  data = ft_volumedownsample(tmpcfg, data);
  % restore the provenance information and put back cfg.smooth
  tmpsmooth = cfg.smooth;
  [cfg, data] = rollback_provenance(cfg, data);
  cfg.smooth = tmpsmooth;
end

switch cfg.method
  case 'interactive'
    % this makes sense with a non-segmented MRI as input
    % call the corresponding helper function
    mesh = prepare_mesh_manual(cfg, data);

  case {'projectmesh', 'iso2mesh', 'isosurface'}
    % this makes sense with a segmented MRI as input
    % call the corresponding helper function
    mesh = prepare_mesh_segmentation(cfg, data);

  case 'headshape'
    % call the corresponding helper function
    mesh = prepare_mesh_headshape(cfg);

  case 'hexahedral'
    % the MRI is assumed to contain a segmentation
    % call the corresponding helper function
    mesh = prepare_mesh_hexahedral(cfg, data);

  case 'tetrahedral'
    % the input data is assumed to contain a segmentation
    % call the corresponding helper function
    mesh = prepare_mesh_tetrahedral(cfg, data);

  case {'singlesphere' 'concentricspheres'}
    % the input data is assumed to contain a spherical head model
    data = ft_datatype_headmodel(data);   % ensure that it is consistent and up-to-date
    data = ft_determine_units(data);      % ensure that it has units

    if length(data.r)>1 && numel(cfg.numvertices)==1
      % use the same number of vertices for each tissue
      cfg.numvertices = repmat(cfg.numvertices, length(data.r));
    end

    mesh = [];
    for i=1:length(data.r)
      ft_info('triangulating sphere %d in the volume conductor\n', i);
      [pos, tri] = mesh_sphere(cfg.numvertices(i));
      mesh(i).pos(:,1) = pos(:,1)*data.r(i) + data.o(1);
      mesh(i).pos(:,2) = pos(:,2)*data.r(i) + data.o(2);
      mesh(i).pos(:,3) = pos(:,3)*data.r(i) + data.o(3);
      mesh(i).tri = tri;
    end

  case 'cortexhull'
    mesh = prepare_mesh_cortexhull(cfg);

  case 'fittemplate'
    M    = prepare_mesh_fittemplate(cfg.headshape.pos, cfg.template.pos);
    mesh = ft_transform_geometry(M, data);

  otherwise
    ft_error('unsupported cfg.method')
end

% copy the geometrical units from the input to the output
if ~isfield(mesh, 'unit') && hasdata && isfield(data, 'unit')
  for i=1:numel(mesh)
    mesh(i).unit = data.unit;
  end
elseif ~isfield(mesh, 'unit')
  mesh = ft_determine_units(mesh);
end

% copy the coordinate system from the input to the output
if ~isfield(mesh, 'coordsys') && hasdata && isfield(data, 'coordsys')
  for i=1:numel(mesh)
    mesh(i).coordsys = data.coordsys;
  end
end

% smooth the mesh
if ~isempty(cfg.smooth)
  tmpcfg = keepfields(cfg, {'smooth', 'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
  tmpcfg.numvertices = []; % the number of vertices should not be changed
  tmpcfg.headshape = mesh;
  mesh = prepare_mesh_headshape(tmpcfg);
end

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble previous   data
ft_postamble provenance mesh
ft_postamble history    mesh


function xyz_write_test ( file_out_name )

%*****************************************************************************80
%
%% XYZ_WRITE_TEST tests the XYZ write routines.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    01 January 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string FILE_OUT_NAME, the name of the output file.
%
  point_num = xyz_example_size ( );
%
%  Set the data.
%
  xyz = xyz_example ( point_num );
%
%  Write the data to the file.
%
  xyz_write ( file_out_name, point_num, xyz );

  return
end


function captureFigure( figh, filename, trim )
%captureFigure: use print to capture a figure with over-sampling
%
%   gpubench.captureFigure(figh,filename,trim)

%   Copyright 2011 The MathWorks, Inc.

if nargin<3
    trim = true;
end

% Have to hard-code the DPI since Windows doesn't report it correctly
% dpi = get(0,'ScreenPixelsPerInch');
%dpi = 192;
dpi = 160;

% Copy the position to the paper position to get the size right
pos = get( figh, 'Position' );
set( figh, 'PaperUnits', 'Points', 'PaperPosition', pos );

% Print the image to file at screen resolution
print( figh, '-zbuffer', sprintf('-r%d',round(0.5*dpi)), '-dpng', filename );

% Load and trim the top whitespace
gpubench.trimImage( filename, trim );


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

%%
clear; close all; clc;

%% Syntax
% |y=logit(x);|

%% 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 F = ismember(x,F)
% Internal class for constraint list

F = lmi(F);
F = ismember(x,F);


function netOutputs = fromCompiledNet(net)
%FROMCOMPILEDNET Decompiles a Net back into Layer objects
%   OUTPUTS = Layer.fromCompiledNet(NET) decompiles a compiled network (of
%   class Net), into their original Layer objects (i.e., a set of
%   recursively nested Layer objects).
%
%   Returns a cell array of Layer objects, each corresponding to an output
%   of the network. These can be composed with other layers, or compiled
%   into a Net object for training/evaluation.

% Copyright (C) 2017 Joao F. Henriques.
% All rights reserved.
%
% This file is part of the VLFeat library and is made available under
% the terms of the BSD license (see the COPYING file).

  % call a local function, to work around an occasional Matlab crash that
  % happens only for static methods
  netOutputs = fromCompiledNet_(net);
end

function netOutputs = fromCompiledNet_(net)
  % use local copies so that any changes won't reflect on the original Net
  forward = net.forward ;
  backward = net.backward ;

  % first undo ReLU short-circuiting, since it creates cycles in the graph
  [forward, backward] = undoShortCircuit(net, forward, backward);

  % main decompilation code.

  % create a cell array 'layers' that will contain all created Layers,
  % indexed by their output vars. e.g., if layer L outputs var V, then
  % layers{V} = L.
  assert(~isempty(net.vars)) ;
  layers = cell(size(net.vars)) ;

  % create Input layers
  inputNames = fieldnames(net.inputs) ;

  for k = 1:numel(inputNames)
    var = net.inputs.(inputNames{k}) ;  % the var index
    layers{var} = Input('name', inputNames{k}, 'gpu', net.isGpuVar(var)) ;
  end

  % create Param layers
  for k = 1:numel(net.params)
    p = net.params(k) ;

    layer = Param('name', p.name, 'value', net.vars{p.var}, ...
      'gpu', net.isGpuVar(p.var), 'learningRate', p.learningRate, ...
      'weightDecay', p.weightDecay) ;

    layer.trainMethod = layer.trainMethods{p.trainMethod} ;  % index to string
    layers{p.var} = layer ;
  end

  % create the layers in forward-order. this order is important, because
  % when processing a layer all its inputs must have been processed too.
  for k = 1:numel(forward)
    layer = forward(k) ;
    args = layer.args ;

    % replace vars in the args list with the corresponding Layer objects
    for i = 1:numel(layer.inputVars)
      assert(~isempty(layers{layer.inputVars(i)}));  % assume already created
      args{layer.inputArgPos(i)} = layers{layer.inputVars(i)} ;
    end

    % now create a Layer with those arguments
    obj = Layer(layer.func, args{:}) ;
    obj.name = layer.name ;

    % retrieve the number of input derivatives from the backward struct
    obj.numInputDer = backward(end - k + 1).numInputDer ;

    %retrieve precious value (set during overloaded construction)
    obj.precious = layer.precious;

    % store in the 'layers' cell array so further references to the same
    % var will fetch the same layer
    obj.name = layer.name ;
    layers{layer.outputVar(1)} = obj ;

    % if the layer has multiple outputs, create a Selector for each of the
    % outputs after the first one
    for i = 2:numel(layer.outputVar)
      layers{layer.outputVar(i)} = Selector(obj, i) ;
    end
  end

  % the last var is the root (skipping the corresponding derivative var)
  rootLayer = layers{end - 1};

  if ~isequal(rootLayer.func, @root)
    % single output
    netOutputs = {rootLayer} ;
  else
    % root layer's arguments are the network's outputs
    netOutputs = rootLayer.inputs ;
  end

  % copy meta properties to the Layers
  for o = 1:numel(netOutputs)
    netOutputs{o}.meta = net.meta ;
  end
end

function [forward, backward] = undoShortCircuit(net, forward, backward)
  % undo ReLU short-circuiting, since it creates cycles in the graph.
  % collect unused vars left behind by short-circuiting, to reuse them now.
  unused = true(size(net.vars)) ;
  unused([forward.inputVars]) = false ;
  unused([forward.outputVar]) = false ;
  unused(2:2:end) = false ;  % ignore derivative vars
  unused = find(unused) ;  % convert to list of var indexes

  next = 1 ;  % next unused var to take
  for k = 1:numel(forward)
    if isequal(forward(k).func, @vl_nnrelu) && ...
      forward(k).inputVars(1) == forward(k).outputVar

      % a short-circuited ReLU (output var = input var). change its output
      % to a new unused var, and update any layers that depend on it.
      oldVar = forward(k).outputVar ;
      for j = k + 1 : numel(forward)
        in = forward(j).inputVars ;
        if any(in == oldVar)  % update this dependent layer
          forward(j).inputVars(in == oldVar) = unused(next) ;
        end
      end

      forward(k).outputVar = unused(next) ;  % update the ReLU

      next = next + 1 ;
      % shouldn't happen if short-circ. ReLUs leave unused vars behind
      assert(next <= numel(unused) + 1) ;
    end
  end
end


function prev_rng = rcnn_seed_rand()
% seed_rand - Set random number generator to a fixed seed.
%   prev_rng = rcnn_seed_rand(seed)
%
%   Strategic use ensures that results are reproducible.
%
%   To restore the previous rng after calling this do:
%   rng(prev_rng);

% AUTORIGHTS
% ---------------------------------------------------------
% Copyright (c) 2014, Ross Girshick
%
% This file is part of the R-CNN code and is available
% under the terms of the Simplified BSD License provided in
% LICENSE. Please retain this notice and LICENSE if you use
% this file (or any portion of it) in your project.
% ---------------------------------------------------------

% This value works best for me.
seed = 3;
% Just kidding, of course ;-).

prev_rng = rng;
rng(seed, 'twister')


function checkHeader
%CHECKHEADER checks the header of the m-files of matGeom.
%
%   checkHeader()
%   Checks and corrects:
%   - the beginning of the first header line
%   - the "author" section is checked and corrected
%   - the "see also" section
%   Looks for:
%   - to-dos
%   Removes:
%   - the "history" section
%   Additional checks could be added.
%
%   Todo
%       - Standardize E-mail adress to "david.legland@inrae.fr"?
%       - Add checks for "Example" section.
%       - Add additional checks for the "See also" section: No
%       self-reference, references, indentations of the references.
%
%   See also
%       codingConventions
%

% ------
% Author: oqilipo
% E-mail: N/A
% Created: 2022-11-08, using MATLAB 9.13.0.2080170 (R2022b) Update 1
% Copyright 2022

cd(strrep(mfilename('fullpath'),mfilename,''))

mFiles = dir('../matGeom/**/*.m');
% Exclude the Contents.m files
mFiles(contains({mFiles.folder}','deprecated'))=[];

for f=1:length(mFiles)
    % Full path of the m-file
    mFile = fullfile(mFiles(f).folder, mFiles(f).name);
    % Read the content of the m-file
    S = readlines(mFile);
    % Make a backup of S
    S_BU = S;
    % File name of the m-file without the file extension
    mFileName = mFiles(f).name(1:end-2);
    % Length of the file name
    LoN = length(mFileName);

    % Assume that the header is invalid
    mFiles(f).validHeader = false;

    %% First header line
    % If the 1st or 2nd line of the file is empty the header is not valid
    if isempty(S{1}) || isempty(S{2})
        continue
    end

    % Check if the 1st header line starts with the capitalized m-file name
    if startsWith(S{1}, 'function')
        H1_Idx = 2;
    else
        H1_Idx = 1;
    end
    % Try to correct the beginning of the 1st header line
    if ~strcmp(S{H1_Idx}(1:2+LoN),['%' upper(mFileName) ' '])
        if startsWith(S{H1_Idx}, '% ') && regexp(S{H1_Idx}, '% ') == 1
            S{H1_Idx} = strrep(S{H1_Idx}, '% ', ['%' upper(mFileName) ' ']);
        end
    end

    if ~endsWith(S(H1_Idx), '.')
        S(H1_Idx) = S{H1_Idx} + ".";
    end

    %% AUTHOR section
    % First line of the header's author section
    % Find the 1st line of the header's author section
    aSec1Idx = find(contains(S,'-----'));
    if isempty(aSec1Idx)
        continue
    elseif length(aSec1Idx) ~= 1
        display(['No line contains or multiple lines contain: ''-----'' in: ' mFileName])
        continue
    end

    if ~strcmp(S(aSec1Idx),'% ------')
        % Remove more than six "-"
        S(aSec1Idx) = regexprep(S(aSec1Idx),'% *-----+','% ------');
    end

    if regexp(S(aSec1Idx+1), '^% *$') == 1
        S(aSec1Idx+1) = [];
    end

    % "Author" line
    % Fix the beginning of the author line
    if contains(S(aSec1Idx+1),'author') && ~contains(S(aSec1Idx+1),'Author')
        S(aSec1Idx+1) = regexprep(S(aSec1Idx+1),'% +author *:','% Author:');
        S(aSec1Idx+1) = regexprep(S(aSec1Idx+1),'% +authors *:','% Authors:');
    elseif contains(S(aSec1Idx+1),'  Author') && ~startsWith(S(aSec1Idx+1), '% Author')
        S(aSec1Idx+1) = regexprep(S(aSec1Idx+1),'% +','% ');
    end

    % "E-mail" line
    if ~contains(S(aSec1Idx+2),'mail','IgnoreCase',1)
        if contains(S(aSec1Idx+2),'created','IgnoreCase',1)
            if contains(S(aSec1Idx+1),'David Legland')
                S = [S(1:aSec1Idx+1); "% E-mail: david.legland@inrae.fr"; S(aSec1Idx+2:end)];
            else
                S = [S(1:aSec1Idx+1); "% E-mail: N/A"; S(aSec1Idx+2:end)];
            end
        elseif contains(S(aSec1Idx+3),'created','IgnoreCase',1)
            coIdx = regexp(S(aSec1Idx+2), 'INRA');
            if any(coIdx)
                % Extract the year of creation for the copyright
                creationYear = regexp(S(aSec1Idx+3), '20\d\d','match');
                if isempty(creationYear); continue; end
                if regexp(S(aSec1Idx+4), '^% *$') == 1
                        S(aSec1Idx+4) = regexprep(S(aSec1Idx+2),'% +INRA','% Copyright ' + creationYear + ' INRA');
                elseif isempty(S{aSec1Idx+4})
                    S(aSec1Idx+4) = "% Copyright " + creationYear + " " + S{aSec1Idx+2}(coIdx:end);
                    S = [S(1:aSec1Idx+4); ''; S(aSec1Idx+5:end)];
                else
                    continue
                end
                if contains(S(aSec1Idx+1),'David Legland')
                    S(aSec1Idx+2) = "% E-mail: david.legland@inrae.fr";
                else
                    S(aSec1Idx+2) = "% E-mail: N/A";
                end
            else
                continue
            end
        end
    end
    % Change e-mail to E-Mail
    S(aSec1Idx+2) = regexprep(S(aSec1Idx+2), '% e-mail:', '% E-mail:');

    % Move affiliation to the copyright line if necesarry
    if contains(S(aSec1Idx+3),'INRA') && contains(S(aSec1Idx+4),'created','IgnoreCase',1)
        coIdx = regexp(S(aSec1Idx+3), 'INRA');
        if contains(S(aSec1Idx+5), 'Copyright')
            S(aSec1Idx+5) = regexprep(S(aSec1Idx+5),'INRA.*',S{aSec1Idx+3}(coIdx:end));
            S(aSec1Idx+3) = [];
        elseif regexp(S(aSec1Idx+5), '^% *$') == 1
            creationYear = regexp(S(aSec1Idx+4), '20\d\d','match');
            if ~isempty(creationYear)
                S(aSec1Idx+5) = "% Copyright " + creationYear + " " + S{aSec1Idx+3}(coIdx:end);
                S(aSec1Idx+3) = [];
            else
                continue
            end
        elseif isempty(S{aSec1Idx+5})
            creationYear = regexp(S(aSec1Idx+4), '20\d\d','match');
            if ~isempty(creationYear)
                S(aSec1Idx+5) = "% Copyright " + creationYear + " " + S{aSec1Idx+3}(coIdx:end);
                S = [S(1:aSec1Idx+5); ''; S(aSec1Idx+6:end)];
                S(aSec1Idx+3) = [];
            else
                continue
            end
        end
    end

    % "Created" line
    if contains(S(aSec1Idx+3),'created the') && ~contains(S(aSec1Idx+3),'Created')
        S(aSec1Idx+3) = regexprep(S(aSec1Idx+3),'% +created the +','% Created: ');
    elseif contains(S(aSec1Idx+3),'created ')
        S(aSec1Idx+3) = regexprep(S(aSec1Idx+3),'% +created +','% Created: ');
    elseif contains(S(aSec1Idx+3),'  Created') && ~startsWith(S(aSec1Idx+3), '% Created')
        S(aSec1Idx+3) = regexprep(S(aSec1Idx+3),'% +','% ');
    elseif contains(S(aSec1Idx+3),' created:')
        S(aSec1Idx+3) = regexprep(S(aSec1Idx+3),'% +created:','% Created:');
    end

    % Standardize creation date
    dateIdxS = regexp(S(aSec1Idx+3),'% Created: ','end') + 1;
    if any(dateIdxS) && length(dateIdxS) == 1
        dateIdxE = regexp(S(aSec1Idx+3), '( by | from|, by |, from|, +using|\.$)') - 1;
        if isempty(dateIdxE)
            dateIdxE = length(S{aSec1Idx+3});
            if length(S{aSec1Idx+3}(dateIdxS:dateIdxE)) >= 10
                if regexp(S{aSec1Idx+3}(dateIdxS:dateIdxS+9),'\d\d\/\d\d\/\d{4}') == 1
                    dateStr = string(datetime(S{aSec1Idx+3}(dateIdxS:dateIdxE),...
                        'InputFormat','dd/MM/uuuu','format','uuuu-MM-dd'));
                else
                    dateStr = string(datetime(S{aSec1Idx+3}(dateIdxS:dateIdxE),'format','uuuu-MM-dd'));
                end
                S(aSec1Idx+3) = "% Created: " + dateStr;
            end
        else
            if length(dateIdxE)~=1; dateIdxE = dateIdxE(1); end
            if length(S{aSec1Idx+3}(dateIdxS:dateIdxE)) >= 10
                if regexp(S{aSec1Idx+3}(dateIdxS:dateIdxS+9),'\d\d\/\d\d\/\d{4}') == 1
                    dateStr = string(datetime(S{aSec1Idx+3}(dateIdxS:dateIdxE),...
                        'InputFormat','dd/MM/uuuu','format','uuuu-MM-dd'));
                else
                    dateStr = string(datetime(S{aSec1Idx+3}(dateIdxS:dateIdxE),'format','uuuu-MM-dd'));
                end
                S(aSec1Idx+3) = "% Created: " + dateStr + S{aSec1Idx+3}(dateIdxE+1:end);
            end
        end
    end

    % "Copyright" line
    % Extract the year of creation for the copyright
    creationYear = regexp(S(aSec1Idx+3), '20\d\d','match');
    if ~isempty(creationYear)
        creationYear = creationYear(1);
    else
        continue
    end
    if isempty(S{aSec1Idx+4})
        S = [S(1:aSec1Idx+3); "% Copyright " + creationYear; S(aSec1Idx+4:end)];
    elseif regexp(S(aSec1Idx+4), '^% *$') == 1
        S(aSec1Idx+4) = "% Copyright " + creationYear;
    end

    % Add current year to the copyright or change it to the current year
    copyrightSYear = regexp(S(aSec1Idx+4), '20\d\d','match');
    copyrightSYear = copyrightSYear{1};
    % Created year and copyright year should be the same
    if ~isequal(copyrightSYear,creationYear{1})
        display(['Creation and copyright year are inconsistent in: ' mFileName])
        continue
    end
    currentYear = char(datetime('today','Format','yyyy'));
    if regexp(S(aSec1Idx+4), '% Copyright 20\d\d( |$)') == 1
        if ~isequal(copyrightSYear, currentYear)
            S(aSec1Idx+4) = regexprep(S(aSec1Idx+4), '% Copyright 20\d\d', ...
                ['% Copyright ' copyrightSYear '-' currentYear]);
        end
    elseif regexp(S(aSec1Idx+4), '% Copyright 20\d\d-20\d\d( |$)') == 1
        copyrightEYear = S{aSec1Idx+4}(18:21);
        if ~isequal(copyrightEYear, currentYear)
            S(aSec1Idx+4) = regexprep(S(aSec1Idx+4), '% Copyright 20\d\d-20\d\d', ...
                ['% Copyright ' copyrightSYear '-' currentYear]);
        end
    else
        continue
    end

    % General checks
    containsHeaderWords = arrayfun(@(x,y) contains(x,y), ...
        S(aSec1Idx:aSec1Idx+4), ["% ------"; "Author"; "E-mail"; "Created"; "Copyright"]);
    if ~all(containsHeaderWords)
        continue
    end
    if any(contains(S(aSec1Idx:aSec1Idx+4), '%  '))
        % Remove leading spaces before the header words
        S(aSec1Idx:aSec1Idx+4) = arrayfun(@(x) regexprep(x,'% +','% '), S(aSec1Idx:aSec1Idx+4));
    end

    aSecLIs = [...
        startsWith(S(aSec1Idx-2), '%') ...
        isempty(S{aSec1Idx-1}) ...
        startsWith(S(aSec1Idx+1), '% Author') ...
        startsWith(S(aSec1Idx+2), '% E-mail: ') ...
        startsWith(S(aSec1Idx+3), '% Created: ')...
        startsWith(S(aSec1Idx+4), '% Copyright ')...
        isempty(S{aSec1Idx+5}) ...
        ];
    if all(aSecLIs)
        mFiles(f).validHeader = true;
    elseif all(aSecLIs == [1 0 1 1 1 1 1])
        S(aSec1Idx-1) = '';
    elseif all(aSecLIs == [0 0 1 1 1 1 1])
        if isempty(S{aSec1Idx-2})
            S(aSec1Idx-2) = '%';
            S(aSec1Idx-1) = '';
        end
    elseif all(aSecLIs == [1 0 1 1 1 1 0]) || all(aSecLIs == [1 1 1 1 1 1 0])
        if regexp(S(aSec1Idx+5), '^% *$') == 1
            S([aSec1Idx-1, aSec1Idx+5]) = '';
        end
    else
        continue
    end

    % No dot after creation date
    if regexp(S(aSec1Idx+3), '% Created: 20\d\d\-\d\d\-\d\d\.','start') == 1
        S(aSec1Idx+3) = regexprep(S(aSec1Idx+3),'\. *$','');
    end
    % Remove multiple spaces after creation date
    S(aSec1Idx+3) = regexprep(S(aSec1Idx+3),' +',' ');
    % If text follows the creation date seperate it by a comma
    if regexp(S(aSec1Idx+3), '% Created: 20\d\d\-\d\d\-\d\d\ .','start') == 1
        S(aSec1Idx+3) = [S{aSec1Idx+3}(1:21) ',' S{aSec1Idx+3}(22:end)];
    end
    % Remove dots at the end of the Created and Copyright line
    if endsWith(S(aSec1Idx+3), '.')
        S(aSec1Idx+3) = S{aSec1Idx+3}(1:end-1);
    end
    if endsWith(S(aSec1Idx+4), '.')
        S(aSec1Idx+4) = S{aSec1Idx+4}(1:end-1);
    end

    if aSec1Idx+6 < length(S)
        while isempty(S{aSec1Idx+6})
            S(aSec1Idx+6) = [];
        end
    end

    %% SEE ALSO section
    if ~isempty(cell2mat(regexp(lower(S), '^% *see also')))
        saSIdx = find(contains(lower(S),'see also'));
        if length(saSIdx) ~=1
            display(['Multiple ''See also'' lines found in: ' mFileName])
            continue
        end
        S(saSIdx) = regexprep(S(saSIdx), '^% *[sS]ee [aA]lso *:* *', '%   See also ');
    end

    %% HISTORY section
    if ~isempty(cell2mat(regexp(lower(S), '^% *history')))
        histSIdx = find(contains(lower(S),'history'));
        if length(histSIdx) ~=1
            display(['Multiple ''History'' sections found in: ' mFileName])
            continue
        end
        histLines = 1;
        while startsWith(S(histSIdx+histLines),'% ')
            histLines = histLines+1;
        end
        S(histSIdx:histSIdx+histLines-1) = [];
    end
    % Check for dates that appear after the header and may be part of a of a "history"
    if ~isempty(cell2mat(regexp(S(aSec1Idx+5:end), '^%.*20\d\d.')))
        display(['Suspicous date found in: ' mFileName])
    end

    %% TODO section
    % There should not be a to-do section. To-dos should be adressed using
    % GitHub Issues.
    if ~isempty(cell2mat(regexp(lower(S), '^%.*(todo|to-do)')))
        display(['''To-do(s)'' found in: ' mFileName])
    end

    %% Save file if changes were performed
    if ~isequal(S, S_BU)
        writelines(S, mFile);
    end
end

% Display remaining invalid files
mFileNames = {mFiles.name}';
validHeaders = {mFiles.validHeader}';
invalidFilesIdx = cellfun(@(x) ~isempty(x) && x==0, validHeaders);
invalidFiles = mFileNames(invalidFilesIdx);
NoIF = length(invalidFiles);
if isempty(invalidFiles)
    invalidFiles='none';
end
disp([num2str(NoIF) ' files with invalid header:'])
disp([num2cell(find(invalidFilesIdx)), invalidFiles])


function varargout = welcome(varargin)
clc;

disp('                     HELLO ;)');
disp('                     @)=--   ')
% WELCOME M-file for welcome.fig
%      WELCOME, by itself, creates a new WELCOME or raises the existing
%      singleton*.
%
%      H = WELCOME returns the handle to a new WELCOME or the handle to
%      the existing singleton*.
%
%      WELCOME('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in WELCOME.M with the given input arguments.
%
%      WELCOME('Property','Value',...) creates a new WELCOME or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before welcome_OpeningFunction gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to welcome_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help welcome

% Last Modified by GUIDE v2.5 23-Jan-2008 08:50:01

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @welcome_OpeningFcn, ...
                   'gui_OutputFcn',  @welcome_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before welcome is made visible.
function welcome_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to welcome (see VARARGIN)

% Choose default command line output for welcome
handles.output = hObject;

% printing the top text
t=clock;
if t(4)>1 && t(4)<=12
    temp = 1;
elseif t(4)>12 && t(4)<=15
    temp = 2;
else
    temp = 3;
end
switch temp
    case 1

        set(handles.text1,'string','GOOD MORNING. WELCOME TO THE WORLD OF MATLAB ');
        backgroundImage = importdata('good_morning.jpg');
        %select the axes
        axes(handles.axes1);
        %place image onto the axes
        image(backgroundImage);
        %remove the axis tick marks
        axis off

    case 2
        set(handles.text1,'string','GOOD AFTERNOON. WELCOME TO THE WORLD OF MATLAB ');
        backgroundImage = importdata('good_afternoon.jpg');
        %select the axes
        axes(handles.axes1);
        %place image onto the axes
        image(backgroundImage);
        %remove the axis tick marks
        axis off

    case 3
       set(handles.text1,'string','GOOD EVENING. WELCOME TO THE WORLD OF MATLAB ');
       backgroundImage = importdata('good_evening.jpg');
        %select the axes
        axes(handles.axes1);
        %place image onto the axes
        image(backgroundImage);
        %remove the axis tick marks
        axis off
end

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes welcome wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = welcome_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
close all;
disp('Have a nice Day :)');

% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
simulink
new_system('New','Model');
open_system('New');
close all;


% rgb.m: translates a colour from multiple formats into matlab colour format
% type 'rgb demo' to get started
%
% [matlabcolor]=rgb(col)
% matlab colors are in the format [R G B]
%
% if 'col' is a string, it is interpreted as
%
% 	[[modifier] descriptor] colour_name
%
% where
%		modifier is one of   (slightly, normal, very, extremely)
%		descriptor is one of (light/pale, normal, dark)
%		colorname is a name of a colour
%			(type 'rgb list' or 'rgb demo' to see them all)
%
% if 'col' is an integer between 0 and &HFFFFFF inclusive,
% it is interpreted as a double word RGB value in the form
% [0][R][G][B]
%
% if 'col' is a negative integer between -1 and -&HFFFFFF
% inclusive, it is interpreted as the complement of a double
% word RGB value in the form [0][B][G][R]
%
% if 'col' is a string of the form 'qbX' or 'qbXX' where X
% is a digit then the number part is interpreted as a qbasic
% color
%
% if 'col' is one of {k,w,r,g,b,y,m,c} a sensible result is
% returned
%
% if 'col' is already in matlab format, it is unchanged

%	VERSION:	06/06/2002
%	AUTHOR:		ben mitch
%	CONTACT:	footballpitch@theconnexion.zzn.com
%	WWW:		www.benmitch.co.uk\matlab (not yet)
%	LOCATION:	figures\colors\

function out=rgb(in)

if isa(in,'char') & length(in)>2 & length(in)<5 & strcmpi('qb',in(1:2))
	out=qbcolor(sscanf(in(3:end),'%i'));
elseif isa(in,'char') & length(in)==1
	out=translatecolorchar(in);
elseif isa(in,'char')
	if strcmp(in,'demo') rgb_demo; return; end
	if strcmp(in,'list') rgb_list; return; end
	out=translatecolorstring(in);
elseif isa(in,'double') & size(in,1)==1 & size(in,2)==1 & abs(in)<16777216
	out=translatecolorRGB(in);
elseif isa(in,'double') & size(in,1)==1 & size(in,2)==3
	out=in;
else
	warning('Unrecognised color format, black assumed');
	out=[0 0 0];
end

function out=translatecolorchar(in)
switch(in)
case 'k', out=[0 0 0];
case 'w', out=[1 1 1];
case 'r', out=[1 0 0];
case 'g', out=[0 1 0];
case 'b', out=[0 0 1];
case 'y', out=[1 1 0];
case 'm', out=[1 0 1];
case 'c', out=[0 1 1];
otherwise
	warning(['Unrecognised colour "' in '", black assumed'])
	out=[0 0 0];
	return;
end

function out=translatecolorstring(in)
args.tokens=rgb_parse(in);
args.N=length(args.tokens);
if args.N>3 warning('Too many words in color description, any more than 3 will be ignored'); end
while(args.N<3)
	args.tokens=[{'normal'};args.tokens];
	args.N=args.N+1;
end

cols=get_cols;
col=[];
for n=1:size(cols,1)
	names=cols{n,1};
	for m=1:length(names)
		if strcmp(args.tokens{3},names{m}) col=cols{n,2}; break; end
	end
	if ~isempty(col) break; end
end

if isempty(col)
	warning(['Unrecognised colour "' args.tokens{3} '", black assumed'])
	out=[0 0 0];
	return;
end

switch args.tokens{1}
case 'slightly', fac=0.75;
case 'normal', fac=0.5;
case 'very', fac=0.25;
case 'extremely', fac=0.125;
otherwise
	warning(['Unrecognised modifier "' args.tokens{1} '", normal assumed'])
	fac=0.5;
end

switch args.tokens{2}
case {'light','pale'}, out=1-(1-col)*fac;
case 'normal', out=col;
case 'dark', out=col*fac;
otherwise
	warning(['Unrecognised descriptor "' args.tokens{2} '", normal assumed'])
	out=col;
end

function out=translatecolorRGB(in)

BGR=0;
if in<0
	in=-in;
	BGR=1;
end

b=bytes4(in);
if BGR out=b(4:-1:2); else out=b(2:4); end

function out=qbcolor(in)

% rgb value from basic colour code
% 0-7 are normal, 8-15 are bright
% 0 - black
% 1 - red,  2 - green,   3 - blue
% 4 - cyan, 5 - magenta, 6 - yellow
% 7 - white

bright=0.5;
if in>7 in=in-8; bright=1; end

switch in
case 0, rgb=[0 0 0];
case 1, rgb=[1 0 0];
case 2, rgb=[0 1 0];
case 3, rgb=[0 0 1];
case 4, rgb=[0 1 1];
case 5, rgb=[1 0 1];
case 6, rgb=[1 1 0];
case 7, rgb=[1 1 1];
otherwise
	warning('Unrecognised QBasic color, black assumed');
	out=[0 0 0];
	return;
end

out=rgb*bright;

function tokens=rgb_parse(str)

% parse string to obtain all tokens
% quoted strings count as single tokens

inquotes=0;
intoken=0;
pos=1;
l=length(str);
st=0;
ed=0;
token='';
tab=char(9);
tokens=cell(0);
while(pos<=l)
	ch=str(pos);
	if inquotes
		if ch=='"'
			inquotes=0;
			tokens={tokens{:} token};
		else
			token=[token ch];
		end
	elseif intoken
		if ch==' ' | ch==tab
			intoken=0;
			tokens={tokens{:} token};
		elseif ch=='"'
			error(['Quote misplace in <' str '>']);
		else
			token=[token ch];
		end
	else
		if ch==' ' | ch==tab
			% do nothing
		elseif ch=='"'
			token='';
			inquotes=1;
		else
			token=ch;
			intoken=1;
		end
	end
	pos=pos+1;
end

if intoken tokens={tokens{:} token}; end
if inquotes error(['Unpaired quotes in <' str '>']); end

tokens=tokens';

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DEMO
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function rgb_demo

figure(1)
clf
cols = get_cols;
cols = {cols{:,1}}';
cols = { cols{:}, ...
	'k', ...
	'r', ...
	'g', ...
	'b', ...
	'y', ...
	'm', ...
	'c', ...
	'w', ...
	'', ...
	'extremely dark green', ...
	'very dark green', ...
	'dark green', ...
	'slightly dark green', ...
	'green', ...
	'slightly pale green', ...
	'pale green', ...
	'very pale green', ...
	'extremely pale green', ...
};

height=9;
x=0;
y=0;
for n=1:length(cols)
	rect(x,y,cols{n})
	y=y+1;
	if y==height
		x=x+2;
		y=0;
	end
end
if y==0 x=x-2; end
axis([0 (x+2) 0 height])
title('names on different rows are alternates')

function rect(x,y,col)
if isempty(col) return; end
r=rectangle('position',[x+0.1 y+0.1 1.8 0.8]);
col_=col;
if iscell(col) col=col{1}; end
colrgb=rgb(col);
if strcmp(col(1),'u') & length(col)==2
	t=text(x+1,y+0.5,{'unnamed',['colour (' col(2) ')']});
	set(r,'facecolor',colrgb);
else
	t=text(x+1,y+0.5,col_);
	set(r,'facecolor',colrgb);
	if sum(colrgb)<1.5 set(t,'color',[1 1 1]); end
end
set(t,'horizontalalignment','center')
set(t,'fontsize',10)

function rgb_list
cols=get_cols;
disp(' ')
for n=1:size(cols,1)
	code=cols{n,2};
	str=cols{n,1};
	str_=[];
	for m=1:length(str)
		str_=[str_ str{m} ', '];
	end
	str_=str_(1:end-2);
	if strcmp(str_(1),'u') & length(str_)==2
		str_=['* (' str_(2) ')'];
	end
	disp(['  [' sprintf('%.1f  %.1f  %.1f',code) '] - ' str_])
end
disp([10 '* colours marked thus are not named - if you know their' 10 '  designation, or if you feel sure a colour is mis-named,' 10 '  email me (address via help) or comment at' 10 '  www.mathworks.com/matlabcentral - "rgb demo" to see them' 10])

function cols=get_cols

cols={
	'black', [0 0 0]; ...
	'navy', [0 0 0.5]; ...
	'blue', [0 0 1]; ...
	'u1', [0 0.5 0]; ...
	{'teal','turquoise'}, [0 0.5 0.5]; ...
	'slateblue', [0 0.5 1]; ...
	{'green','lime'}, [0 1 0]; ...
	'springgreen', [0 1 0.5]; ...
	{'cyan','aqua'}, [0 1 1]; ...
	'maroon', [0.5 0 0]; ...
	'purple', [0.5 0 0.5]; ...
	'u2', [0.5 0 1]; ...
	'olive', [0.5 0.5 0]; ...
	{'gray','grey'}, [0.5 0.5 0.5]; ...
	'u3', [0.5 0.5 1]; ...
	{'mediumspringgreen','chartreuse'}, [0.5 1 0]; ...
	'u4', [0.5 1 0.5]; ...
	'sky', [0.5 1 1]; ...
	'red', [1 0 0]; ...
	'u5', [1 0 0.5]; ...
	{'magenta','fuchsia'}, [1 0 1]; ...
	'orange', [1 0.5 0]; ...
	'u6', [1 0.5 0.5]; ...
	'u7', [1 0.5 1]; ...
	'yellow', [1 1 0]; ...
	'u8', [1 1 0.5]; ...
	'white', [1 1 1]; ...
	};

for n=1:size(cols,1)
	if ~iscell(cols{n,1}) cols{n,1}={cols{n,1}}; end
end

% converts a DWORD into a four byte row vector
function out=bytes4(in)

out=[0 0 0 0];
if in<0 | in>(2^32-1)
	warning('DWORD out of range, zero assumed');
	return;
end

N=4;
while(in>0)
	out(N)=mod(in,256);
	in=(in-out(N))/256;
	N=N-1;
end


clear;clc;
util;
VAEdata = load([input_folder, filesep, data_filename]);% load the generated data

tic
dataset = {};
for i = 1:length(VAEdata.boxes)
    data.leafreps = VAEdata.boxes{i}';
    data.relposreps = VAEdata.rplist{i}';
    data.kids = VAEdata.kids{i};
    [ ndata ] = convertPytorchData( data );
    ndata = adjustReconOffset( ndata );%adjust the one-hot vectors
    dataset{length(dataset)+1} = ndata;
end

rdataset = {};
for i = 1:length(dataset)
    fprintf([num2str(i),'\n']);
    p_data = dataset{i};

    % adjust the relpos between floor and wallnodes
    rplist = p_data.relposreps{length(p_data.relposreps)};
    rplist(1,:) = [-1,0.5,0.5,0.5];
    rplist(24:end,1:4) = 0;
    rplist(25,1) = 1;
    rplist(28,2:end) = 1;
    p_data.relposreps{length(p_data.relposreps)} = rplist;
	try
        [ rdata ] = reconOffset2Scene( p_data, 7, 6 , i, labelset_filename, objperlabel_filename, objfolder_path);
        [ rdata ] = optimize3dScene( rdata ); % generate 3D scenes from 2D

        % plot and save the topviews
        plotRoom2(rdata.obblist, rdata.labellist, 0);
        set(gcf,'position',[100 100 900 900])
        saveas(gcf, [output_img_folder, filesep,num2str(i),'.jpg']);
        close gcf;
catch
end
    % save the object meshes in the scenes
    % scene_folder = [output_obj_folder, filesep, 'scene-', num2str(i)];
    % mkdir(scene_folder);
    % recon3dscene( rdata, scene_folder, 7, objfolder_path);
    rdataset{i} = rdata;
end
toc


function hdr = makeAnalyzeHeader(datatype, fname)
%
% hdr = makeAnalyzeHeader(datatype, fname)
%
% makes an Analyze-format header struct with many default values pre-loaded.
%
%
%

if(~exist('datatype','var') | isempty(datatype))
    datatype = 4;
end
if(~exist('fname','var') | isempty(fname))
    fname = 'unknown';
end

% compute intensity range & bits per pix from datatype
%
glmin = 0;
switch(datatype)
case 1,
    bitpix = 1;
    glmax = 1;
case 2,
    bitpix = 8;
    glmax = 255;
case 4,
    bitpix = 16;
    glmax = 32767;
case 8,
    bitpix = 32;
    glmax = (2^31-1);
case 16,
    bitpix = 32;
    glmax = 1;
case 64,
    bitpix = 64;
    glmax = 1;
otherwise,
    error(['Unknown datatype ',num2str(datatype),'!']);
end

hdr.data_type = fixLen('dsr', 10);
hdr.db_name = fixLen(fname,18);
hdr.extents = 16384; % Should be 16384, the image file is created as contiguous with a minimum
hdr.session_error = 0;
hdr.regular = 'r';   % Must be `r' to indicate that all images and volumes are the same size.
hdr.hkey_un0 = 0;

% write (struct) image_dimension
%
hdr.dim = fixLen(dim,8);
hdr.vox_units = fixLen('mm',4);
hdr.cal_units = fixLen(' ',8);
hdr.unused1 = fixLen(0,1);
hdr.datatype = fixLen(datatype,1);
hdr.bitpix = fixLen(bitpix,1);
hdr.dim_un0 = fixLen(0,1);
hdr.pixdim = fixLen(pixdim,8);
hdr.vox_offset = fixLen(vox_offset,1);
hdr.funused1 = fixLen(funused1,1);
hdr.funused2 = fixLen(funused2,1);
hdr.funused3 = fixLen(funused3,1);
hdr.cal_max = fixLen(cal_max,1);
hdr.cal_min = fixLen(cal_min,1);
hdr.compressed = fixLen(compressed,1);
hdr.verified = fixLen(verified,1);
hdr.glmax = fixLen(glmax,1);
hdr.glmin = fixLen(glmin,1);

% write (struct) data_history
%---------------------------------------------------------------------------
hdr.descrip = fixLen(descrip,80),	'char');
hdr.aux_file = fixLen(aux_file,24), 'char');
% valid values for orient:
% 0 transverse unflipped, 1 coronal unflipped, 2 sagittal unflipped,
% 3 transverse flipped, 4 coronal flipped, 5 sagittal flipped
hdr.orient = fixLen(orient,1), 'char');
hdr.origin = fixLen(origin,5), 'int16');
hdr.generated = fixLen(generated,10), 'uchar');
hdr.scannum = fixLen(scannum,10), 'uchar');
hdr.patient_id = fixLen(patient_id,10), 'uchar');
hdr.exp_date = fixLen(exp_date,10), 'uchar');
hdr.exp_time = fixLen(exp_time,10), 'uchar');
hdr.hist_un0 = fixLen(hist_un0,3), 'uchar');
hdr.views = fixLen(views,1), 'int32');
hdr.vols_added = fixLen(vols_added,1), 'int32');
hdr.start_field = fixLen(start_field,1), 'int32');
hdr.field_skip = fixLen(field_skip,1), 'int32');
hdr.omax = fixLen(omax,1), 'int32');
hdr.omin = fixLen(omin,1), 'int32');
hdr.smax = fixLen(smax,1), 'int32');
hdr.smin = fixLen(smin,1), 'int32');

numOut = ftell(fid);
fclose(fid);
return;

function m = fixLen(m, len)
m = m(:)';
if(length(m) > len)
    m = m(1:len);
elseif(length(m) < len)
    if(ischar(m))
        m = [m char(zeros(1,len-length(m)))];
    else
        m = [m zeros(1,len-length(m))];
    end
end
return


% Author : FUAT COGUN
% Date   : 16.07.2009
%
%
% Gets the video information of the specified video file.
%
%
% Inputs  : -Name of the video file                             (String)
% ======
%
% Outputs : -Number of frames in video file                     (Integer)
% =======   -Frames per Second                                  (Integer)
%           -Width of the video                                 (Integer)
%           -Height of the video                                (Integer)
%           -Width-to-Height ratio                              (Double)

function [numOfFrames fps videoWidth videoHeight ratio] = getVideoInfo(videoFile)

    info = aviinfo(videoFile);
    numOfFrames = info.NumFrames;
    fps = info.FramesPerSecond;
    videoWidth = info.Width;
    videoHeight = info.Height;
    ratio = videoWidth/videoHeight;