function obj = spm2canlab_dataset(obj, subject, spm)
% Extract Event_Level data from subjects' SPM.mat files to add data to
% canlab_dataset object.
%
% :Usage:
% ::
%
%    obj = spm2canlab_dataset(obj, subject, spm)
%
%
% ..
%     Author and copyright information:
%
%     Copyright (C) 2015  Wani Woo
%
%     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/>.
% ..
%
%
% :Inputs:
%
%   **obj:**
%        Canlab_dataset object (see canlab_dataset)
%
%   **subject:**
%        Subject list (it could be one subject [in a string
%        format], or it could be multiple subjects in cell array)
%
%   **spm:**
%        This could be loaded SPM (struct), or one path for one
%        subject's SPM.mat file (string), or multiple loaded SPM or
%        paths in cell array
%
% :Outputs:
%
%   **obj:**
%        Canlab_dataset object with new data
%
%
% :Examples:
% ::
%
%    subj = {'dpsp002','dpsp003'};
%    spm = {'dpsp002_SPM.mat', 'dpsp003_SPM.mat'};
%
%    D = canlab_dataset; % if D doesn't exist yet
%    D = spm2canlab_dataset(D, subj, spm);
%
%
% :See also:
%   canlab_dataset
%   spm_mat2batchinput
%

% ..
%    Programmers' notes:
%       After running this, please check D.Subj_Level.data and
%       D.Event_level.data to see if there are NaNs. NaNs could be there when
%       information cannot be extracted from the given SPM.mat files.
% ..

subj = parseSUBJ(subject); % Check 1: parsing subjects

% Check 2: parsing SPM input
SPM = parseSPM(spm);

% Adding data to the canlab_dataset obj
for subj_i = 1:numel(subj)

    % check if the subject exists in obj
    [isexist_sub, wh_subj] = exist_data(obj.Subj_Level.id, subj{subj_i});

    % if the subject is new, add the subject to obj.Subj_Level
    if ~isexist_sub

        obj.Subj_Level.id{wh_subj} = subj{subj_i};

        if ~isempty(obj.Subj_Level.names)

            str = ['D.Subj_Level.data for subject ' subj{subj_i} ' are now NaNs. Please enter the data.'];
            warning(str);

            obj.Subj_Level.data(wh_subj,:) = NaN(1,size(obj.Subj_Level.data,2));

        end
    end

    % get information from SPM
    out = spm2canlab_dataset_format(SPM{subj_i});
    names = out.names;

    for fields_i = 1:numel(names)

        % check the same information exists already
        [isexist_data, wh_col] = exist_data(obj.Event_Level.names, names{fields_i});

        % if the info is new, the existing subjects data for that column should be NaNs.
        if ~isexist_data && numel(obj.Subj_Level.id) ~= 1
            for i = 1:numel(obj.Event_Level.data)
                obj.Event_Level.data{i}(:,wh_col) = NaN(size(obj.Event_Level.data{i},1),1);
            end
            warning('For existing subjects, please check NaNs in D.Event_Level.data.');
        end

        % add the data
        obj.Event_Level.names{wh_col} = names{fields_i};
        obj.Event_Level.type{wh_col} = out.type{fields_i};
        obj.Event_Level.descrip{wh_col} = out.descrip{fields_i};
        obj.Event_Level.data{wh_subj}(:,wh_col) = out.data(:,fields_i);

        wh_cols(fields_i) = wh_col;

    end

    % if the subject is new and there were existing data, the data that the
    % new subject doesn't have should be NaNs
    if ~isexist_sub
        wh_old = ~ismember(1:size(obj.Event_Level.data{wh_subj},2),wh_cols);
        if any(wh_old)
            obj.Event_Level.data{wh_subj}(:,wh_old) = ...
                NaN(size(obj.Event_Level.data{wh_subj}(:,wh_old)));
            warning('For new subjects, please check NaNs in D.Event_Level.data.');
        end
    end

end

end

% ============ SUB-FUNCTIONS ============

function subj = parseSUBJ(subject)

if ischar(subject)
    subj{1} = subject;
else
    subj = subject;
end

end

function SPM = parseSPM(spm)

if ischar(spm)
    temp = load(spm);
    SPM{1} = temp.SPM;
else
    if iscell(spm)
        for i = 1:numel(spm)
            if ischar(spm{i})
                temp = load(spm{i});
                SPM{i} = temp.SPM;
            elseif isstruct(spm{i})
                SPM{i} = spm{i};
            else
                error('SPM is unknown format.');
            end
        end
    elseif isstruct(spm)
        SPM{1} = spm;
    else
        error('SPM is unknown format.');
    end
end

end

function [isexist, wh] = exist_data(obj_field, field)

isexist = any(strcmp(obj_field, field));

if isexist
    wh = find(strcmp(obj_field, field));
else
    wh = numel(obj_field) + 1;
end

end

% ---- MAJOR SUBFUNCTION ----

function out = spm2canlab_dataset_format(SPM)

% Extract Event_Level data from one subject's SPM.mat file to enter data to
% canlab_dataset object. This function is called by "spm2canlab_dataset".
%
% Usage:
% -------------------------------------------------------------------------
% out = spm2canlab_dataset_format(SPM)
%
% Inputs:
% -------------------------------------------------------------------------
% SPM            SPM saved in SPM.mat of the model directory.
%
% Outputs:
% -------------------------------------------------------------------------
% out.names      Event_Level names in cell array
%                (RunNumber, EventName, Onsets, Durations)
% out.descrip    Event_Level descript in cell array
% out.type       Event_Level variable types of data
% out.data       Event_Level data
%
% See also spm2canlab_dataset, canlab_dataset, spm_mat2batchinput
%
% Examples:
% -------------------------------------------------------------------------
% load SPM.mat;
% out = spm2dataset(SPM);
%
% % output:
% %   names: {'RunNumber'  'EventNames'  'Onsets'  'Durations'}
% % descrip: {'Run 1-8'  {12x1 cell}  'Onsets'  'Duration'}
% %    type: {'Categorical'  'Categorical'  'Continuous'  'Continuous'}
% %    data: [192x4 double]
%
% -------------------------------------------------------------------------
% Copyright (C) 2015  Wani Woo

% Programmers' notes:

% Parsing SPM to know the total number of Event types

[~, ~, ~, names] = spm_mat2batchinput(SPM);

% 1. Event_Level variable names
out.names = {'RunNumber','EventNames','Onsets','Durations'};

% 2. Event_Level descript
out.descrip{1} = ['Run 1-' num2str(numel(SPM.Sess))];
for i = 1:numel(unique(names))
    out.descrip{2}{i,1} = [num2str(i) ': ' deblank(names{i})];
end
out.descrip{3} = 'Onsets';
out.descrip{4} = 'Duration';

% 3. Event_Level variable type
out.type{1} = 'Categorical';
out.type{2} = 'Categorical';
out.type{3} = 'Continuous';
out.type{4} = 'Continuous';

% 4. Event_Level variable type
out.data = [];
for run_i = 1:numel(SPM.Sess)

    row_i = 0;
    for eventtype_i = 1:numel(SPM.Sess(run_i).U)

        EventName = find(strcmp(unique(names), SPM.Sess(run_i).U(eventtype_i).name));

        for event_i = 1:numel(SPM.Sess(run_i).U(eventtype_i).ons)

            row_i = row_i+1;
            Durations = SPM.Sess(run_i).U(eventtype_i).dur(event_i);
            Onsets = SPM.Sess(run_i).U(eventtype_i).ons(event_i);
            Ddata_run(row_i,:) = [run_i EventName Onsets Durations];

        end
    end

    % sorting events using onset information
    [~, idx] = sort(Ddata_run(:,3));
    out.data = [out.data; Ddata_run(idx,:)];

end

end


function Rx = getPrescribedDose(planNum,planC)
% Get prescribed dose (Gy) for selected plan
%
%AI 07/09/21

indexS = planC{end};

%Get referenced beam SOPInstanceUID
DCMheaderS = planC{indexS.dose}(planNum).DICOMHeaders;
ReferencedSOPInstanceUID = DCMheaderS.ReferencedRTPlanSequence.Item_1.ReferencedSOPInstanceUID;

%Identify corresponding beamNum
SOPInstanceUIDv = {planC{indexS.beams}.SOPInstanceUID};
beamNum = strcmpi(ReferencedSOPInstanceUID,SOPInstanceUIDv);

%Get prescribed dose
Rx = planC{indexS.beams}(beamNum).DoseReferenceSequence.Item_1.DeliveryMaximumDose;

end


function ft_plot_layout(layout, varargin)

% FT_PLOT_LAYOUT plots a two-dimensional channel layout
%
% Use as
%   ft_plot_layout(layout, ...)
% where the layout is a FieldTrip structure obtained from FT_PREPARE_LAYOUT.
%
% Additional options should be specified in key-value pairs and can be
%   'chanindx'    = list of channels to plot (default is all)
%   'point'       = yes/no
%   'box'         = yes/no
%   'label'       = yes/no
%   'labeloffset' = offset of label from point (default = 0)
%   'labelrotate' = scalar, vector with rotation angle (in degrees) per label (default = 0)
%   'labelalignh' = string, or cell-array specifying the horizontal alignment of the text (default = 'center')
%   'labelalignv' = string, or cell-array specifying the vertical alignment of the text (default = 'middle')
%   'mask'        = yes/no
%   'outline'     = yes/no
%   'verbose'     = yes/no
%   'pointsymbol' = string with symbol (e.g. 'o') - all three point options need to be used together
%   'pointcolor'  = string with color (e.g. 'k')
%   'pointsize'   = number indicating size (e.g. 8)
%   'fontcolor'   = string, color specification (default = 'k')
%   'fontsize'    = number, sets the size of the text (default = 10)
%   'fontunits'   =
%   'fontname'    =
%   'fontweight'  =
%
% It is possible to plot the object in a local pseudo-axis (c.f. subplot), which is specfied as follows
%   'hpos'        = horizontal position of the lower left corner of the local axes
%   'vpos'        = vertical position of the lower left corner of the local axes
%   'width'       = width of the local axes
%   'height'      = height of the local axes
%
% See also FT_PREPARE_LAYOUT, FT_PLOT_TOPO

% Copyright (C) 2009, Robert Oostenveld
%
% 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$

ws = warning('on', 'MATLAB:divideByZero');

% get the optional input arguments
chanindx     = ft_getopt(varargin, 'chanindx',     []);
hpos         = ft_getopt(varargin, 'hpos',         0);
vpos         = ft_getopt(varargin, 'vpos',         0);
width        = ft_getopt(varargin, 'width',        []);
height       = ft_getopt(varargin, 'height',       []);
point        = ft_getopt(varargin, 'point',        true);
box          = ft_getopt(varargin, 'box',          true);
label        = ft_getopt(varargin, 'label',        true);
labeloffset  = ft_getopt(varargin, 'labeloffset',  0);
labelxoffset = ft_getopt(varargin, 'labelxoffset', labeloffset);
labelyoffset = ft_getopt(varargin, 'labelyoffset', labeloffset*1.5);
mask         = ft_getopt(varargin, 'mask',         true);
outline      = ft_getopt(varargin, 'outline',      true);
verbose      = ft_getopt(varargin, 'verbose',      false);
pointsymbol  = ft_getopt(varargin, 'pointsymbol');
pointcolor   = ft_getopt(varargin, 'pointcolor');
pointsize    = ft_getopt(varargin, 'pointsize');

% these have to do with the font
fontcolor   = ft_getopt(varargin, 'fontcolor', 'k'); % default is black
fontsize    = ft_getopt(varargin, 'fontsize',   get(0, 'defaulttextfontsize'));
fontname    = ft_getopt(varargin, 'fontname',   get(0, 'defaulttextfontname'));
fontweight  = ft_getopt(varargin, 'fontweight', get(0, 'defaulttextfontweight'));
fontunits   = ft_getopt(varargin, 'fontunits',  get(0, 'defaulttextfontunits'));
% these have to do with the font
interpreter  = ft_getopt(varargin, 'interpreter', 'tex');

% some stuff related to some refined label plotting
labelrotate   = ft_getopt(varargin, 'labelrotate',  0);
labelalignh   = ft_getopt(varargin, 'labelalignh',  'center');
labelalignv   = ft_getopt(varargin, 'labelalignv',  'middle');
labelcolor    = ft_getopt(varargin, 'labelcolor', 'k');

% convert between true/false/yes/no etc. statements
point   = istrue(point);
box     = istrue(box);
label   = istrue(label);
mask    = istrue(mask);
outline = istrue(outline);
verbose = istrue(verbose);

% color management
if ischar(pointcolor) && exist([pointcolor '.m'], 'file')
  pointcolor = eval(pointcolor);
end

if ~(point || box || label || mask || outline)
  % there is nothing to be plotted
  return;
end

% everything is added to the current figure
holdflag = ishold;
if ~holdflag
  hold on
end

% make a selection of the channels
if ~isempty(chanindx)
  layout.pos    = layout.pos(chanindx,:);
  layout.width  = layout.width(chanindx);
  layout.height = layout.height(chanindx);
  layout.label  = layout.label(chanindx);
end

% the units can be arbitrary (e.g. relative or pixels), so we need to compute the right scaling factor and offset
% create a matrix with all coordinates from positions, mask, and outline
allCoords = layout.pos;
if isfield(layout, 'mask') && ~isempty(layout.mask)
  for k = 1:numel(layout.mask)
    allCoords = [allCoords; layout.mask{k}];
  end
end
if isfield(layout, 'outline') &&~isempty(layout.outline)
  for k = 1:numel(layout.outline)
    allCoords = [allCoords; layout.outline{k}];
  end
end

naturalWidth = (max(allCoords(:,1))-min(allCoords(:,1)));
naturalHeight = (max(allCoords(:,2))-min(allCoords(:,2)));

if isempty(width) && isempty(height)
  xScaling = 1;
  yScaling = 1;
elseif isempty(width) && ~isempty(height)
  % height specified, auto-compute width while maintaining aspect ratio
  yScaling = height/naturalHeight;
  xScaling = yScaling;
elseif ~isempty(width) && isempty(height)
  % width specified, auto-compute height while maintaining aspect ratio
  xScaling = width/naturalWidth;
  yScaling = xScaling;
else
  % both width and height specified
  xScaling = width/naturalWidth;
  yScaling = height/naturalHeight;
end

X      = layout.pos(:,1)*xScaling + hpos;
Y      = layout.pos(:,2)*yScaling + vpos;
Width  = layout.width*xScaling;
Height = layout.height*yScaling;
Lbl    = layout.label;

if point
  if ~isempty(pointsymbol) && ~isempty(pointcolor) && ~isempty(pointsize) % if they're all non-empty, don't use the default
    plot(X, Y, 'marker', pointsymbol, 'color', pointcolor, 'markersize', pointsize, 'linestyle', 'none');
  else
    plot(X, Y, 'marker', '.', 'color', 'b', 'linestyle', 'none');
    plot(X, Y, 'marker', 'o', 'color', 'y', 'linestyle', 'none');
  end
end

if label
  % the MATLAB text function fails if the position for the string is specified in single precision
  X = double(X);
  Y = double(Y);

  % check whether fancy label plotting is needed, this requires a for loop,
  % otherwise print text in a single shot
  if numel(labelrotate)==1
    text(X+labelxoffset, Y+labelyoffset, Lbl , 'interpreter', interpreter, 'horizontalalignment', labelalignh, 'verticalalignment', labelalignv, 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight);
  else
    n = numel(Lbl);
    if ~iscell(labelalignh)
      labelalignh = repmat({labelalignh},[n 1]);
    end
    if ~iscell(labelalignv)
      labelalignv = repmat({labelalignv},[n 1]);
    end
    if numel(Lbl)~=numel(labelrotate)||numel(Lbl)~=numel(labelalignh)||numel(Lbl)~=numel(labelalignv)
      error('there is something wrong with the input arguments');
    end
    for k = 1:numel(Lbl)
      h = text(X(k)+labelxoffset, Y(k)+labelyoffset, Lbl{k}, 'interpreter', interpreter, 'horizontalalignment', labelalignh{k}, 'verticalalignment', labelalignv{k}, 'rotation', labelrotate(k), 'color', fontcolor, 'fontunits', fontunits, 'fontsize', fontsize, 'fontname', fontname, 'fontweight', fontweight);
    end
  end
end

if box
  line([X-Width/2 X+Width/2 X+Width/2 X-Width/2 X-Width/2]',[Y-Height/2 Y-Height/2 Y+Height/2 Y+Height/2 Y-Height/2]', 'color', [0 0 0]);
end

if outline && isfield(layout, 'outline')
  if verbose
    fprintf('solid lines indicate the outline, e.g. head shape or sulci\n');
  end
  for i=1:length(layout.outline)
    if ~isempty(layout.outline{i})
      X = layout.outline{i}(:,1)*xScaling + hpos;
      Y = layout.outline{i}(:,2)*yScaling + vpos;
      h = line(X, Y);
      set(h, 'color', 'k');
      set(h, 'linewidth', 2);
    end
  end
end

if mask && isfield(layout, 'mask')
  if verbose
    fprintf('dashed lines indicate the mask for topograpic interpolation\n');
  end
  for i=1:length(layout.mask)
    if ~isempty(layout.mask{i})
      X = layout.mask{i}(:,1)*xScaling + hpos;
      Y = layout.mask{i}(:,2)*yScaling + vpos;
      % the polygon representing the mask should be closed
      X(end+1) = X(1);
      Y(end+1) = Y(1);
      h = line(X, Y);
      set(h, 'color', 'k');
      set(h, 'linewidth', 1.5);
      set(h, 'linestyle', ':');
    end
  end
end

axis auto
axis equal
axis off

if ~holdflag
  hold off
end

warning(ws); %revert to original state


function this = realign(this)
% Realigns all 3D images in 4D data to each other, then to the mean
% Uses SPM's realign: estimate+rewrite functionality
%
%   MrSeries = realign(MrSeries)
%
% This is a method of class MrSeries.
%
% IN
%   MrImage.data
%   MrImage.parameters.realign.quality
%
% OUT
%
% EXAMPLE
%   realign
%
%   See also MrSeries MrImage MrImage.realign

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

quality = this.parameters.realign.quality;

this.init_processing_step('realign');
this.data = this.data.realign('quality', quality);
this.finish_processing_step('realign', this.data);


function batch_ds_info=my_get_batch_ds_info(...
    opts, imdb, work_info, net_config, work_info_epoch, work_info_batch)

task_idx=work_info_batch.ref.task_idxes;
task_subidx=work_info_batch.ref.task_subidxes;

% only support using one image for one batch...
batch_img_num=length(task_subidx);
assert(batch_img_num==1);
assert(work_info_batch.ref.batch_task_num==1);

batch_data=get_batch_data(opts, imdb, task_idx);
img_size_input=size(batch_data.img_data);
img_size_input=img_size_input(1:2);
assert(size(batch_data.img_data, 4)==batch_img_num);

% do augmentation before crop

img_size_aug=[];

if work_info.ref.run_trn

    batch_data=batch_do_data_augmentation(opts, imdb, work_info_epoch, batch_data, work_info_batch, work_info);
    img_size_aug=size(batch_data.img_data);
    img_size_aug=img_size_aug(1:2);

    batch_data=batch_do_data_crop(opts, imdb, work_info_epoch, batch_data, work_info_batch, work_info);

else

    batch_data.aug_info=[];
    batch_data.crop_info=[];
end

net_input_img_scales=net_config.ref.net_input_img_scales;

[net_input_info, net_input_str]=gen_net_input_info(opts, imdb, batch_data, net_input_img_scales);
img_size=size(batch_data.img_data);
img_size=img_size(1:2);

batch_ds_info=[];
batch_ds_info.aug_info=batch_data.aug_info;
batch_ds_info.crop_info=batch_data.crop_info;
batch_ds_info.task_idx=task_idx;
batch_ds_info.img_size=img_size;
batch_ds_info.img_size_aug=img_size_aug;
batch_ds_info.img_size_input=img_size_input;
batch_ds_info.net_input_str=net_input_str;

batch_ds_info.net_input_info=net_input_info;
batch_ds_info.batch_data=batch_data;

end

function img_data=pre_process_img_net_input(imdb, img_data)

    data_norm_info=imdb.ref.data_norm_info;

    img_data=single(img_data);
    img_data=img_data-data_norm_info.image_mean;

end

function [net_input_info,net_input_str]=gen_net_input_info(opts, imdb, batch_data, net_input_img_scales)

feat_scale_num=length(net_input_img_scales);

org_img_size=size(batch_data.img_data);
org_img_size=org_img_size(1:2);

input_info_child_groups=cell(feat_scale_num, 1);
for s_idx=1:length(net_input_img_scales)
    one_scale=net_input_img_scales(s_idx);

    if one_scale==1
        one_img_data_scaled=batch_data.img_data;
    else
        scaled_img_size=round(org_img_size.*one_scale);
        one_img_data_scaled=imresize(batch_data.img_data, scaled_img_size);
    end

    one_child_input_info=[];
    one_child_input_info.is_group_data=false;
    one_child_input_info.x=one_img_data_scaled;
    input_info_child_groups{s_idx}=one_child_input_info;
end

for tmp_img_idx=1:length(input_info_child_groups)

    one_img=input_info_child_groups{tmp_img_idx}.x;
    assert(size(one_img, 4)==1);
    assert(isa(one_img, 'uint8'));
    one_img=pre_process_img_net_input(imdb, one_img);
    assert(isa(one_img, 'single'));
    input_info_child_groups{tmp_img_idx}.x=one_img;
end

net_input_info=[];
net_input_info.is_group_data=true;
net_input_info.data_child_groups=input_info_child_groups;

net_input_str=[];
for s_idx=1:feat_scale_num
    one_net_input_size=size(input_info_child_groups{s_idx}.x);
    if length(one_net_input_size)<4
        one_net_input_size(4)=1;
    end
    one_net_input_str=my_gen_array_str(one_net_input_size);
    net_input_str=cat(2, net_input_str, one_net_input_str);
end

net_input_info=my_init_input_info(net_input_info);

end

function batch_data=get_batch_data(train_opts, imdb, img_idx)

    batch_data=[];
    if train_opts.cache_data_mem

        if ~isfield(imdb.ref, 'data_cache_tasks') || isempty(imdb.ref.data_cache_tasks)
            imdb.ref.data_cache_tasks=cell(imdb.ref.max_task_idx, 1);
        end

        batch_data=imdb.ref.data_cache_tasks{img_idx};
        if isempty(batch_data)
            do_ds_cache_all_before_run(train_opts, imdb);
            batch_data=imdb.ref.data_cache_tasks{img_idx};
            assert(~isempty(batch_data));
        end
    end

    if isempty(batch_data)
        batch_data=do_load_batch_data(train_opts, imdb, img_idx);
    end

end

function do_ds_cache_all_before_run(train_opts, imdb)

    disp('cache all data in memory ...');
    task_idxes=imdb.ref.task_idxes;
    task_num=length(task_idxes);
    for t_idx=1:task_num
        one_task_idx=task_idxes(t_idx);
        batch_data=do_load_batch_data(train_opts, imdb, one_task_idx);
        imdb.ref.data_cache_tasks{one_task_idx}=batch_data;
        if mod(t_idx, 200)==1 || t_idx==task_num
            fprintf('caching item:%d/%d\n', t_idx, task_num)
        end
    end

end

function batch_data=do_load_batch_data(train_opts, imdb, img_idx)

    ds_info=imdb.ref.ds_info;
    img_data_batch=load_img_from_ds_info(ds_info, img_idx);
    assert(isa(img_data_batch, 'uint8'));

    img_size=[size(img_data_batch, 1), size(img_data_batch, 2)];
    img_size_input=img_size;

    if ~train_opts.use_dummy_gt
        mask_data_info=ds_info.class_idxes_mask_data_info;
        one_mask=load_mask_from_ds_info(mask_data_info, img_idx);
    else
    	one_mask=ones(img_size, 'uint8');
    end
    assert(all(size(one_mask)==img_size_input));

    todo_scale=1;
    short_edge=min(img_size);
    if short_edge<train_opts.input_img_short_edge_min
        todo_scale=train_opts.input_img_short_edge_min/short_edge;
        assert(todo_scale>=1);
    end

    if short_edge>train_opts.input_img_short_edge_max
        todo_scale=train_opts.input_img_short_edge_max/short_edge;
        assert(todo_scale<=1);
    end
    todo_scale=todo_scale*train_opts.input_img_scale;

    if todo_scale~=1
        img_data_batch=imresize(img_data_batch, todo_scale);
%         img_size=[size(img_data_batch, 1), size(img_data_batch, 2)];
    end

    batch_data=[];
    batch_data.img_data=img_data_batch;
    batch_data.label_data=one_mask;
    batch_data.img_idx=img_idx;
    batch_data.img_size_origin=img_size_input;

end


function [beamGeometryInitS,tags] = dicomrt_d2c_beam(beamGeometryInitS,indexS,study,tags)
% dicomrt_d2c_beam(beamGeometryInitS,indexS,plan,tags)
%
% Convert DICOM beam data in CERR format.
%
% Copyright (C) 2002 Emiliano Spezi (emiliano.spezi@physics.org)

% Check input data
[study,type,dummylabel,PatientPosition]=dicomrt_checkinput(study);

if strcmpi('RTPLAN',type)~=1
    error('dicomrt_d2c_scan: input data does not have the right format. Exit now!');
else
    type='BEAM GEOMETRY';
end

% Get DICOM-RT toolbox dataset info
study_pointer=study{1,1};
temp_study_header=study_pointer{1};

% Get parameters
beams=fieldnames(temp_study_header.BeamSequence);
nbeams=size(beams,1);

for i=1:nbeams; % loop through the number of slices
    beamGeometryInitS(i).imageNumber                = tags.nimages +i;
    beamGeometryInitS(i).imageType                  = type;
    beamGeometryInitS(i).caseNumber                 = 1;
    beamGeometryInitS(i).patientName                = [temp_study_header.PatientName.FamilyName ,' ', ...
                temp_study_header.PatientName.GivenName];
    beamGeometryInitS(i).beamNumber                 = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'BeamNumber');
    % RadiationType
    RadiationType=getfield(temp_study_header,'BeamSequence',char(beams(i)),'RadiationType');
    if strcmpi(RadiationType,'PHOTON')==1
        beamGeometryInitS(i).beamModality               = 'X-RAY';
    else % 'OTHER' is not a possibility
        beamGeometryInitS(i).beamModality               = RadiationType;
    end
    beamGeometryInitS(i).beamEnergyMeV              = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'ControlPointSequence','Item_1','NominalBeamEnergy');
    beamGeometryInitS(i).beamDescription            = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'BeamName');
    beamGeometryInitS(i).RxDosePerTxGy              = getfield(temp_study_header,'FractionGroupSequence','Item_1',...
        'ReferencedBeamSequence',char(beams(i)),'BeamDose');
    beamGeometryInitS(i).numberOfTx                 = getfield(temp_study_header,'FractionGroupSequence','Item_1',...
        'NumberOfFractionsPlanned');

    beamGeometryInitS(i).fractionGroupID            = temp_study_header.RTPlanDescription;
    beamGeometryInitS(i).beamType                   = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'BeamType');
    beamGeometryInitS(i).planIDOfOrigin             = temp_study_header.StudyID;
    % collimatorType
    xjaw = getfield(temp_study_header,'BeamSequence',char(beams(i)),'ControlPointSequence','Item_1',...
        'BeamLimitingDevicePositionSequence','Item_1','LeafJawPositions');
    yjaw =  getfield(temp_study_header,'BeamSequence',char(beams(i)),'ControlPointSequence','Item_1',...
        'BeamLimitingDevicePositionSequence','Item_2','LeafJawPositions');
    if -xjaw(1)==xjaw(2) & -yjaw(1)==yjaw(2)
        beamGeometryInitS(i).collimatorType             = 'SYMMETRIC';
    elseif -xjaw(1)==xjaw(2) & -yjaw(1)~=yjaw(2)
        beamGeometryInitS(i).collimatorType             = 'ASYMMETRIC_Y';
    elseif -xjaw(1)==xjaw(2) & -yjaw(1)~=yjaw(2)
        beamGeometryInitS(i).collimatorType             = 'ASYMMETRIC_X';
    else
        beamGeometryInitS(i).collimatorType             = 'ASYMMETRIC';
    end
    % apertureType
    % set default
    nblocks = 0;
    ncomp   = 0;
    mlcmod  = 0;
    nwedges = 0;
    % retrieve info
    nblocks = getfield(temp_study_header,'BeamSequence',char(beams(i)),'NumberOfBlocks');
    ncomp   = getfield(temp_study_header,'BeamSequence',char(beams(i)),'NumberOfCompensators');
    mlcmod  = 0;
    nwedges = getfield(temp_study_header,'BeamSequence',char(beams(i)),'NumberOfWedges');
    % check
    if nblocks ~= 0
        beamGeometryInitS(i).apertureType               = 'BLOCKS';
    elseif ncomp ~= 0
        beamGeometryInitS(i).apertureType               = 'TRANSMISSION_MAP';
    elseif mlcmod ~= 0
        beamGeometryInitS(i).apertureType               = 'MLC_XY';
    else
        beamGeometryInitS(i).apertureType               = 'COLLIMATOR';
    end
    beamGeometryInitS(i).apertureDescription        = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'BeamName');
    beamGeometryInitS(i).collimatorAngle            = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'ControlPointSequence','Item_1','BeamLimitingDeviceAngle');
    beamGeometryInitS(i).gantryAngle                = 360-getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'ControlPointSequence','Item_1','GantryAngle');
    beamGeometryInitS(i).couchAngle                 = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'ControlPointSequence','Item_1','TableTopEccentricAngle');
    beamGeometryInitS(i).headInOut                  = tags.hio;
    beamGeometryInitS(i).nominalIsocenterDistance   = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'SourceAxisDistance').*0.1;
    beamGeometryInitS(i).numberRepresentation       = 'CHARACTER';
    % Optional
    beamGeometryInitS(i).apertureID                 = '';
    if nwedges ~= 0
        beamGeometryInitS(i).wedgeAngle                 = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
            'WedgeSequence','Item_1','WedgeAngle');
        beamGeometryInitS(i).wedgeRotationAngle         = 360-getfield(temp_study_header,'BeamSequence',char(beams(i)),...
            'WedgeSequence','Item_1','WedgeOrientation');
    else
        beamGeometryInitS(i).wedgeAngle                 = '';
        beamGeometryInitS(i).wedgeRotationAngle         = '';
    end
    beamGeometryInitS(i).arcAngle                   = '';
    beamGeometryInitS(i).machineID                  = getfield(temp_study_header,'BeamSequence',char(beams(i)),...
        'TreatmentMachineName');
    beamGeometryInitS(i).beamWeight                 = '';
    beamGeometryInitS(i).weightUnits                = '';
    beamGeometryInitS(i).compensator                = '';
    beamGeometryInitS(i).compensatorFormat          = '';
    beamGeometryInitS(i).file                       = '';
end

% Update nimages
tags.nimages = tags.nimages + nbeams;


% PURPOSE: Loads current ERP structure (if any) from de the workspace.
%          Otherwise, load ALLERP(CURRENTERP); Otherwise ERP = [];
%
%          To avoid clearing an already filled ERP structure after an interrupted
%          process (for instance, after an error)
%
% *** This function is part of ERPLAB Toolbox ***
% Author: Javier Lopez-Calderon
% Center for Mind and Brain
% University of California, Davis,
% Davis, CA
% 2009

function ALLERP = preloadALLERP
try
        ALLERP = evalin('base', 'ALLERP');
catch
        ALLERP = [];
end


% eeg_rejsuperpose() - superpose rejections of a EEG dataset.
%
% Usage:
%   >> EEGOUT = eeg_rejsuperpose( EEGIN, typerej, Rmanual, Rthres, ...
%                    Rconst, Rent, Rkurt, Rfreq, Rothertype);
%
% Inputs:
%   EEGIN      - input dataset
%   typerej    - type of rejection (1=raw data; 0=ica).
%   Rmanual    - include manual rejection (0|1).
%   Rthres     - include threshold rejection (0|1).
%   Rconst     - include rejection of constant activity (0|1).
%   Rent       - include entropy rejection (0|1).
%   Rkurt      - include kurtosis rejection (0|1).
%   Rfreq      - include frequcy based rejection (0|1).
%   Rothertype - include manual rejection (0|1).
%
% Outputs:
%   EEGOUT     - with rejglobal and rejglobalE fields updated
%
% See also: eeglab()

% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% 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 2 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, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [EEG, com] = eeg_rejsuperpose( EEG, typerej, Rmanual, Rthres, Rconst, ...
                              Rent, Rkurt, Rfreq, Rothertype);

if nargin < 9
	help eeg_rejsuperpose;
	return;
end;

typerej = ~typerej;
rejglobal  = zeros( 1, EEG.trials);
if typerej == 0
    rejglobalE = zeros( EEG.nbchan, EEG.trials);
else
    rejglobalE = zeros( size(EEG.icaweights,1), EEG.trials);
end

if typerej == 0 | Rothertype
	if Rmanual
		rejglobal  = rejarray( rejglobal,  EEG.reject.rejmanual); % see bottom for the
		rejglobalE = rejarray( rejglobalE, EEG.reject.rejmanualE); % function rejarray
	end;
	if Rthres
		rejglobal  = rejarray( rejglobal,  EEG.reject.rejthresh);
		rejglobalE = rejarray( rejglobalE, EEG.reject.rejthreshE);
	end;
	if Rfreq
		rejglobal  = rejarray( rejglobal,  EEG.reject.rejfreq);
		rejglobalE = rejarray( rejglobalE, EEG.reject.rejfreqE);
	end;
	if Rconst
		rejglobal  = rejarray( rejglobal,  EEG.reject.rejconst);
		rejglobalE = rejarray( rejglobalE, EEG.reject.rejconstE);
	end;
	if Rent
		rejglobal  = rejarray( rejglobal,  EEG.reject.rejjp);
		rejglobalE = rejarray( rejglobalE, EEG.reject.rejjpE);
	end;
	if Rkurt
		rejglobal  = rejarray( rejglobal,  EEG.reject.rejkurt);
		rejglobalE = rejarray( rejglobalE, EEG.reject.rejkurtE);
	end;
end;

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

if typerej == 1 | Rothertype
	if Rmanual
		rejglobal  = rejarray( rejglobal,  EEG.reject.icarejmanual);
		rejglobalE = rejarray( rejglobalE, EEG.reject.icarejmanualE);
	end;
	if Rthres
		rejglobal  = rejarray( rejglobal,  EEG.reject.icarejthresh);
		rejglobalE = rejarray( rejglobalE, EEG.reject.icarejthreshE);
	end;
	if Rfreq
		rejglobal  = rejarray( rejglobal,  EEG.reject.icarejfreq);
		rejglobalE = rejarray( rejglobalE, EEG.reject.icarejfreqE);
	end;
	if Rconst
		rejglobal  = rejarray( rejglobal,  EEG.reject.icarejconst);
		rejglobalE = rejarray( rejglobalE, EEG.reject.icarejconstE);
	end;
	if Rent
		rejglobal  = rejarray( rejglobal,  EEG.reject.icarejjp);
		rejglobalE = rejarray( rejglobalE, EEG.reject.icarejjpE);
	end;
	if Rkurt
		rejglobal  = rejarray( rejglobal,  EEG.reject.icarejkurt);
		rejglobalE = rejarray( rejglobalE, EEG.reject.icarejkurtE);
	end;
end;

EEG.reject.rejglobal = rejglobal;
EEG.reject.rejglobalE = rejglobalE;

com =sprintf('%s = eeg_rejsuperpose( %s, %d, %d, %d, %d, %d, %d, %d, %d);', ...
	  inputname(1), inputname(1), ~typerej, Rmanual, Rthres, Rconst, Rent, Rkurt, Rfreq, Rothertype);

return;

% subfunction rejecting an array ------
function dest = rejarray( dest, ori)
    if isempty(dest)
        dest = ori;
    elseif ~isempty(ori)
		dest = dest | ori;
	end;
return;


function hf=anim8(varargin)

% function hf=anim8(hf,animStruct)
% ------------------------------------------------------------------------
%
% Change log:
% 2019/05/20 Added loading of saved anim8 figure by using the path to the
% figure as sole input (or no input which triggers uigetfile)
% 2019/08/09 Changed to use uicontrol slider rather than java slider due
% to future removal of javacomponent
% 2019/10/13 Fixed bug in relation to handling a single time step (no
% annimation), fixed by copying state twice and animating clones states.
% ------------------------------------------------------------------------

%% Parse input

switch nargin
    case {0,1} %Load previous
        if nargin==1 %If path to figure is specified
            figureFullPath=varargin{1};
        else %If no path is specified
            [figureFileName,figurePath]=uigetfile;
            figureFullPath=fullfile(figurePath,figureFileName);
        end
        hf=open(figureFullPath); %Open figure and keep handle

        %Add view control widget
        hp=vcw(hf);
        hf.UserData.cFigure.Handles.vcw=hp;

        %Add export figure widget
        efw(hf);

        if ~isfield(hf.UserData,'anim8')
            error('Loaded figure lacks an anim8 structure as UserData');
        else
            animStruct=hf.UserData.anim8.animStruct; %Get anim8 structure
        end

        try %Try to remove a slider if present
            hSlider=hf.UserData.anim8.sliderHandles{1};
            if isa(hSlider,'matlab.ui.control.UIControl')
                delete(hSlider)
            else %Old jSlider type
                try %javacomponent is scheduled to be removed but try it here for old slider bar type
                    warning off %Disable all warnings
                    [~,hc]=javacomponent(hSlider);
                    delete(hc);
                    warning on %Enable warnings again
                catch
                    %No fix if the above throws an error
                end
            end
        catch %Nothing to delete
        end

        try %Try to remove text label above slider if present
            delete(hf.UserData.anim8.ButtonHandles.hTextTime)
        catch %Nothing to delete
        end

    case 2 %Create new
        hf=varargin{1}; %Figure handle
        animStruct=varargin{2}; %The anim8 structure
end

if ~isfield(animStruct,'Time')
    animStruct.Time=linspace(0,numel(animStruct.Handles),numel(animStruct.Handles));
end

%% Visualisation settings

% fontColor='w';
fontSize=15;
% cMap=gjet(250);
scrollBarWidth=30;

%% Defining slider
figure(hf); drawnow;

if numel(animStruct.Time)==1
    warning('Only 1 step for animation');
    animStruct.Time(end+1)=animStruct.Time(end);
    animStruct.Handles{end+1}=animStruct.Handles{end}; %Handles of objects to animate
    animStruct.Props{end+1}=animStruct.Props{end}; %Properties of objects to animate
    animStruct.Set{end+1}=animStruct.Set{end};
end

animTime=animStruct.Time(:);
sliceIndexI=numel(animTime); %Initial index at end
sliderStep=[1/(numel(animTime)-1) 1/(numel(animTime)-1)]; %Slider step sizes

%Initialize slider
hSlider= uicontrol(hf,'Style','slider','Position',[0,0,round(hf.Position(3)),scrollBarWidth]);
set(hSlider,'Value',sliceIndexI,'Min',1,'Max',numel(animTime),'SliderStep',sliderStep);
hSlider.Callback={@updateViewFunc,hf};
% hSlider.KeyPressFcn={@updateViewFunc,hf};
addlistener(hSlider,'ContinuousValueChange',@(hObject, event) updateViewFunc(hObject, event,hf));
addlistener(hSlider,'Value','PostSet',@(hObject, event) updateViewFunc(hObject, event,hf));

%% Set resize function

% set(hf,'ResizeFcn',{@figResize,{hf,scrollBarWidth,hSlider}});
% set(hf,'ResizeFcn',@(h,e)figResize(h,e,{hf,scrollBarWidth,hSlider}));

hFunc=get(hf,'ResizeFcn');

if iscell(hFunc)
    warning('anim8 changed the ResizeFcn function for this figure. Specify your ResizeFcn in the form @(h,e)figResize(h,e,c) to avoid this behavior.');
    set(hf,'ResizeFcn',@(a,b)figResize(a,b,{hf,scrollBarWidth,hSlider}));
else
    if isempty(hFunc)
        set(hf,'ResizeFcn',@(a,b)figResize(a,b,{hf,scrollBarWidth,hSlider}));
    else
        set(hf,'ResizeFcn',@(a,b)(cellfun(@(x)feval(x,a,b),{hFunc,@(a,b)figResize(a,b,{hf,scrollBarWidth,hSlider})})));
    end
end

%% Initialize figure callbacks

set(hf,'KeyPressFcn', {@figKeyPressFunc,{hf}});%'WindowButtonDownFcn', {@figMouseDown,{hf}},'WindowButtonUpFcn', {@mouseup,hf});

%% Initialise tool bar and buttons

filePath=mfilename('fullpath');
toolboxPath=fileparts(fileparts(filePath));
iconPath=fullfile(toolboxPath,'icons');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Toolbar
toolbarTag='anim8_toolbar';

%Remove existing anim8 toolbar
hb = findall(hf,'Tag',toolbarTag); % hb = findall(hf,'Type','uitoolbar');
if ~isempty(hb)
    delete(hb)
else
    %Find all toolbars
    hb = findall(hf,'Type','uitoolbar');

    %Remove them if they are not the default bar
    if ~isempty(hb)
        for q=1:1:numel(hb)
            if ~strcmp(hb(q).Tag,'FigureToolBar')
                delete(hb(q));
            end
        end
    end
end

%Create new anim8 toolbar
hb = uitoolbar(hf);
hb.Tag=toolbarTag;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Help button

%get icon
D=importdata(fullfile(iconPath,'help.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
% Create a uipushtool in the toolbar
uipushtool(hb,'TooltipString','Help','CData',S,'Tag','help_button','ClickedCallback',@helpFunc,'Separator','on');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Play button

%get icon 1
D=importdata(fullfile(iconPath,'play.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
iconPlay=S;

%get icon 2
D=importdata(fullfile(iconPath,'stop.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
iconStop=S;

% Create a uitoggletool in the toolbar
hPlay=uitoggletool(hb,'TooltipString','Play','CData',iconPlay,'Tag','play_button','ClickedCallback',{@playFunc,{hf}});

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Time button

%get icon
D=importdata(fullfile(iconPath,'time.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
% Create a uipushtool in the toolbar
uipushtool(hb,'TooltipString','Time','CData',S,'Tag','time_button','ClickedCallback',{@timeFunc,{hf}}); %,'Separator','on'

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Cycle button

%get icon
D=importdata(fullfile(iconPath,'cycle.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
% Create a uitoggletool in the toolbar
hCycle=uitoggletool(hb,'TooltipString','Cycle forward-backward','CData',S,'Tag','cycle_button');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Save animation button

%get icon
D=importdata(fullfile(iconPath,'saveAnimation.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
% Create a uipushtool in the toolbar
uipushtool(hb,'TooltipString','Save .gif animation','CData',S,'Tag','saveAnimation_button','ClickedCallback',{@saveAnimationFunc,{hf}}); %,'Separator','on'

%% Text fields

% title(sprintf('%6.16e ',T),'FontSize',hf.UserData.anim8.fontSize);
% title(sprintf('%f',T),'FontSize',hf.UserData.anim8.fontSize);

hTextTime = uicontrol(hf,'Style','text',...
    'String',[' Time: ',sprintf('%f',animTime(1))],...
    'Position',[0 scrollBarWidth round(hf.Position(3)) scrollBarWidth],...
    'BackgroundColor',[1 1 1],'HorizontalAlignment','Left',...
    'fontSize',fontSize);

%% Set figure UserData

hf.UserData.anim8.sliderHandles={hSlider};
% hf.UserData.anim8.ButtonHandles.Sample=hSample;
hf.UserData.anim8.animStruct=animStruct;
hf.UserData.anim8.fontSize=fontSize;
% animHandles=animStruct.Handles; %Handles of objects to animate
% animProps=animStruct.Props; %Properties of objects to animate
% animSets=animStruct.Set; %Property values for to set in order to animate
% animTime=animStruct.Time;
hf.UserData.anim8.playDir=1;
hf.UserData.anim8.ButtonHandles.Play=hPlay;
hf.UserData.anim8.ButtonHandles.hCycle=hCycle;
hf.UserData.anim8.ButtonHandles.hTextTime=hTextTime;
hf.UserData.anim8.pauseTime=1/numel(animStruct.Time);%mean(diff(animStruct.Time));
hf.UserData.anim8.shiftMag=1;%ceil(numel(animStruct.Time)/20);
hf.UserData.anim8.icons.play=iconPlay;
hf.UserData.anim8.icons.stop=iconStop;

% Store current settings
hf.UserData.anim8.WindowButtonDownFcn=hf.WindowButtonDownFcn;
hf.UserData.anim8.WindowButtonUpFcn=hf.WindowButtonUpFcn;
hf.UserData.anim8.KeyPressFcn=hf.KeyPressFcn;
hf.UserData.anim8.WindowScrollWheelFcn=hf.WindowScrollWheelFcn;
hf.UserData.anim8.BusyAction=hf.BusyAction;

%Export figure widget settings
hf.UserData.efw.defaultPath=fullfile(cd,'efw');
hf.UserData.efw.imName=['figure',num2str(get(hf,'Number'))];
hf.UserData.efw.imExt='png';
hf.UserData.efw.imRes='50';
hf.UserData.efw.exportFigOpt='-nocrop';
hf.UserData.efw.exportGifOpt='1';

%% Initialize slider locations
set(hSlider,'Value',round(sliceIndexI/2));
set(hSlider,'Value',sliceIndexI);
drawnow;

end

%% Scroll bar resizing

function figResize(~,~,inputCell)
hf=inputCell{1};
scrollBarWidth=inputCell{2};

hSlider=inputCell{3};
if isa(hSlider,'matlab.ui.control.UIControl') %Check if its a MATLAB style slider
    set(hSlider,'Position',[0,0,round(hf.Position(3)), scrollBarWidth]);
    set(hf.UserData.anim8.ButtonHandles.hTextTime,'Position',[0 scrollBarWidth round(hf.Position(3)) scrollBarWidth]);
else %Old JAVA jSlider
%     try
% %         delete(hSlider)
%     catch
%     end
%     try %javacomponent is scheduled to be removed but try it here for old slider bar type
%         jc=javacomponent(hSlider,[0,0,round(hf.Position(3)), scrollBarWidth]);
%         jc.delete
%     catch
%         %No fix if the above throws an error
%     end
end

end

%% Help

function helpFunc(~,~)

msgText={'* Play button or press the space bar -> Start animation',...
    '* Stop button or press the space bar -> Stop animation',...
    '* Time button -> Change time stepping settings',...
    '* Cycle button -> Toggle forward / forward-backward mode',...
    '* Save button -> Export snap shorts (e.g. jpg) and animated .gif files',...
    '* Press the v key to activate the view control widget (vcw), note that vcw changes key press functions until vcw is deactivated',...
    };
helpdlg(msgText,'Help information');

end

%% play

function playFunc(~,~,inputCell)
hf=inputCell{1};
shiftMag=hf.UserData.anim8.shiftMag;

set(hf.UserData.anim8.ButtonHandles.Play,'CData',hf.UserData.anim8.icons.stop,'TooltipString','Stop');

while strcmp(get(hf.UserData.anim8.ButtonHandles.Play,'State'),'on')
    tic
    if strcmp(get(hf.UserData.anim8.ButtonHandles.hCycle,'State'),'on')
        hSlider=hf.UserData.anim8.sliderHandles{1};

        sliderValue=get(hSlider,'Value');
        sliderValueNew=sliderValue+(shiftMag*hf.UserData.anim8.playDir);

        sliderMax=get(hSlider,'Max');
        sliderMin=get(hSlider,'Min');

        if sliderValueNew<sliderMin
            hf.UserData.anim8.playDir=hf.UserData.anim8.playDir*-1;
            sliderValueNew=sliderValue+(shiftMag*hf.UserData.anim8.playDir);
        elseif sliderValueNew>sliderMax
            hf.UserData.anim8.playDir=hf.UserData.anim8.playDir*-1;
            sliderValueNew=sliderValue+(shiftMag*hf.UserData.anim8.playDir);
        end
        set(hSlider,'Value',sliderValueNew);
    else
        shiftSlider(hf.UserData.anim8.sliderHandles{1},shiftMag);
    end
    updateViewFunc([],[],hf);
    drawnow;

    t=toc;
    tPause=hf.UserData.anim8.pauseTime-t;
    if tPause>0
        pause(tPause);
    end
end

set(hf.UserData.anim8.ButtonHandles.Play,'CData',hf.UserData.anim8.icons.play,'TooltipString','Play');

end

%% Time
function timeFunc(~,~,inputCell)
hf=inputCell{1};

prompt = {'Enter pause time:','Enter step size:'};
dlg_title = 'Time stepping settings';
defaultOptions = {num2str(hf.UserData.anim8.pauseTime),num2str(hf.UserData.anim8.shiftMag)};
s=40+max([cellfun(@numel,prompt) cellfun(@numel,defaultOptions)]);
Q = inputdlg(prompt,dlg_title,[1 s],defaultOptions);
if ~isempty(Q)
    if ~isempty(Q{1})
        hf.UserData.anim8.pauseTime=str2double(Q{1});
    end
    if ~isempty(Q{2})
        hf.UserData.anim8.shiftMag=str2double(Q{2});
    end
end

end

%% Save Animation

function saveAnimationFunc(~,~,inputCell)

hf=inputCell{1};
defStruct=hf.UserData.efw; %Default option structure
exportGifAnim8(hf,defStruct,1); %Export gif data

end

%% Figure key press

function figKeyPressFunc(~,eventData,inputCell)

hf=inputCell{1}; %Figure handle

% Key input options
switch eventData.Key
    case {'leftarrow','downarrow'}
        shiftSlider(hf.UserData.anim8.sliderHandles{1},-1*hf.UserData.anim8.shiftMag);
        updateViewFunc([],[],hf);
    case {'rightarrow','uparrow'}
        shiftSlider(hf.UserData.anim8.sliderHandles{1},1*hf.UserData.anim8.shiftMag);
        updateViewFunc([],[],hf);
    case 'home' % Go to the start
        hSlider=hf.UserData.anim8.sliderHandles{1};
        sliderVal=get(hSlider,'Min');
        set(hSlider,'Value',sliderVal);
        updateViewFunc([],[],hf);
    case 'end' % Go to the end
        hSlider=hf.UserData.anim8.sliderHandles{1};
        sliderVal=get(hSlider,'Max');
        set(hSlider,'Value',sliderVal);
        updateViewFunc([],[],hf);
    case 'v' % Activate vcw
        set(hf.UserData.cFigure.Handles.vcw,'State','On');
    case'space'
        if strcmp(get(hf.UserData.anim8.ButtonHandles.Play,'State'),'off')
            set(hf.UserData.anim8.ButtonHandles.Play,'State','on');
            playFunc([],[],{hf});
        else
            set(hf.UserData.anim8.ButtonHandles.Play,'State','off');
        end
end

end

%% updateViewFunc

function updateViewFunc(~,~,hf)

animStruct=hf.UserData.anim8.animStruct;
hSlider=hf.UserData.anim8.sliderHandles{1};
sliderValue=round(get(hSlider,'Value'));
set(hSlider,'Value',sliderValue);

T=animStruct.Time(sliderValue);
H=animStruct.Handles{sliderValue};%e.g. [hp,hp]; %Handles of objects to animate
P=animStruct.Props{sliderValue};% e.g. {'FaceColor','Vertices'}; %Properties of objects to animate
S=animStruct.Set{sliderValue};%e.g.{c(q,:),V}; %Property values for to set in order to animate

set(hf.UserData.anim8.ButtonHandles.hTextTime,'String',[' Time: ',sprintf('%f',T)],'FontSize',hf.UserData.anim8.fontSize);

for q=1:1:numel(H)
    h=H(q); % Current graphics handle
    p=P{q}; % Current graphics property
    s=S{q}; % Current property setting
    h.(p)=s;% Setting the property
end

end

%% Shift slider

function shiftSlider(hSlider,shiftMag)

sliderValue=get(hSlider,'Value');
sliderValueNew=sliderValue+shiftMag;

sliderMax=get(hSlider,'Max');
sliderMin=get(hSlider,'Min');

if sliderValueNew<sliderMin
    set(hSlider,'Value',sliderMax);
elseif sliderValueNew>sliderMax
    set(hSlider,'Value',1);
else
    set(hSlider,'Value',sliderValueNew);
end

end

%%
% _*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 svgClipping(s, path)
% Adds a clipping path
% PRELIMINARY IMPLEMENTATION (Parameters may change)
%
% svgClipping(s, path)
% Parameters:
%   s : Array of plot object handles
%   path : Clipping path nx3 or nx2.
for i = 1:length(s)
    userdata = get(s(i),'UserData');
    userdata.svg.ClippingPath = path;
    set(s(i),'UserData', userdata);
end


%BORDERINTERPOLATE  Computes the source location of an extrapolated pixel
%
%     loc = cv.borderInterpolate(p, len)
%     [...] = cv.borderInterpolate(..., 'OptionName', optionValue, ...)
%
% ## Input
% * __p__ 0-based coordinate of the extrapolated pixel along one of the axes,
%   likely `p < 0` or `p >= len`.
% * __len__ Length of the array along the corresponding axis.
%
% ## Output
% * __loc__ Pixel coordinate along the specified axis.
%
% ## Options
% * __BorderType__ Border type, one of:
%   * __Constant__ `iiiiii|abcdefgh|iiiiiii` with some specified `i`
%   * __Replicate__ `aaaaaa|abcdefgh|hhhhhhh`
%   * __Reflect__ `fedcba|abcdefgh|hgfedcb`
%   * __Reflect101__ `gfedcb|abcdefgh|gfedcba`
%   * __Wrap__ `cdefgh|abcdefgh|abcdefg`
%   * __Default__ same as 'Reflect101' (default)
%
%   When `BorderType=='Constant'`, the function always returns -1, regardless
%   of `p` and `len`.
%
% The function computes and returns the coordinate of a donor pixel
% corresponding to the specified extrapolated pixel when using the specified
% extrapolation border mode.
%
% Normally, the function is not called directly. It is used inside filtering
% functions and also in cv.copyMakeBorder.
%
% See also: cv.copyMakeBorder
%


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

%%
clear; close all; clc;

%% Syntax
% |[varargout]=patchEdgeCrossProduct(F,V);|

%% 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 [class_name,rotation] = modelnet_extract_classname_and_rot_from_filename(filename)

s = strsplit(filename,{'.','/'});
class_name = s{end-4};
r = strsplit(s{end-1},'_');
rotation = str2double(r(end));


function bz_meta_extracted = bz_database_extract_meta(bz_datasets,j)
% Submit dataset to the Buzsakilab metadata-database
% v1.1
%
% INPUT
% bz_datasets
% structure with subfields named after the mySQL columns. The subfields has
% to have the right format for submitting to the database.
%
%
% By Peter Petersen
% petersen.peter@gmail.com

bz_meta_extracted = bz_datasets;
if ~exist('j')
    j = size(bz_meta_extracted,2);
end
Session = bz_datasets(j).SessionPath;
fprintf(['\n ', num2str(j), '. Animal ' bz_datasets(j).Animal, ', session ', bz_datasets(j).Session, ': '])

% LFP
if exist([Session,'.eeg'])
    bz_meta_extracted(j).LFP = 'Yes';
elseif exist([Session,'.lfp'])
    bz_meta_extracted(j).LFP = 'Yes';
else
    bz_meta_extracted(j).LFP = 'No';
end

% Raw data
if exist(([Session,'.dat']))
    bz_meta_extracted(j).RawData = 'Raw data';
elseif exist(([Session,'.fil']))
    bz_meta_extracted(j).RawData = 'High-pass filtered';
else
    bz_meta_extracted(j).RawData = 'No';
end
if ~strcmp(bz_meta_extracted(j).RawData,'No')
    fprintf(['Data format: ' char(bz_meta_extracted(j).RawData) '. '])
end

% Sampling rate and channel count
if exist(([Session,'.xml']))
    xml = LoadXml(([Session,'.xml']));
    bz_meta_extracted(j).SampleRate = xml.SampleRate;
    bz_meta_extracted(j).lfpSampleRate = xml.lfpSampleRate;
    bz_meta_extracted(j).nChannels = xml.nChannels;
    bz_meta_extracted(j).nElecGps = xml.nElecGps;
    bz_meta_extracted(j).Unitsformat = 'NA';
end

% Number of Cells
bz_meta_extracted(j).Cells = 0;
for i = 1:bz_meta_extracted(j).nElecGps
    if exist(([Session,'.clu.' num2str(i)]))
        cluster_index = load(([Session,'.clu.' num2str(i)]));
        bz_meta_extracted(j).Cells = bz_meta_extracted(j).Cells + sum(unique(cluster_index(2:end))>1);
        bz_meta_extracted(j).Unitsformat = 'Neurosuite';
    end
end
if bz_meta_extracted(j).Cells>0
    fprintf([num2str(bz_meta_extracted(j).Cells) ' units detected. '])
else
    fprintf('No units detected. ')
end

% Duration
if exist(([Session,'.eeg']))
    temp_ = dir(([Session,'.eeg']));
    bz_meta_extracted(j).Duration = temp_.bytes/bz_meta_extracted(j).nChannels/bz_meta_extracted(j).lfpSampleRate/2;
elseif exist(([Session,'.lfp']))
    temp_ = dir(([Session,'.lfp']));
    bz_meta_extracted(j).Duration = temp_.bytes/bz_meta_extracted(j).nChannels/bz_meta_extracted(j).lfpSampleRate/2;
else
    bz_meta_extracted(j).Duration = 0;
end

% Sleep scored
if exist(([Session,'.states.REM'])) | exist(([Session,'.states.SWS'])) | exist(([Session,'.states.Wake']))
    bz_meta_extracted(j).SleepScored = 'Yes';
elseif exist(([Session,'-states.mat']))
    bz_meta_extracted(j).SleepScored = 'Yes';
elseif exist(([Session,'.sts.REM'])) | exist(([Session,'.sts.SWS'])) | exist(([Session,'.sts.Wake']))
    bz_meta_extracted(j).SleepScored = 'Yes';
elseif exist(([Session,'_SleepScore.mat']))
    bz_meta_extracted(j).SleepScored = 'Yes';
elseif exist(([Session,'.SleepState.states.mat']))
    bz_meta_extracted(j).SleepScored = 'Yes';
else
    bz_meta_extracted(j).SleepScored = 'No';
end
if strcmp(bz_meta_extracted(j).SleepScored, 'Yes')
    fprintf('SleepScoring detected. ')
else
    fprintf('No sleepScoring. ')
end

% Ripples
if exist(([Session,'.ripplesALL.event.mat']))
    fprintf('Ripple analysis detected. ')
    bz_meta_extracted(j).RipplesDetected = 'Yes';
else
    fprintf('No ripple analysis detected. ')
    bz_meta_extracted(j).RipplesDetected = 'No';
end

% Tracking
if exist(([Session,'.whl']))
    fprintf('whl tracking files detected. ')
    bz_meta_extracted(j).Tracking = 'Camera';
    bz_meta_extracted(j).TrackingFormat = 'whl';
    bz_meta_extracted(j).TrackingFrameRate = 39.06;
else
    bz_meta_extracted(j).Tracking = 'No';
    bz_meta_extracted(j).TrackingFormat = nan;
end

% Buzcode
if exist(([Session,'.sessionInfo.mat']))
    fprintf('Buzcode sessionInfo file detected. ')
    sessionInfo = load([Session,'.sessionInfo.mat']);
    if isfield(sessionInfo.sessionInfo,'region') && ~isempty(sessionInfo.sessionInfo.region)
        bz_meta_extracted(j).BrainRegion = strjoin(unique(sessionInfo.sessionInfo.region),',');
    end
    if isfield(sessionInfo.sessionInfo,'depth') && ~isempty(sessionInfo.sessionInfo.region)
        bz_meta_extracted(j).Depth = char(sessionInfo.sessionInfo.depth);
    end
    if isfield(sessionInfo.sessionInfo,'Date')
        bz_meta_extracted(j).Date = sessionInfo.sessionInfo.Date;
    end
    bz_meta_extracted(j).FileFormat = 'Buzcode';
    clear sessionInfo
end

if exist(([Session,'.behavior.mat']))
    fprintf('Buzcode behavior file detected. ')
    behavior = load([Session,'.behavior.mat']);
    bz_meta_extracted(j).TrackingFormat = 'buzcode';
    if isfield(behavior.behavior,'acquisitionsystem') && ~isempty(behavior.behavior.acquisitionsystem)
        bz_meta_extracted(j).Tracking = behavior.behavior.acquisitionsystem;
    end
    if isfield(behavior.behavior,'samplingRate') && ~isempty(behavior.behavior.samplingRate)
        bz_meta_extracted(j).TrackingFrameRate = behavior.behavior.samplingRate;
    end
    if isfield(behavior.behavior,'events') && isfield(behavior.behavior.events,'trials') && ~isempty(behavior.behavior.events.trials)
    bz_meta_extracted(j).BehavioralTrials = size(behavior.behavior.events.trials,2);
    end
    clear behavior
end

% Brendon's standard
if exist(([Session,'_BasicMetaData.mat']))
    fprintf('_BasicMetaData file detected (Brendons format). ')
    BasicMetaData = load([Session,'_BasicMetaData.mat']);
    if isfield(BasicMetaData,'CortexRegion')
        bz_meta_extracted(j).BrainRegion = strjoin(unique(BasicMetaData.CortexRegion),',');
    end
    if isfield(BasicMetaData,'bmd') && isfield(BasicMetaData.bmd,'Par') && isfield(BasicMetaData.bmd.Par,'Date')
        bz_meta_extracted(j).Date = BasicMetaData.bmd.Par.Date;
    end
    bz_meta_extracted(j).FileFormat = 'Brendon_metadata';
    clear bmd CortexRegion
end

% Neurodata Without Borders


function labels = ind2label(obj, indices)
    % Returns the label of SymVariable specified by the position index
    %
    %
    % Parameters:
    %  indices: position indices of symbolic variable
    %
    % Return values:
    %  labels: a cellstr array of the labels
    %

    labels = obj.label(indices);

end


function [ readerobj ] = open_tsx_reader( filename )
%OPEN_TSX_READER Intiates a reader object for TSX XML description file
%
% Written by: Wade Schwartzkopf, NGA/IDT
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

%% Read in XML metadata
xp=javax.xml.xpath.XPathFactory.newInstance.newXPath();
domnode=xmlread(filename); % Read main TSX XML descriptor file
filepath=fileparts(filename);
geoxmlfile=dir(fullfile(filepath,'ANNOTATION','GEOREF.xml'));
if ~isempty(geoxmlfile)
    geo_dom_node = xmlread(fullfile(filepath,'ANNOTATION','GEOREF.xml'));
else
    geo_dom_node = [];
end
meta=meta2sicd_tsxxml(domnode, geo_dom_node);
for i=1:length(meta)
    meta{i}.native.tsxxml=domnode;
end
symmetry=[(meta{1}.SCPCOA.SideOfTrack=='L') 0 1]; % COSAR written in range lines

%% Setup readers for each component
num_files=str2double(xp.evaluate('count(level1Product/productComponents/imageData/file/location)',domnode));
filelist=cell(1,num_files); readerobj=filelist; % Create empty cell arrays
for i=1:num_files
    basepathname=fileparts(filename);
    xpath_str_base=['level1Product/productComponents/imageData[' num2str(i) ']/file/'];
    host=char(xp.evaluate([xpath_str_base 'location/host'],domnode));
    pathname=char(xp.evaluate([xpath_str_base 'location/path'],domnode));
    datafilename=char(xp.evaluate([xpath_str_base 'location/filename'],domnode));
    filelist{i}=fullfile(basepathname,host,pathname,datafilename);
    format = char(xp.evaluate('level1Product/productInfo/imageDataInfo/imageDataFormat',domnode));
    if strcmp(format,'COSAR')
        readerobj{i}=open_cos_reader_noxml(filelist{i},symmetry);
        cos_meta=readerobj{i}.get_meta();
        meta{i}.native.cos=cos_meta.native.cos;
        if (meta{i}.ImageData.NumCols~=cos_meta.native.cos.az)||...
            (meta{i}.ImageData.NumRows~=cos_meta.native.cos.rs)
            error('OPEN_TSX_READER:INCONSISTENT_SIZE','COSAR and XML metadata do not match.');
        end
        % Reading ValidData region from COSAR is slow, so we comment it out
        % meta{i}.ImageData.ValidData = cosar_valid_data(filelist{i},symmetry(1));
        % valid_latlons=point_slant_to_ground(...
        %     [[meta{i}.ImageData.ValidData.Vertex.Row]; ...
        %     [meta{i}.ImageData.ValidData.Vertex.Col]], meta{i});
        % for j = 1:size(valid_latlons,2)
        %     meta{i}.GeoData.ValidData.Vertex(j).Lat=valid_latlons(1,j);
        %     meta{i}.GeoData.ValidData.Vertex(j).Lon=valid_latlons(2,j);
        % end
    elseif strcmp(format,'GEOTIFF')
        readerobj{i}=open_tiff_reader(filelist{i}); % Not necessarily oriented properly
        meta{i}.native.tiff=readerobj{i}.get_meta();
    end
    readerobj{i}.get_meta = @() meta{i};
end
end

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


function [obj] = regObjective(obj, funcs)
    % This method registers the information of a NLP function as a
    % cost function
    %
    % Parameters:
    %  funcs: a list of objective functions @type NlpFunction
    %
    % Parameters:
    %  funcs: new NLP variables @type NlpFunction
    %
    % @note We always assume ''funcs'' to be a 2-D array of objects or
    % table consists of array objects. It also covers 1-D array or scalar
    % variables.
    %
    % @see NlpFunction

    if iscell(funcs)
        % validate the class of each objects
        assert(all(cellfun(@(x)isa(x,'NlpFunction'), funcs)), ...
            'Each variable must be an object of ''NlpFunction'' class or inherited subclasses');

        % remove empty (Dimension==0) objects from the the array
        funcs = funcs(~cellfun(@(x)x.Dimension==0,funcs));
        % contecate to the variable array
        obj.CostArray = [obj.CostArray; vertcat(funcs{:})];

    elseif isa(funcs, 'NlpFunction')
        % remove empty (Dimension==0) objects from the the array
        funcs = funcs(~arrayfun(@(x)x.Dimension==0,funcs));

        % contecate to the variable array
        obj.CostArray = [obj.CostArray; funcs(:)];
    elseif istable(funcs)

        % convert table content to an array
        funcs = transpose(table2array(funcs));
        % remove empty (Dimension==0) objects from the the array
        funcs = funcs(~arrayfun(@(x)x.Dimension==0,funcs));

        % contecate to the variable array
        obj.CostArray = [obj.CostArray; funcs(:)];

    else
        error('Unsupported variable type found: %s\n', class(funcs));
    end

end


%% select file
if ~exist('zip_file_path', 'var') || ~exist(zip_file_path, 'file')
    [file_name, folder_path] = uigetfile('*.zip');
    zip_file_path = fullfile(folder_path, file_name);
end

%% unzip the zip file
[s_dir, s_name, ~] = fileparts(zip_file_path);
output_folder = fullfile(s_dir, s_name);
unzip(zip_file_path, output_folder);

%% select the mat file
temp = dir(output_folder);
for m=1:length(temp)
   [~, ~, file_type] = fileparts(temp(m).name);
   if strcmpi(file_type, '.mat')
      matfile_name = fullfile(output_folder, temp(m).name);
   elseif strcmpi(file_type, '.txt')
       textfile_name = fullfile(output_folder, temp(m).name);
   end
end
if ~exist(matfile_name, 'file')
    error('no mat file in the selected zip file');
end

%% load mat file
load(matfile_name);

% check whether we used the same computer again
if exist(neuron.P.log_file, 'file')
    movefile(matfile_name, neuron.P.log_folder);
    movefile(textfile_name, neuron.P.log_file);
    rmdir(output_folder);
else
    original_log_folder = neuron.P.log_folder;
    original_logfile = neuron.P.log_file;
    neuron.P.log_folder = output_folder;
    neuron.P.log_file = textfile_name;
end

fprintf('The results have been loaded. \n');


function view = writeAnalyzeInTSeriesForm(view,scanList);
%
% view = writeAnalyzeInTSeriesForm(view,[scanList])
%
% Could be for either INPLANE or VOLUME
% Transform the analyze format images into time series format.
% By definition, each analyze image corresponds to one time
% frame and is a 3D matrix.
%
% scanList:
%   0 - do all scans
%   number or list of numbers - do only those scans
%   default - prompt user via selectScans dialog
%
% The user will identify, by GUI, where the source img files are, and where
% the tseries will be saved to.
%
% saveDir: if not given, then
%   ask a user to select a DataType or create a new DataType
%   save to 'Inplane/DataTypeName/TSeries_fromImgFiles/Scan*/TSeries*.mat'
%
% SPM Matlab toolbox required.
%
% MA, 10/18/2004. Based on ana2ts.m
% JL, 11/8/2004. Reorganize a little bit

mrGlobals;

% Choose the img file source
sourceChoice = questdlg('Where are the Analyze format Files in ?','choose source file','Current DataType','Other DataType','I Choose!','Current DataType');
switch sourceChoice;
    case 'Current DataType';
        curDataDir = dataDir(view);
    case 'Other DataType';
        %%%% Pop out menu to let user choose datatype.
        dtCount = size(dataTYPES,2);
        for i=1:dtCount; dtList{i} = dataTYPES(i).name; end;
        [selDataType,ok] = listdlg('ListString',dtList, 'SelectionMode','single', ...
            'InitialValue',curDataType, 'Name','Please, select a DataType:','ListSize', [300,200]);
        if ok;
            curDataDir = fullfile(viewGet(view,'subdir'),dtList{selDataType});
        end
    otherwise
        curDataDir = pwd;
end
% If no dir found, ask user to identify.
sourceDir = fullfile(curDataDir,'TSeries_imgFiles');
if ~exist(sourceDir,'dir') | strcmp(curDataDir,pwd);
    if ~strcmp(curDataDir,pwd); % which means the user did not choose 'I Choose!'
        disp('Warning: cannot find TSeries_imgFiles/ in the dataType.');
    end
    sourceDir = 0;
    while sourceDir == 0;     % Must choose one
        sourceDir = uigetdir(curDataDir,'Please choose the folder containing Scan* subfolders that have Analyze format files');
    end
end

% In the sourceDir, there must be folders Scan1, Scan2, ... Scan*
% (Re-)set scanList
if ~exist('scanList','var'); % User choose #scans
    scanList = selectScans(view,'Choose scans with IMG-files to Xform',sourceDir);
elseif scanList == 0 % all scans available
    [nScans, fileNames] = countDirs('Scan*',sourceDir);
    scanList = 1:nScans;
elseif ~isnumeric(scanList) | isempty(scanList)
    myErrorDlg('Xform aborted');
end

% Now, choose target save location
targetChoice = questdlg('Where to save the Xform tSeries?','choose save location','Current DataType','I Choose!','I Choose!');
switch targetChoice;
    case 'Current DataType';
        targetDir = tSeriesDir(view);
        disp('Warning: The old tSeries of this datatype will be overwritten.');
    otherwise
        targetDir = 0;
        while targetDir == 0;     % Must choose one
            targetDir = uigetdir(pwd,'Please choose the folder where Xform-ed time series is saved to');
        end
        disp('Warning: The Xform-ed time series may not match the scan params of current dataType.');
end

% current DataType params:
curDataType = viewGet(view,'currentDataType');
dtName = dataTYPES(curDataType).name;
scanParams = dataTYPES(curDataType).scanParams;

%select analyze files:
nScans = length(scanList);
for scanIndex=1:nScans
    scanNum = scanList(scanIndex);
    scanDir = ['Scan',int2str(scanNum)];
	sourcePath = fullfile(sourceDir,scanDir);
	targetPath = fullfile(targetDir,scanDir);

    %get files:
    files = dir(fullfile(sourcePath,'*.img'));
    for iList = 1:size(files);
        fName = files(iList).name;
        pat = '^\d+.img'; % must start with number and end with .img
        [s f tag] = regexp(lower(fName),pat);
        if ~isempty(s);
            seqNo = str2num(fName(1:end-4));
            F(seqNo+1,:) = fullfile(sourcePath,files(iList).name);
        end
    end
%    dpos=findstr(F(1,:),FILESEP);
%	sourcePath=F(1,1:dpos(end));

    if ~exist('F','var');
        myErrorDlg(['writeAnalyzeInTSeriesForm did not find any ', sourcePath, ' *.img files']);
    end;

    if scanIndex == 1
        msg = ['Saving TSeries Files for ',scanDir,' in ',targetPath];
        disp(msg);
        waitHandle = mrvWaitbar(0,[msg, '. Please wait...']);
    end

	%load volumes
	V = spm_vol(F);

    %check sizes. If mismatch, if user chose current datatype to save to, then error
    %and quit, but if user chose any location to save to, then just warning.
    errorString = {[]};
    if scanNum > length(scanParams);
        errorString{1} = ['Scan # exceeds the total number of scans in current dataType.']
    end
    params = scanParams(scanNum);
    if size(V) ~= params.nFrames;
        errorString{2} = ['Number of img-files does not match to Number of Frames for current dataType.'];
    end
    if V(1).dim(1:2) ~= params.cropSize;
        errorString{3} = ['cropSize in img-files does not match for current dataType.'];
    end
    if V(1).dim(3) ~= size(params.slices,2)
        errorString{4} = ['Number of Slices in img-files does not match for current dataType.'];
    end
    for ierror = 1:length(errorString);
        if ~isempty(errorString{ierror});
            if strcmp(targetChoice, 'Current DataType');
                myErrorDlg(errorString{ierror});
            else
                disp(['Warning!: ',errorString{ierror}]);
            end
        end
    end

    if ~exist(targetPath,'dir'); mkdir(targetDir,scanDir); end;

    %go through slices
    nSlices = V(1).dim(3);
	for slice=1:nSlices
        %get slice signal
        tSeries = [];
        C=[1 0 0 0;0 1 0 0;0 0 1 -slice;0 0 0 1];
        for it=1:size(V,1)
            temp = squeeze( spm_slice_vol(V(it),inv(C),V(it).dim(1:2),0) );
            tSeries(it,:) = temp(:)';
        end
        fileName = ['tSeries',num2str(slice),'.mat'];
        fprintf('Save slice %d in %s\n', slice, fullfile(targetPath,fileName));
        save(fullfile(targetPath,fileName),'tSeries');
        msg = [scanDir, ': saved slice in ', targetPath];
        mrvWaitbar((scanIndex-1+slice/nSlices)/nScans, waitHandle, msg);
	end
end

disp(['TSeries Files saved to ',targetDir]);
close(waitHandle);

return


function [mfile,idx]=get_mfile(obj, fn)
% get mfile either by name or by index
%
% [mfile,idx]=get_mfile(obj, fn)
%
% Inputs:
%   obj                 @MOcovMFileCollection instance
%   fn                  filename or integer
%
% Outputs:
%   mfile               @MOcovMFile that either has name fn (if fn is a
%                       string) or is the fn-th file (if fn is numeric)
%   idx                 index of mfile within obj
%

    if isnumeric(fn)
        lookup_func=@get_mfile_numeric;
    else
        lookup_func=@get_mfile_by_name;
    end

    [mfile,idx]=lookup_func(obj,fn);

function [mfile,idx]=get_mfile_numeric(obj,idx)
    mfile=obj.mfiles{idx};

function [mfile,idx]=get_mfile_by_name(obj,fn)
    root_dir=obj.root_dir;
    abs_fn=mocov_get_absolute_path(fullfile(root_dir,fn));

    mfiles=obj.mfiles;
    n=numel(mfiles);
    for k=1:n
        mfile=mfiles{k};
        mfile_fn=get_filename(mfile);
        if strcmp(mfile_fn, abs_fn)
            [mfile,idx]=get_mfile_numeric(obj,k);
            return;
        end
    end

    error('Not found: %s', fn);


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

%%
clear; close all; clc;

%% Syntax
% |L=isrounded(A);|

%% 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 sS = subSet(sS,ind)
% subindex vector3d

sS.b = sS.b(ind);
sS.l = sS.l(ind);
sS.u = sS.u(ind);

end


function batch_register_scans_with_struct_priors(baseScanFileNameC,...
    movScansFileNameC, basePriorStructNameC, movPriorStructNameC, ...
    movStrsToDeformC, movDoseToDeformC, registeredDir, paired_scans_flag)
% function batch_register_scans_with_struct_priors(baseScanFileNameC,...
%     movScansFileNameC, basePriorStructNameC, movPriorStructNameC, ...
%     strsToDeformC, registeredDir, paired_scans_flag)
%
% This script registers movScansFileNameC to baseScanFileNameC using
% basePriorStructNameC and movPriorStructNameC structure priors for initial alignment.
% Additionally, the structurnames specified in strsToDeformC are warped on to the base
% scan and the deformed images and segmwntation are written to registeredDir.
%
% APA, 12/30/2021

% RIDER template
% baseScan = '/lab/deasylab1/Data/RTOG0617/CERR_files_tcia/rider_template/RIDER-1225316081_First_resampled_1x1x3.mat';

% Directory containing CERR files
%movScanDir = '/lab/deasylab1/Data/RTOG0617/CERR_files_tcia/dose_mapping_original_plans'; % RTOG0617
%movScanDir = '/lab/deasylab1/Data/Lung_PORT/cerr_files'; % PORT
%movScanDir = '/lab/deasylab1/Maria/Heart_pCT_NSCLC/CERR/All_ph_1_pts_GTVcorrect/ATRIA_VENTR_PERI_DONE/N_241/0617structs_QAed_MT'; % OLD Conventional
% movScanDir = '/lab/deasylab1/Data/LA-NSCLC_Durva_N113/cerr_files_planning_only'; % NEW Conventional
%movScanDir = '/lab/deasylab1/Maria/Lung_EarlyStage_MSK_PFS_pCT_CT_PETCT/CERR_DCM_OMT_Validation/cerr_files_all_fx_corrected'; % MSK early stage Lung (fractionation corrected)

% Directory to write registered scans
%registeredDir = '/lab/deasylab1/Data/RTOG0617/registrations_pericardium/CERR_files_RTOG0617_to_RIDER_1225316081_First_template'; %RIDER RIDER-1225316081
%registeredDir = '/lab/deasylab1/Data/RTOG0617/registrations_pericardium/CERR_files_PORT_to_RIDER_1225316081_First_template'; %RIDER RIDER-1225316081
%registeredDir = '/lab/deasylab1/Data/RTOG0617/registrations_pericardium/CERR_files_OLD_CONVN_to_RIDER_1225316081_First_template'; %RIDER RIDER-1225316081
% registeredDir = '/lab/deasylab1/Data/RTOG0617/registrations_pericardium/CERR_files_NEW_CONVN_to_RIDER_1225316081_First_template'; %RIDER RIDER-1225316081
%registeredDir = '/lab/deasylab1/Data/RTOG0617/registrations_pericardium/CERR_files_MSK_EarlyStage_to_RIDER_1225316081_First_template'; % MSK early stage Lung (fractionation corrected)

if ~exist(registeredDir,'dir')
    mkdir(registeredDir)
end

% Filename to store dice scores
%diceSaveFileName = '/lab/deasylab1/Data/RTOG0617/registrations_pericardium/RTOG0617_peri_dice_RIDER.mat'; %RTOG0617
%diceSaveFileName = '/lab/deasylab1/Data/RTOG0617/registrations_pericardium/PORT_peri_dice_RIDER.mat'; %PORT
%diceSaveFileName ='/lab/deasylab1/Data/RTOG0617/registrations_pericardium/OLD_CONVN_peri_dice_RIDER.mat'; %OLD_CONVN
% diceSaveFileName ='/lab/deasylab1/Data/RTOG0617/registrations_pericardium/NEW_CONVN_peri_dice_RIDER.mat'; %NEW_CONVN
%diceSaveFileName = '/lab/deasylab1/Data/RTOG0617/registrations_pericardium/MSK_EarlyStage_peri_dice_RIDER.mat'; %EarlyStage
%
% strsToDeformC = {'DL_HEART_MT','DL_HEART','DL_AORTA', 'DL_LA', 'DL_LV', 'DL_RA', 'DL_RV', 'DL_IVC',...
%     'DL_SVC', 'DL_PA', 'DL_ATRIA', 'DL_PERICARDIUM', 'DL_VENTRICLES'};
% strsToDeformC = {'DL_HEART_MT','DL_PERICARDIUM'};
% strsToDeformC = {'DL_HEART','DL_PERICARDIUM'};

% movDirS = dir(movScanDir);
% movDirS([movDirS.isdir]) = [];
% movScanC = fullfile(movScanDir,{movDirS.name});

% registerToAtlasMultipleScans(baseScan,movScanC,registeredDir,...
%     strNameToWarp,initPlmCmdFile,refinePlmCmdFile)

%hpool = parpool(12);

% % Load base planC
% planC = loadPlanC(baseScan,tempdir);
% planC = updatePlanFields(planC);
% planC = quality_assure_planC(baseScan,planC);
% indexS = planC{end};
%
% % Generate mask by excluding GTV
% indTumor = findTumorIndex(1,planC);
% baseMask3M = [];
% if length(indTumor) == 1
%     baseMask3M = ~getStrMask(indTumor,planC);
% end
% strC = {planC{indexS.structures}.structureName};
% pericardInd = getMatchingIndex('DL_PERICARDIUM',strC,'exact');
% basePeriMask3M = getStrMask(pericardInd,planC);
% % [minr, maxr, minc, maxc, mins, maxs,baseMask3M] = compute_boundingbox(baseMask3M,3);
% se = strel('sphere',5);
% basePeriMaskDilate3M = imdilate(basePeriMask3M, se);
% diffPeriMask3M = xor(basePeriMaskDilate3M,basePeriMask3M);
% planC{indexS.scan}(1).scanArray(diffPeriMask3M) = 5000;

for iBase = 1:length(baseScanFileNameC)

    if paired_scans_flag
        movScansFileToRegisterC = movScansFileNameC(iBase);
        movStrsToDeformToUseC = movStrsToDeformC(iBase);
        movPriorStructNameToUseC = movPriorStructNameC(iBase);
        movDoseToDeformToUseC = movDoseToDeformC(iBase);
    else
        movScansFileToRegisterC = movScansFileNameC;
        movStrsToDeformToUseC = movStrsToDeformC;
        movPriorStructNameToUseC = movStructNameC;
        movDoseToDeformToUseC = movDoseToDeformC;
    end

    baseScan = baseScanFileNameC{iBase};

    % Load base planC
    planC = loadPlanC(baseScan,tempdir);
    planC = updatePlanFields(planC);
    planC = quality_assure_planC(baseScan,planC);
    indexS = planC{end};

    % Mask to restrict cost function
    baseMask3M = [];

    baseLandmarkStrC = basePriorStructNameC{iBase}; %{'DL_PERICARDIUM'};
    baseScanNum = 1;
    strBaseC = {planC{indexS.structures}.structureName};
    baseLandmarkListM = [];
    xyzBaseM = zeros(length(baseLandmarkStrC),3);
    for iStr = 1:length(baseLandmarkStrC)
        baseLandmarkStr = baseLandmarkStrC{iStr};
        strIndV = getMatchingIndex(baseLandmarkStr,strBaseC,'exact');
        assocScanNumV = getStructureAssociatedScan(strIndV,planC);
        baseLandmarkInd = strIndV(assocScanNumV == baseScanNum);
        [baseX,baseY,baseZ] = calcIsocenter(baseLandmarkInd,'COM',planC);
        xyzBaseV = [baseX,baseY,baseZ];
        xyzBaseM(iStr,:) = xyzBaseV;
        [xBaseV,yBaseV,zBaseV] = getScanXYZVals(planC{indexS.scan}(baseScanNum));
        baseY =  -yBaseV(1)+(yBaseV(1)-baseY);
        baseZ = -zBaseV(end) + zBaseV(end) - baseZ;
        baseLandmarkListM(iStr,:,1) = [iStr-1, [-baseX,-baseY,baseZ]*10];
    end

    allPlanC = {planC};

    for movNum = 1:length(movScansFileToRegisterC)

        movScanFileName = movScansFileToRegisterC{movNum};

        %[~,fName] = fileparts(movScanFileName);
        %newFileName = fullfile(registeredDir,[fName,'.mat']);
        %if exist(newFileName,'file')
        %    continue;
        %end

        try

            %     baseStrNumV = [];
            %     movStrNumV = [];

            %     % Load base planC
            %     planC = loadPlanC(baseScan,tempdir);
            %     planC = updatePlanFields(planC);
            %     planC = quality_assure_planC(baseScan,planC);
            %     indexS = planC{end};
            %
            %     % Generate mask by excluding GTV
            %     indTumor = findTumorIndex(1,planC);
            %     if length(indTumor) == 1
            %         baseMask3M = ~getStrMask(indTumor,planC);
            %     end

            % Load moving planC as planD
            planD = loadPlanC(movScanFileName,tempdir);
            planD = updatePlanFields(planD);
            planD = quality_assure_planC(movScanFileName,planD);
            indexSD = planD{end};

            % Register all image representations to each other starting from the
            % transformation generated previously
            %numScans = length(planC{indexS.scan});
            %     numScans = 1;
            %     allStrNumV = 1:length(planD{indexSD.structures}); % -1 to omit the "noise" structure
            %     assocScanV = getStructureAssociatedScan(allStrNumV,planD);
            %
            %     outBspFile = '';

            %inputCmdFile = '';
            %     numScans = 1;
            scanNumV = 1;
            for iScan = 1:length(scanNumV)

                scanNum = scanNumV(iScan);

                % Registration settings
                registration_tool = 'PLASTIMATCH';
                plmSettingsFile = '/lab/deasylab1/Data/RTOG0617/plastimatch_registration_settings/plm_reg_settings_with_landmark_stiffness_pericard.txt';
                %plmSettingsFile = '//vpensmph/deasylab1/Data/RTOG0617/plastimatch_registration_settings/plm_reg_settings_with_landmark_stiffness_pericard.txt';
                %plmSettingsFile = 'L:/Data/RTOG0617/plastimatch_registration_settings/plm_reg_settings_with_landmark_stiffness_pericard.txt';
                %baseMask3M = [];
                movMask3M = [];
                threshold_bone = -800;
                inBspFile = '';
                outBspFile = '';
                %tmpDirPath = '/lab/deasylab1/Data/RTOG0617/cerr_registration_temp_dir';
                tmpDirPath = '/cluster/home/aptea/segSessions/registration_temp';
                %tmpDirPath = '//vpensmph/deasylab1/Data/RTOG0617/cerr_registration_temp_dir';
                %tmpDirPath = 'L:/Data/RTOG0617/cerr_registration_temp_dir';
                algorithm = 'BSPLINE PLASTIMATCH';

                %         % Generate mask by excluding GTV
                %         indTumor = findTumorIndex(scanNum,planD);
                %         if length(indTumor) == 1
                %             movMask3M = ~getStrMask(indTumor,planD);
                %         end
                %         strC = {planD{indexSD.structures}.structureName};
                %         pericardInd = getMatchingIndex('DL_PERICARDIUM',strC,'exact');
                %         movPeriMask3M = getStrMask(pericardInd,planD);
                %         %         [minr, maxr, minc, maxc, mins, maxs,movMask3M] = compute_boundingbox(movMask3M,3);
                %         movPeriMaskDilate3M = imdilate(movPeriMask3M, se);
                %         diffPeriMask3M = xor(movPeriMaskDilate3M,movPeriMask3M);
                %         planD{indexSD.scan}(1).scanArray(diffPeriMask3M) = 5000;

                % Generate Landmarks
                movLandmarkStrC = movPriorStructNameToUseC{movNum}; %{'DL_PERICARDIUM'};

                % Register planD to planC
                baseScanNum = scanNum;
                movScanNum  = scanNum;
                %strBaseC = {planC{indexS.structures}.structureName};
                strMovC = {planD{indexSD.structures}.structureName};
                landmarkListM = [];
                xyzMovM = nan(length(movLandmarkStrC),3);
                for iStr = 1:length(movLandmarkStrC)
                    movLandmarkStr = movLandmarkStrC{iStr};
                    strIndV = getMatchingIndex(movLandmarkStr,strMovC,'exact');
                    assocScanNumV = getStructureAssociatedScan(strIndV,planD);
                    movLandmarkInd = strIndV(assocScanNumV == movScanNum);
                    if length(movLandmarkInd) ~= 1
                        continue;
                    end
                    [movX,movY,movZ] = calcIsocenter(movLandmarkInd,'COM',planD);
                    xyzMovV = [movX,movY,movZ];
                    xyzMovM(iStr,:) = xyzMovV;
                    [xMovV,yMovV,zMovV] = getScanXYZVals(planD{indexSD.scan}(movScanNum));
                    movY =  -yMovV(1)+(yMovV(1)-movY);
                    movZ = -zMovV(end) + zMovV(end) - movZ;
                    landmarkListM(iStr,:,1) = baseLandmarkListM(iStr,:,1);
                    landmarkListM(iStr,:,2) = [iStr-1, [-movX,-movY,movZ]*10];
                end

                % Don't use landmarks (update it to use landmarks in future)
                landmarkListM = [];

                %         initialTranslationXyzV = xyzMovV-xyzBaseV;
                initialTranslationXyzM = xyzMovM - xyzBaseM;
                initialTranslationXyzV = nanmean(initialTranslationXyzM,1);
                initialTranslationXyzV(1) = initialTranslationXyzV(1);
                initialTranslationXyzV(2) = -initialTranslationXyzV(2);
                initialTranslationXyzV(3) = -initialTranslationXyzV(3);

                plnC = allPlanC{1};

                % Call registration wrapper
                plnC = register_scans(plnC, baseScanNum, planD, movScanNum,...
                    algorithm, registration_tool, tmpDirPath, baseMask3M,...
                    movMask3M, threshold_bone, plmSettingsFile, inBspFile,...
                    outBspFile, landmarkListM,initialTranslationXyzV);

                strCreationScanNum = scanNum;

                % Warp scan (already warped in register_scans.m)
                deformS = plnC{indexS.deform}(end);
                %planC = warp_scan(deformS,movScanNum,planD,planC);

                strsToDeformC = movStrsToDeformToUseC{movScanNum};

                movStructNumsV = [];
                strNamC = {planD{indexSD.structures}.structureName};
                for iStr = 1:length(strsToDeformC)
                    movStructNumsV = [movStructNumsV,...
                        getMatchingIndex(strsToDeformC{iStr},strNamC,'exact')];
                end

                %planC = warp_structures(deformS,strCreationScanNum,movStructNumsV,planD,planC);
                plnC = warp_structures(deformS,strCreationScanNum,movStructNumsV,planD,plnC,tmpDirPath);

                doseCreationScanNum = strCreationScanNum;
%                 numDoses = length(planD{indexSD.dose});
                doseToDeformC = movDoseToDeformToUseC{movScanNum}; % update to get the correct dose num
                if ~isempty(doseToDeformC)
                    doseNum = length(planD{indexSD.dose});
                    %for doseNum = 1:numDoses
                    %planC = warp_dose(deformS,doseCreationScanNum,doseNum,planD,planC);
                    plnC = warp_dose(deformS,doseCreationScanNum,doseNum,planD,plnC,tmpDirPath);
                    %end
                end

                % delete the output nrrd file
                if strcmpi(algorithm,'DEMONS PLASTIMATCH')
                    delete(outBspFile)
                end

            end

            if exist(inBspFile,'file')
                delete(inBspFile)
            end

            % Save base and moving scans
            [~,fName] = fileparts(movScanFileName);
            newFileName = fullfile(registeredDir,fName);
            save_planC(plnC,[],'passed',newFileName);

        catch

        end % end try-catch

    end  % Iterate over moving scans

end % Iterate over base scans


function insertDCMDose(planC,dcmFileName)
%
%Insert dose from dcm file into the currently open planC.
%
% 11/07/2013
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

global stateS

if ~exist('planC','var')
    global planC
end
indexS = planC{end};

if ~exist('dcmFileName','var')
    [fileName, dirName] = uigetfile('*.dcm','Pick Dose file');
    dcmFileName = fullfile(dirName,fileName);
end

dcmInitFlag = init_ML_DICOM;
[dcmObj, isDcm] = scanfile_mldcm(dcmFileName);
dcmdirS = [];
if isDcm
    dcmdirS = dcmdir_add(dcmFileName, dcmObj, dcmdirS);
    dcmObj.clear;
else
    error('Invalid DICOM data')
end

% Read options file
pathStr = getCERRPath;
optName = [pathStr 'CERROptions.json'];
optS = opts4Exe(optName);

dataS = populate_planC_field('dose', dcmdirS.PATIENT,optS);

if ~isempty(planC{indexS.dose})
    planC{indexS.dose} = dissimilarInsert(planC{indexS.dose},dataS,length(planC{indexS.dose})+1);
else
    planC{indexS.dose} = dataS;
end

%Check dose-grid
doseNum = length(planC{indexS.dose});
for doseNum = 1:length(planC{indexS.dose})
    if planC{indexS.dose}(doseNum).zValues(2) - planC{indexS.dose}(doseNum).zValues(1) < 0
        planC{indexS.dose}(doseNum).zValues = flipud(planC{indexS.dose}(doseNum).zValues);
        planC{indexS.dose}(doseNum).doseArray = flipdim(planC{indexS.dose}(doseNum).doseArray,3);
    end
end

if isfield(stateS, 'CERRFile')
    stateS.doseSetChanged = 1;
    stateS.doseDisplayChanged = 1;
    stateS.doseSet = length(planC{indexS.dose});
    CERRRefresh
end

CERRStatusString('Done inserting dose.')


function handles = two_link_workcell_init(vrep,id)

handles = struct('id',id);

armJoints = -1*ones(2,1);
links = -1*ones(2,1);
forcesensor = -1;
for i=1:2
[res,armJoints(i)] = vrep.simxGetObjectHandle(id,['joint',num2str(i)],vrep.simx_opmode_oneshot_wait);vrchk(vrep, res);
[res,links(i)] = vrep.simxGetObjectHandle(id,['link',num2str(i)],vrep.simx_opmode_oneshot_wait);vrchk(vrep, res);
end
[res,forcesensor] = vrep.simxGetObjectHandle(id,'Force_sensor',vrep.simx_opmode_oneshot_wait);vrchk(vrep, res);
handles.armJoints = armJoints;
handles.links = links;
handles.forcesensor = forcesensor;

%% streaming
for i=1:2
vrep.simxGetJointPosition(id,armJoints(i),vrep.simx_opmode_streaming);vrchk(vrep, res, true);
vrep.simxGetObjectFloatParameter(id,armJoints(i),2012,vrep.simx_opmode_streaming);vrchk(vrep, res, true);
vrep.simxGetJointForce(id,armJoints(i),vrep.simx_opmode_streaming);vrchk(vrep, res, true);
end
vrep.simxReadForceSensor(id,forcesensor,vrep.simx_opmode_streaming);vrchk(vrep, res, true);
vrep.simxGetObjectOrientation(id,forcesensor,-1,vrep.simx_opmode_streaming);vrchk(vrep, res, true);
% Make sure that all streaming data has reached the client at least once
vrep.simxGetPingTime(id);
end