classdef ImdbDetectionFullSupervision < ImdbMatbox
    properties(SetAccess = protected, GetAccess = public)
        negOverlapRange = [0.1 0.5];
        boxesPerIm = 64;
        boxRegress = true;
        instanceWeighting = false;
        maxImageSize = 600;
    end
    methods
        function obj = ImdbDetectionFullSupervision(imageDir, imExt, matboxDir, filenames, datasetIdx, meanIm)
            obj@ImdbMatbox(imageDir, imExt, matboxDir, filenames, datasetIdx, meanIm);
        end

        function [batchData, numElements] = getBatch(obj, batchInds, net, ~)
            if length(batchInds) > 1
                error('Error: Only supports subbatches of 1!');
            end

            if nargin == 2
                gpuMode = false;
            else
                gpuMode = strcmp(net.device, 'gpu');
            end

            % Load image. Make correct size. Subtract average im.
            [image, oriImSize] = obj.LoadImage(batchInds, gpuMode);

            % Sample boxes
            gStruct = obj.LoadGStruct(batchInds);

            % Flip the image and boxes at training time
            % Note: flipLR alternates between true and false in ImdbMatbox.initEpoch()
            if obj.flipLR && strcmp(obj.datasetMode, 'train')
                currImT = fliplr(image);
                currBoxesT = gStruct.boxes;
                currBoxesT(:,3) = oriImSize(2) - gStruct.boxes(:,1) + 1;
                currBoxesT(:,1) = oriImSize(2) - gStruct.boxes(:,3) + 1;
                gStruct.boxes = currBoxesT;
                image = currImT;
            end

            if ismember(obj.datasetMode, {'train', 'val'})
                [boxes, labels, ~, overlapScores, regressionFactors] = obj.SamplePosAndNegFromGstruct(gStruct, obj.boxesPerIm);

                % Assign elements to cell array for use in training the network
                numElements = obj.boxesPerIm;

                numBatchFields = 2 * (4 + obj.boxRegress + obj.instanceWeighting);
                batchData = cell(numBatchFields, 1);
                idx = 1;
                batchData{idx} = 'input';       idx = idx + 1;
                batchData{idx} = image;         idx = idx + 1;
                batchData{idx} = 'label';       idx = idx + 1;
                batchData{idx} = labels';       idx = idx + 1;
                batchData{idx} = 'boxes';       idx = idx + 1;
                batchData{idx} = boxes';        idx = idx + 1;
                batchData{idx} = 'oriImSize';   idx = idx + 1;
                batchData{idx} = oriImSize;     idx = idx + 1;

                if obj.boxRegress
                    batchData{idx} = 'regressionTargets';   idx = idx + 1;
                    batchData{idx} = regressionFactors';    idx = idx + 1;
                end
                if obj.instanceWeighting
                    instanceWeights = overlapScores;
                    instanceWeights(labels == 1) = 1;
                    instanceWeights = reshape(instanceWeights, [1 1 1 length(instanceWeights)]); % VL-Feat way :-S
                    batchData{idx} = 'instanceWeights';     idx = idx + 1;
                    batchData{idx} = instanceWeights;       %idx = idx + 1;
                end

            else
                % Test set. Get all boxes
                numElements = size(gStruct.boxes,1);
                batchData{6} = oriImSize;
                batchData{5} = 'oriImSize';
                batchData{4} = gStruct.boxes';
                batchData{3} = 'boxes';
                batchData{2} = image;
                batchData{1} = 'input';
            end

        end

        function [image, oriImSize] = LoadImage(obj, batchIdx, gpuMode)
            % image = LoadImage(obj, batchIdx)
            % Loads an image from disk, resizes it, and subtracts the mean image
            imageT = single(imread([obj.imageDir obj.data.(obj.datasetMode){batchIdx} obj.imExt]));
            oriImSize = double(size(imageT));
            if numel(obj.meanIm) == 3
                for colourI = 1:3
                    imageT(:,:,colourI) = imageT(:,:,colourI) - obj.meanIm(colourI);
                end
            else
                imageT = imageT - imresize(obj.meanIm, [oriImSize(1) oriImSize(2)]); % Subtract mean im
            end

            % Resize image to be at most x pixels in each dimension
            % If you notice a "CUDA_ERROR_ILLEGAL_ADDRESS" error, use a
            % smaller maximum image size.
            resizeFactor = obj.maxImageSize / max(oriImSize(1:2));
            if gpuMode
                image = gpuArray(imageT);
                image = imresize(image, resizeFactor);
            else
                image = imresize(imageT, resizeFactor, 'bilinear', 'antialiasing', false);
            end
        end

        function [boxes, labels, keys, overlapScores, regressionTargets] = SamplePosAndNegFromGstruct(obj, gStruct, numSamples)
            % Get positive, negative, and true GT keys
            [maxOverlap, classOverlap] = max(gStruct.overlap, [], 2);

            posKeys = find(maxOverlap >= 0.5 & gStruct.class == 0);
            negKeys = find(maxOverlap < obj.negOverlapRange(2) & maxOverlap >= obj.negOverlapRange(1) & gStruct.class == 0);
            gtKeys = find(gStruct.class > 0);

            % Get correct number of positive and negative samples
            numExtraPos = numSamples * obj.posFraction - length(gtKeys);
            numExtraPos = min(numExtraPos, length(posKeys));
            if numExtraPos > 0
                posKeys = posKeys(randperm(length(posKeys), numExtraPos));
            else
               numExtraPos = 0;
            end
            numNeg = numSamples - numExtraPos - length(gtKeys);
            numNeg = min(numNeg, length(negKeys));
            negKeys = negKeys(randperm(length(negKeys), numNeg));

            % Concatenate for final keys and labs
            keys = cat(1, gtKeys, posKeys, negKeys);
            labels = cat(1, gStruct.class(gtKeys), classOverlap(posKeys), zeros(numNeg, 1));
            labels = single(labels + 1); % Add 1 for background class
            boxes = gStruct.boxes(keys,:);

            overlapScores = cat(1, ones(length(gtKeys),1), maxOverlap(posKeys), maxOverlap(negKeys));

            % Calculate regression targets.
            % Jasper: I simplify Girshick by implementing regression through four
            % scalars which scale the box with respect to its center.
            if nargout == 5
                % Create NaN array: nans represent numbers which will not be active
                % in regression
                regressionTargets = nan([size(boxes,1) 4 * obj.numClasses], 'like', boxes);

                % Get scaling factors for all positive boxes
                gtBoxes = gStruct.boxes(gtKeys,:);
                for bI = 1:length(gtKeys)+length(posKeys)
                    % Get current box and corresponding GT box
                    currPosBox = boxes(bI,:);
                    [~, gtI] = BoxBestOverlapFastRcnn(gtBoxes, currPosBox);
                    currGtBox = gtBoxes(gtI,:);

                    % Get range of regression target based on the label of the gt box
                    targetRangeBegin = 4 * (labels(bI)-1)+1;
                    targetRange = targetRangeBegin:(targetRangeBegin+3);

                    % Set regression targets
                    regressionTargets(bI, targetRange) = BoxRegressionTargetGirshick(currGtBox, currPosBox);
                end
            end
        end

        function SetBoxRegress(obj, doRegress)
            obj.boxRegress = doRegress;
        end

        function SetInstanceWeighting(obj, doInstanceWeighting)
            obj.instanceWeighting = doInstanceWeighting;
        end
    end % End methods
end % End classdef


function obj = updateIsosurface(obj, isoIndex)

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

	%-INITIALIZATIONS-%

	axIndex = obj.getAxisIndex(obj.State.Plot(isoIndex).AssociatedAxis);
	plotData = get(obj.State.Plot(isoIndex).Handle);
	axisData = get(plotData.Parent);
	[xSource, ySource] = findSourceAxis(obj, axIndex);

	%-update scene-%
	updateScene(obj, isoIndex)

	%-get mesh data-%
	xData = plotData.Vertices(:, 1);
	yData = plotData.Vertices(:, 2);
	zData = plotData.Vertices(:, 3);

	iData = plotData.Faces(:, 1) - 1;
	jData = plotData.Faces(:, 2) - 1;
	kData = plotData.Faces(:, 3) - 1;

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

	%-get trace-%
	obj.data{isoIndex}.type = 'mesh3d';
	obj.data{isoIndex}.name = plotData.DisplayName;
	obj.data{isoIndex}.showscale = false;

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

	%-set mesh data-%
	obj.data{isoIndex}.x = xData;
	obj.data{isoIndex}.y = yData;
	obj.data{isoIndex}.z = zData;

	obj.data{isoIndex}.i = iData;
	obj.data{isoIndex}.j = jData;
	obj.data{isoIndex}.k = kData;

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

	%-mesh coloring-%
	faceColor = getFaceColor(plotData, axisData);

	if iscell(faceColor)
		obj.data{isoIndex}.facecolor = faceColor;
	else
		obj.data{isoIndex}.color = faceColor;
	end

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

	%-lighting settings-%
	if ~strcmp(plotData.FaceLighting, 'flat')
		obj.data{isoIndex}.lighting.diffuse = plotData.DiffuseStrength;
		obj.data{isoIndex}.lighting.ambient = plotData.AmbientStrength;
		obj.data{isoIndex}.lighting.specular = plotData.SpecularStrength;
		obj.data{isoIndex}.lighting.roughness = 0.2;
		obj.data{isoIndex}.lighting.fresnel = 0.5;
		obj.data{isoIndex}.lighting.vertexnormalsepsilon = 1e-12;
		obj.data{isoIndex}.lighting.facenormalsepsilon = 1e-6;
	end

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

	%-associate scene to trace-%
	obj.data{isoIndex}.scene = sprintf('scene%d', xSource);

	%-------------------------------------------------------------------------%
end

function updateScene(obj, isoIndex)

	%-INITIALIZATIONS-%
	axIndex = obj.getAxisIndex(obj.State.Plot(isoIndex).AssociatedAxis);
	plotData = get(obj.State.Plot(isoIndex).Handle);
	axisData = get(plotData.Parent);
	[xSource, ySource] = findSourceAxis(obj, axIndex);
	scene = eval( sprintf('obj.layout.scene%d', xSource) );

	aspectRatio = axisData.PlotBoxAspectRatio;
	cameraPosition = axisData.CameraPosition;
	dataAspectRatio = axisData.DataAspectRatio;
	cameraUpVector = axisData.CameraUpVector;
	cameraEye = cameraPosition./dataAspectRatio;
	normFac = 0.5*abs(min(cameraEye));

	%-aspect ratio-%
	scene.aspectratio.x = aspectRatio(1);
	scene.aspectratio.y = aspectRatio(2);
	scene.aspectratio.z = aspectRatio(3);

	%-camera eye-%
	scene.camera.eye.x = cameraEye(1) / normFac;
    scene.camera.eye.y = cameraEye(2) / normFac;
    scene.camera.eye.z = cameraEye(3) / normFac;

    %-camera up-%
    scene.camera.up.x = cameraUpVector(1);
    scene.camera.up.y = cameraUpVector(2);
    scene.camera.up.z = cameraUpVector(3);

    %-camera projection-%
    % scene.camera.projection.type = axisData.Projection;

	%-scene axis configuration-%
	scene.xaxis.range = axisData.XLim;
	scene.yaxis.range = axisData.YLim;
	scene.zaxis.range = axisData.ZLim;

	scene.xaxis.zeroline = false;
	scene.yaxis.zeroline = false;
	scene.zaxis.zeroline = false;

	scene.xaxis.showline = true;
	scene.yaxis.showline = true;
	scene.zaxis.showline = true;

	scene.xaxis.ticklabelposition = 'outside';
	scene.yaxis.ticklabelposition = 'outside';
	scene.zaxis.ticklabelposition = 'outside';

	scene.xaxis.title = axisData.XLabel.String;
	scene.yaxis.title = axisData.YLabel.String;
	scene.zaxis.title = axisData.ZLabel.String;

	%-tick labels-%
	scene.xaxis.tickvals = axisData.XTick;
	scene.xaxis.ticktext = axisData.XTickLabel;
	scene.yaxis.tickvals = axisData.YTick;
	scene.yaxis.ticktext = axisData.YTickLabel;
	scene.zaxis.tickvals = axisData.ZTick;
	scene.zaxis.ticktext = axisData.ZTickLabel;

	scene.xaxis.tickcolor = 'rgba(0,0,0,1)';
	scene.yaxis.tickcolor = 'rgba(0,0,0,1)';
	scene.zaxis.tickcolor = 'rgba(0,0,0,1)';
	scene.xaxis.tickfont.size = axisData.FontSize;
	scene.yaxis.tickfont.size = axisData.FontSize;
	scene.zaxis.tickfont.size = axisData.FontSize;
	scene.xaxis.tickfont.family = matlab2plotlyfont(axisData.FontName);
	scene.yaxis.tickfont.family = matlab2plotlyfont(axisData.FontName);
	scene.zaxis.tickfont.family = matlab2plotlyfont(axisData.FontName);

	%-grid-%
	if strcmp(axisData.XGrid, 'off'), scene.xaxis.showgrid = false; end
	if strcmp(axisData.YGrid, 'off'), scene.yaxis.showgrid = false; end
	if strcmp(axisData.ZGrid, 'off'), scene.zaxis.showgrid = false; end

	%-SET SCENE TO LAYOUT-%
	obj.layout = setfield(obj.layout, sprintf('scene%d', xSource), scene);
end

function fillColor = getFaceColor(plotData, axisData)

	%-initializations-%
	faceColor = plotData.FaceColor;
	cData = plotData.CData;
	cLim = axisData.CLim;
	colorMap = axisData.Colormap;

	%-get face color depending of faceColor attribute
	if isnumeric(faceColor)
		numColor = 255 * faceColor;
		fillColor = sprintf('rgb(%f,%f,%f)', numColor);

	elseif strcmpi(faceColor, 'flat')
		fillColor = getStringColor(cData, colorMap, cLim);

    elseif strcmpi(faceColor, 'interp')
    	if size(cData, 1) ~= 1
    		for n = 1:size(cData, 2)
				fillColor{n} = getStringColor(mean(cData(:, n)), colorMap, cLim);
    		end
    	else
    		% TODO
    	end
	end
end

function stringColor = getStringColor(cData, colorMap, cLim)
	nColors = size(colorMap, 1);
	cIndex = max( min( cData, cLim(2) ), cLim(1) );
    scaleColor = (cIndex - cLim(1)) / diff(cLim);
    cIndex = 1 + floor(scaleColor*(nColors-1));
    numColor =  255 * colorMap(cIndex, :);
    stringColor = sprintf('rgb(%f,%f,%f)', numColor);
end


function [fid, tree, dir] = fiff_open_le(fname)
%
% [fid, tree, dir] = fiff_open_le(fname)
%
% Open a fif file and provide the directory of tags
%
% fid     the opened file id
% tree    tag directory organized into a tree
% dir     the sequential tag directory
%
% This is a modified version, specific for opening 'little endian' fiff files
% Arjen Stolk

%
%   Author : Matti Hamalainen, MGH Martinos Center
%   License : BSD 3-clause
%
%   Revision 1.7  2009/03/30 11:37:37  msh
%   Added copying of measurement info blocks from the original like in mne_browse_raw
%
%   Revision 1.6  2008/11/16 21:31:23  msh
%   Added mne_transform_coordinates and new coordinate frame definitions
%
%   Revision 1.5  2006/05/03 19:03:19  msh
%   Eliminated the use of cast function for Matlab 6.5 compatibility
%
%   Revision 1.4  2006/04/23 15:29:40  msh
%   Added MGH to the copyright
%
%   Revision 1.3  2006/04/18 20:44:46  msh
%   Added reading of forward solution.
%   Use length instead of size when appropriate
%
%   Revision 1.2  2006/04/17 15:01:34  msh
%   More small improvements.
%
%   Revision 1.1  2006/04/10 23:26:54  msh
%   Added fiff reading routines
%

global FIFF;
if isempty(FIFF)
    FIFF = fiff_define_constants();
end

me='MNE:fiff_open';
verbose=false;
fid = fopen_or_error(fname,'rb','ieee-le'); % Arjen Stolk: this is 'ieee-be' in fiff_open.m

%
%   Check that this looks like a fif file
%
tag = fiff_read_tag_info(fid);
if tag.kind ~= FIFF.FIFF_FILE_ID
    ft_error(me,'file does not start with a file id tag');
end
if tag.type ~= FIFF.FIFFT_ID_STRUCT
    ft_error(me,'file does not start with a file id tag');
end
if tag.size ~= 20
    ft_error(me,'file does not start with a file id tag');
end
tag = fiff_read_tag(fid);
if tag.kind ~= FIFF.FIFF_DIR_POINTER
    ft_error(me,'file does have a directory pointer');
end
if nargout == 1
    fseek(fid,0,'bof');
    return;
end
%
%   Read or create the directory tree
%
if verbose
    fprintf(1,'\tCreating tag directory for %s...',fname);
end
dirpos = double(tag.data);
if dirpos > 0
    tag = fiff_read_tag(fid,dirpos);
    dir = tag.data;
else
    k = 0;
    fseek(fid,0,'bof');
    dir = struct('kind',{},'type',{},'size',{},'pos',{});
    while tag.next >= 0
        pos = ftell(fid);
        tag = fiff_read_tag_info(fid);
        k = k + 1;
        dir(k).kind = tag.kind;
        dir(k).type = tag.type;
        dir(k).size = tag.size;
        dir(k).pos  = pos;
    end
end
%
%   Create the directory tree structure
%
tree = fiff_make_dir_tree(fid,dir);
if verbose
    fprintf(1,'[done]\n');
end
%
%   Back to the beginning
%
fseek(fid,0,'bof');
return;


classdef ImdbFCN < ImdbCalvin
    % ImdbFCN
    %
    % Standard Imdb for FCN experiments.
    %
    % Copyright by Holger Caesar, 2016

    properties
        % Set in constructor
        dataset

        batchOpts = struct();
    end
    methods
        function obj = ImdbFCN(dataset, dataDir, nnOpts)
            % Call default constructor
            obj = obj@ImdbCalvin();
            obj.dataset = dataset;

            % FCN-specific
            obj.batchOpts.imageSize = [512, 512] - 128;
            obj.batchOpts.labelStride = 1;

            obj.batchOpts.imageFlipping = true;
            obj.batchOpts.rgbMean = single([128; 128; 128]);
            obj.batchOpts.classWeights = [];
            obj.batchOpts.imageNameToLabelMap = @(imageName) obj.dataset.getImLabelMap(imageName);
            obj.batchOpts.translateLabels = false;
            obj.batchOpts.maskThings = false;

            obj.batchOpts.useInvFreqWeights = false;

            % Dataset-specific
            obj.batchOpts.vocAdditionalSegmentations = true;
            obj.batchOpts.vocEdition = '11';
            obj.batchOpts.dataDir = dataDir;

            % Load VOC-style IMDB
            obj.loadImdb(nnOpts);
        end

        function loadImdb(obj, nnOpts)
            % loadImdb(obj, nnOpts)
            %
            % Creates or load the current VOC-style IMDB.

            %%% VOC specific
            if strStartsWith(obj.dataset.name, 'VOC')
                % Get PASCAL VOC segmentation dataset plus Berkeley's additional segmentations
                imdbPath = fullfile(nnOpts.expDir, 'imdbVoc.mat');
                if exist(imdbPath, 'file')
                    % Load imdbVoc
                    load(imdbPath, 'imdbVoc', 'rgbStats');
                else
                    imdbVoc = vocSetup('dataDir', obj.batchOpts.dataDir, ...
                        'edition', obj.batchOpts.vocEdition, ...
                        'includeTest', false, ...
                        'includeSegmentation', true, ...
                        'includeDetection', false);
                    if obj.batchOpts.vocAdditionalSegmentations
                        imdbVoc = vocSetupAdditionalSegmentations(imdbVoc, 'dataDir', obj.batchOpts.dataDir);
                    end
                    rgbStats = getDatasetStatistics(imdbVoc);

                    save(imdbPath, 'imdbVoc', 'rgbStats');
                end
                obj.batchOpts = structOverwriteFields(obj.batchOpts, imdbVoc);

                obj.batchOpts.rgbMean = rgbStats.rgbMean;
                obj.batchOpts.rgbMean = reshape(obj.batchOpts.rgbMean, [1 1 3]);
                obj.batchOpts.translateLabels = true;
                obj.batchOpts.imageNameToLabelMap = @(imageName) imread(sprintf(obj.batchOpts.paths.classSegmentation, imageName));
            else
                %%% Other datasets
                % Get labels and image path
                obj.batchOpts.classes.name = obj.dataset.getLabelNames();
                obj.batchOpts.paths.image = fullfile(obj.dataset.getImagePath(), sprintf('%%s%s', obj.dataset.imageExt));

                % Get trn + tst/val images
                imageListTrn = obj.dataset.getImageListTrn();
                imageListTst = obj.dataset.getImageListTst();

                % Remove images without labels
                missingImageIndicesTrn = obj.dataset.getMissingImageIndices('train');
                imageListTrn(missingImageIndicesTrn) = [];
                % TODO: is it a good idea to remove test images?
                % (only doing it on non-competitive EdiStuff
                if isa(obj.dataset, 'EdiStuffDataset') || isa(obj.dataset, 'EdiStuffSubsetDataset')
                    missingImageIndicesTst = obj.dataset.getMissingImageIndices('test');
                    imageListTst(missingImageIndicesTst) = [];
                end
                imageCountTrn = numel(imageListTrn);
                imageCountTst = numel(imageListTst);

                obj.batchOpts.images.name = [imageListTrn; imageListTst];
                obj.batchOpts.images.segmentation = true(imageCountTrn+imageCountTst, 1);
                obj.batchOpts.images.set = nan(imageCountTrn+imageCountTst, 1);
                obj.batchOpts.images.set(1:imageCountTrn) = 1;
                obj.batchOpts.images.set(imageCountTrn+1:end) = 2;

                obj.batchOpts.rgbMean = obj.dataset.getMeanColor();
                obj.batchOpts.rgbMean = reshape(obj.batchOpts.rgbMean, [1 1 3]);
                obj.batchOpts.translateLabels = false;
                obj.batchOpts.imageNameToLabelMap = @(imageName) obj.dataset.getImLabelMap(imageName);
            end

            % Specify level of supervision for each train image
            if ~nnOpts.misc.weaklySupervised
                % Full supervision
                obj.batchOpts.images.isFullySupervised = true(numel(obj.batchOpts.images.name), 1);
            elseif ~semiSupervised
                % Weak supervision
                obj.batchOpts.images.isFullySupervised = false(numel(obj.batchOpts.images.name), 1);
            else
                % Semi supervision: Set x% of train and all val to true
                obj.batchOpts.images.isFullySupervised = true(numel(obj.batchOpts.images.name), 1);
                if isa(obj.dataset, 'EdiStuffDataset')
                    selWS = find(~ismember(obj.batchOpts.images.name, obj.dataset.datasetFS.getImageListTrn()));
                    assert(numel(selWS) == 18431);
                else
                    selTrain = find(obj.batchOpts.images.set == 1);
                    selTrain = selTrain(randperm(numel(selTrain)));
                    selWS = selTrain((selTrain / numel(selTrain)) >= semiSupervisedRate);
                end
                obj.batchOpts.images.isFullySupervised(selWS) = false;

                if nnOpts.misc.semiSupervisedOnlyFS
                    % Keep x% of train and all val
                    selFS = obj.batchOpts.images.isFullySupervised(:) | obj.batchOpts.images.set(:) == 2;
                    obj.batchOpts.images.name = obj.batchOpts.images.name(selFS);
                    obj.batchOpts.images.set = obj.batchOpts.images.set(selFS);
                    obj.batchOpts.images.segmentation = obj.batchOpts.images.segmentation(selFS);
                    obj.batchOpts.images.isFullySupervised = obj.batchOpts.images.isFullySupervised(selFS);

                    if strStartsWith(obj.dataset.name, 'VOC')
                        obj.batchOpts.images.id = obj.batchOpts.images.id(selFS);
                        obj.batchOpts.images.classification = obj.batchOpts.images.classification(selFS);
                        obj.batchOpts.images.size = obj.batchOpts.images.size(:, selFS);
                    end
                end
            end

            % Make sure val images are always fully supervised
            obj.batchOpts.images.isFullySupervised(obj.batchOpts.images.set == 2) = true;

%             % Print overview of the fully and weakly supervised number of training
%             % images
%             fsCount = sum( obj.batchOpts.images.isFullySupervised(:) & obj.batchOpts.images.set(:) == 1);
%             wsCount = sum(~obj.batchOpts.images.isFullySupervised(:) & obj.batchOpts.images.set(:) == 1);
%             fsRatio = fsCount / (fsCount+wsCount);
%             wsRatio = 1 - fsRatio;
%             fprintf('Images in train: %d FS (%.1f%%), %d WS (%.1f%%)...\n', fsCount, fsRatio * 100, wsCount, wsRatio * 100);

            % Get training and test/validation subsets
            % We always validate and test on val
            trainInds = find(obj.batchOpts.images.set == 1 & obj.batchOpts.images.segmentation);
            valInds   = find(obj.batchOpts.images.set == 2 & obj.batchOpts.images.segmentation);
            obj.data.train = obj.batchOpts.images.name(trainInds); %#ok<FNDSB>
            obj.data.val   = obj.batchOpts.images.name(valInds); %#ok<FNDSB>
            obj.data.train = obj.data.train(:);
            obj.data.val   = obj.data.val(:);

            % Dataset-independent imdb fields
            obj.numClasses = obj.dataset.labelCount;
        end

        function[inputs, numElements] = getBatch(obj, batchIdx, net, nnOpts)
            % [inputs, numElements] = getBatch(obj, batchIdx, net, nnOpts)
            %
            % Returns a single image, its labels and boxes to be used as a sub-batch in training, validation or testing.
            % Note: Currently train and val batches are treated the same.
            %
            % Copyright by Holger Caesar, 2015

            % Check inputs
            assert(~isempty(obj.datasetMode));
            assert(numel(batchIdx) == 1);
            imageCount = numel(batchIdx);
            imageIdx = batchIdx;

            % Check settings
            assert(~isempty(obj.batchOpts.rgbMean));

            % Determine whether testing
            testMode = strcmp(obj.datasetMode, 'test');

            % Init labels
            if ~testMode
                lx = 1 : obj.batchOpts.labelStride : obj.batchOpts.imageSize(2);
                ly = 1 : obj.batchOpts.labelStride : obj.batchOpts.imageSize(1);
                labels = zeros(numel(ly), numel(lx), 1, imageCount, 'double'); % must be double for to avoid numerical precision errors in vl_nnloss, when using many classes
                if nnOpts.misc.weaklySupervised
                    labelsImageCell = cell(imageCount, 1);
                end
                if nnOpts.misc.maskThings
                    assert(isa(obj.dataset, 'EdiStuffDataset'));
                    datasetIN = ImageNetDataset();
                end
                masksThingsCell = cell(imageCount, 1); % by default this is empty
            end

            % Get image
            if true
                % Get image
                imageName = obj.data.(obj.datasetMode){imageIdx};
                imageOri = single(obj.dataset.getImage(imageName)) * 255;

                if ~testMode
                    image = zeros(obj.batchOpts.imageSize(1), obj.batchOpts.imageSize(2), 3, imageCount, 'single');

                    % Crop and rescale image
                    h = size(imageOri, 1);
                    w = size(imageOri, 2);
                    sz = obj.batchOpts.imageSize(1 : 2);
                    scale = max(h / sz(1), w / sz(2));
                    scale = scale .* (1 + (rand(1) - .5) / 5);
                    sy = round(scale * ((1:sz(1)) - sz(1)/2) + h/2);
                    sx = round(scale * ((1:sz(2)) - sz(2)/2) + w/2);

                    % Flip image
                    if obj.batchOpts.imageFlipping && rand > 0.5
                        sx = fliplr(sx);
                    end

                    % Get image indices in valid area
                    okx = find(1 <= sx & sx <= w);
                    oky = find(1 <= sy & sy <= h);
                    image(oky, okx, :, 1) = imageOri(sy(oky), sx(okx), :);
                else
                    image = imageOri;

                    % Workaround: Limit image size to avoid running out of RAM
                    maxImSize = 700;
                    if ~isempty(maxImSize),
                        maxSize = max(size(image, 1), size(image, 2));
                        if maxSize > maxImSize,
                            factor = maxImSize / maxSize;
                            image = imresize(image, factor);
                        end;
                    end;

                    % Some networks requires the image to be a multiple of 32 pixels
                    imageNeedsToBeMultiple = true;
                    if imageNeedsToBeMultiple
                        sz = [size(image, 1), size(image, 2)];
                        sz = round(sz / 32) * 32;
                        image = imresize(image, sz);
                    end
                end

                % Subtract mean image
                image = bsxfun(@minus, image, obj.batchOpts.rgbMean);
            end

            % Get labels
            if true
                % Fully supervised: Get pixel level labels
                if ~testMode
                    % Get pixel-level GT
                    if obj.dataset.annotation.hasPixelLabels || obj.batchOpts.images.isFullySupervised(imageIdx)
                        anno = uint16(obj.batchOpts.imageNameToLabelMap(imageName));

                        % Translate labels s.t. 255 is mapped to 0
                        if obj.batchOpts.translateLabels,
                            % Before: 255 = ignore, 0 = bkg, 1:n = classes
                            % After : 0 = ignore, 1 = bkg, 2:n+1 = classes
                            anno = mod(anno + 1, 256);
                        end
                        % 0 = ignore, 1:n = classes
                    else
                        anno = [];
                    end

                    if ~isempty(anno)
                        tlabels = zeros(sz(1), sz(2), 'double');
                        tlabels(oky,okx) = anno(sy(oky), sx(okx));
                        tlabels = single(tlabels(ly, lx));
                        labels(:, :, 1, 1) = tlabels; % 0: ignore
                    end
                end

                if ~testMode
                    % Weakly supervised: extract image-level labels
                    if nnOpts.misc.weaklySupervised
                        if ~isempty(anno) && ~all(anno(:) == 0)
                            % Get image labels from pixel labels
                            % These are already translated (if necessary)
                            curLabelsImage = unique(anno);
                        else
                            curLabelsImage = obj.dataset.getImLabelInds(imageName);

                            % Translate labels s.t. 255 is mapped to 0
                            if obj.batchOpts.translateLabels
                                curLabelsImage = mod(curLabelsImage + 1, 256);
                            end

                            if obj.dataset.annotation.labelOneIsBg
                                % Add background label
                                curLabelsImage = unique([0; curLabelsImage(:)]);
                            end
                        end

                        % Remove invalid pixels
                        curLabelsImage(curLabelsImage == 0) = [];

                        % Store image-level labels
                        labelsImageCell{1} = single(curLabelsImage(:));
                    end
                end

                % Optional: Mask out thing pixels
                if ~testMode
                    if nnOpts.misc.maskThings
                        % Get mask
                        longName = datasetIN.shortNameToLongName(imageName);
                        mask = datasetIN.getImLabelBoxesMask(longName);

                        % Resize it if necessary
                        if size(mask, 1) ~= size(image, 1) || ...
                                size(mask, 2) ~= size(image, 2)
                            mask = imresize(mask, [size(image, 1), size(image, 2)]);
                        end
                        masksThingsCell{1} = mask;
                    end
                end
            end

            % Extract inverse class frequencies from dataset
            if ~testMode
                if obj.batchOpts.useInvFreqWeights,
                    if nnOpts.misc.weaklySupervised,
                        classWeights = obj.dataset.getLabelImFreqs('train');
                    else
                        classWeights = obj.dataset.getLabelPixelFreqs('train');
                    end

                    % Inv freq and normalize classWeights
                    classWeights = classWeights ./ sum(classWeights);
                    nonEmpty = classWeights ~= 0;
                    classWeights(nonEmpty) = 1 ./ classWeights(nonEmpty);
                    classWeights = classWeights ./ sum(classWeights);
                    assert(~any(isnan(classWeights)));
                else
                    classWeights = [];
                end
                obj.batchOpts.classWeights = classWeights;
            end

            % Move image to GPU
            if strcmp(net.device, 'gpu')
                image = gpuArray(image);
            end

            % Store in output struct
            inputs = {'input', image};
            if ~testMode
                %TODO: fix imageIdx relative to subset
                if obj.dataset.annotation.hasPixelLabels || obj.batchOpts.images.isFullySupervised(imageIdx)
                    inputs = [inputs, {'label', double(labels)}];  % has to be double to avoid problems in loss
                end
                if nnOpts.misc.weaklySupervised
                    assert(~any(cellfun(@(x) isempty(x), labelsImageCell)));
                    inputs = [inputs, {'labelsImage', labelsImageCell}];
                end

                % Instance/pixel weights, can be left empty
                inputs = [inputs, {'classWeights', obj.batchOpts.classWeights}];

                % Decide which level of supervision to pick
                if nnOpts.misc.semiSupervised
                    % SS
                    isWeaklySupervised = ~obj.batchOpts.images.isFullySupervised(imageIdx);
                else
                    % FS or WS
                    isWeaklySupervised = nnOpts.misc.weaklySupervised;
                end
                inputs = [inputs, {'isWeaklySupervised', isWeaklySupervised}];
                inputs = [inputs, {'masksThingsCell', masksThingsCell}];
            end
            numElements = 1; % One image
        end

        function[allBatchInds] = getAllBatchInds(obj)
            % Obtain the indices and ordering of all batches (for this epoch)

            batchCount = numel(obj.data.(obj.datasetMode));
            if strcmp(obj.datasetMode, 'train')
                allBatchInds = randperm(batchCount)';
            elseif strcmp(obj.datasetMode, 'val'),
                allBatchInds = (1:batchCount)';
            elseif strcmp(obj.datasetMode, 'test'),
                allBatchInds = (1:batchCount)';
            else
                error('Error: Unknown datasetMode!');
            end
        end

        function initEpoch(obj, epoch)
            % Call default method
            initEpoch@ImdbCalvin(obj, epoch);
        end
    end
end


function view=initDataValsSlider(view,curDVIndex)
%
%       view=initDataValsSlider(view,[curDVIndex])
%
% Installs the slider and text box that control the current datavals .
% The slider is placed on the mid-left, under the datavals control slider.
%
% The first time through, the callback and related textbox are installed
%
% It is also called repeatedly as dataTypes or FFTCheckBox are switched to re-display
%   the slider that represents datavals information
%
% ARW Wrote it 030606:
% Based on BW's initScanSlider

% The sliderHandle always exists because it is created in openXXWindow
% Set the step size for clicking on the arrows and the trough
sliderHandle = view.ui.datavals.sliderHandle;

nDataVals=numDataVals(view); % This looks at dataTYPES and also FFTCheckBox to see if we're currently displaying FFT or Time-domain data
if nDataVals < 2
    %   Can't have a slider value of 1.  Sorry.
    nDataVals=2;
    set(sliderHandle,'Enable','off');
else
    set(sliderHandle,'Enable','on');
end

% By setting the max to a little more than nDataValss, we should
% never quite reach it by clicking the arrow or the trough
set(sliderHandle,'Min',1,'Max',nDataVals);

% Clicking an arrow moves by an amount (max - min)*sliderstep(1)
% Cllicking in the trough moves by an amount (max - min)*sliderstep(2)
% setSlider traps any values == to the max value and queries the user
%    this is a cheap way of setting a value by hand.
sliderStep(1) = 1/(nDataVals - 1);
sliderStep(2) = 2*sliderStep(1);
set(sliderHandle,'sliderStep',sliderStep);

% If we are first opening the window, create the text box.
if ~isfield(view.ui.datavals,'textHandle')
    % Can this be inside the if below so that it only happens
	% when the window is first opened?
	% djh, 9/5/01
	callBackStr = ...
        ['val = get(',view.name,'.ui.datavals.sliderHandle,''value'');'...
            'val = round(val);'...
            'setSlider(',view.name,',',view.name,'.ui.datavals,val);'...
            view.name '=setCurDataValIndex(',view.name,',val);'...
            view.name,'=refreshScreen(',view.name,');'];
	set(sliderHandle,'CallBack',callBackStr);

   % Position the text box to the right of the slider
   pos = get(sliderHandle,'Position');
   l2 = pos(1) + pos(3) + .01;
   w2 = pos(3)/4; b = pos(2); h = pos(4);
   position = [l2 b w2 h];

   view.ui.datavals.textHandle = ...
      uicontrol('Style','text',...
      'Units','normalized',...
      'Position',position);
end

% This text tells the user how many datavals indices there are
% in the current dataType and domain.  Here, we set the value
%
str = sprintf('%.0f',nDataVals);
set(view.ui.datavals.textHandle,'String',str);

% Synchronize the curScan with the slider state
%

if (~isfield(view,'dataValIndex'))
    view = setCurDataValIndex(view,1);
end

if ~exist('curDataValIndex','var')
   curDataValIndex = getCurDataValIndex(view);
end

if curDataValIndex > numDataVals(view)
    curDataValIndex = 1;
end
setSlider(view,view.ui.datavals,curDataValIndex);
view = setCurDataValIndex(view,curDataValIndex);

% ras 08/05: make the scan slider update the curScan field as well:
cb = 'val=str2num(get(gcbo,''String'')); ';
cb = [cb sprintf('%s=setCurDataValIndex(%s,val); ',view.name,view.name)];
cb = [cb sprintf('%s=refreshScreen(%s);',view.name,view.name)];
set(view.ui.datavals.labelHandle,'Callback',cb);

return


% MatrixUser, a multi-dimensional matrix analysis software package
% https://sourceforge.net/projects/matrixuser/
%
% The MatrixUser is a matrix analysis software package developed under Matlab
% Graphical User Interface Developing Environment (GUIDE). It features
% functions that are designed and optimized for working with multi-dimensional
% matrix under Matlab. These functions typically includes functions for
% multi-dimensional matrix display, matrix (image stack) analysis and matrix
% processing.
%
% Author:
%   Fang Liu <leoliuf@gmail.com>
%   University of Wisconsin-Madison
%   Aug-30-2014

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

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

% Last Modified by GUIDE v2.5 18-Sep-2013 17:17:55

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

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

% --- Executes just before MU_Load_DICOM_File is made visible.
function MU_Load_DICOM_File_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% varargin   command line arguments to MU_Load_DICOM_File (see VARARGIN)

%MatrixUser logo
MU_marks(handles.Matrix_preview_axes,'MatrixUser');

set(handles.File_list,'String',varargin{4});
set(handles.File_list,'Max',max(size(varargin{4})));
handles.pathname=varargin{5};

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

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes MU_Load_DICOM_File wait for user response (see UIRESUME)
% uiwait(handles.MU_load_DICOM_file);

% --- Outputs from this function are returned to the command line.
function varargout = MU_Load_DICOM_File_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);

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

% --- Executes on selection change in File_list.
function File_list_Callback(hObject, eventdata, handles)

% Hints: contents = get(hObject,'String') returns File_list contents as cell array
%        contents{get(hObject,'Value')} returns selected item from File_list

contents=get(handles.File_list,'String');
if ischar(contents)
        filename=[handles.pathname contents];
else
        selected_files=contents(get(handles.File_list,'Value'));
        filename=[handles.pathname selected_files{1}];
end
try
    info=dicominfo(filename);
    dicom_image=dicomread(filename);
catch me
    warndlg([char(39) filename char(39) ' is not in DICOM format.']);
    return;
end

% dicom_image=double(dicom_image);
set(gcf,'CurrentAxes',handles.Matrix_preview_axes);
imagesc(dicom_image);
colormap gray;
axis off;          % Remove axis ticks and numbers
axis image;        % Set aspect ratio to obtain square pixels

cstr=MU_readStruct(info);
set(handles.DICOM_header_list,'String',cstr);

% --- Executes during object creation, after setting all properties.
function File_list_CreateFcn(hObject, eventdata, handles)

% Hint: listbox controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in File_check_button.
function File_check_button_Callback(hObject, eventdata, handles)

contents=get(handles.File_list,'String');
if iscell(contents)
    selected_files=contents(get(handles.File_list,'Value'));
    set(handles.Selected_file_list,'String',selected_files);
    set(handles.Selected_file_list,'Max',max(size(selected_files)));
else
    selected_files=contents;
    set(handles.Selected_file_list,'String',selected_files);
    set(handles.Selected_file_list,'Max',1);
end

% --- Executes on button press in File_uncheck_button.
function File_uncheck_button_Callback(hObject, eventdata, handles)

if ~isempty(get(handles.Selected_file_list,'String'))
    contents=get(handles.Selected_file_list,'String');
    if iscell(contents)
        ind=get(handles.Selected_file_list,'Value');
        contents(ind)=[];
        set(handles.Selected_file_list,'String',contents);
    else
        set(handles.Selected_file_list,'String',[]);
    end
end
set(handles.Selected_file_list,'Value',1);

% --- Executes on selection change in Selected_file_list.
function Selected_file_list_Callback(hObject, eventdata, handles)

% Hints: contents = get(hObject,'String') returns Selected_file_list contents as cell array
%        contents{get(hObject,'Value')} returns selected item from Selected_file_list

% --- Executes during object creation, after setting all properties.
function Selected_file_list_CreateFcn(hObject, eventdata, handles)

% Hint: listbox controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in DICOM_convert_button.
function DICOM_convert_button_Callback(hObject, eventdata, handles)

contents=get(handles.Selected_file_list,'String');

set(handles.DICOM_convert_button,'Enable','off');
set(handles.File_uncheck_button,'Enable','off');
set(handles.File_check_button,'Enable','off');
set(handles.Load_matrix_button,'Enable','off');
set(handles.Edit_matrix_name,'Enable','off');
[created_matrix,created_matrix_name,errflag]=MU_DICOM2Mat(contents,handles.pathname,handles);
set(handles.DICOM_convert_button,'Enable','on');
set(handles.File_uncheck_button,'Enable','on');
set(handles.File_check_button,'Enable','on');
set(handles.Load_matrix_button,'Enable','on');
set(handles.Edit_matrix_name,'Enable','on');

if errflag==1
    return;
elseif errflag==0
    handles.created_matrices.(created_matrix_name)=created_matrix;
    set(handles.Created_matrix_list,'String',fieldnames(handles.created_matrices));

end
guidata(hObject, handles);

% --- Executes during object creation, after setting all properties.
function Created_matrix_list_CreateFcn(hObject, eventdata, handles)

% Hint: listbox controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes during object creation, after setting all properties.
function Edit_matrix_name_CreateFcn(hObject, eventdata, handles)

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in Load_matrix_button.
function Load_matrix_button_Callback(hObject, eventdata, handles)

if ~isfield(handles,'created_matrices')
    errordlg('No matrix was created!');
    return;
end
if isempty(handles.created_matrices)
    errordlg('No matrix was created!');
    return;
end

created_matrix_name=fieldnames(handles.created_matrices);
for i=1:max(size(created_matrix_name))
    MU_load_matrix(created_matrix_name{i}, handles.created_matrices.(created_matrix_name{i}),0);
end

MU_load_DICOM_file_CloseRequestFcn(hObject, eventdata, handles);

% --- Executes when user attempts to close MU_load_DICOM_file.
function MU_load_DICOM_file_CloseRequestFcn(hObject, eventdata, handles)

delete(handles.MU_load_DICOM_file);

% Hint: delete(hObject) closes the figure
% delete(hObject);

% --- Executes during object creation, after setting all properties.
function DICOM_header_list_CreateFcn(hObject, eventdata, handles)
% hObject    handle to DICOM_header_list (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: listbox controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function Edit_matrix_name_Callback(hObject, eventdata, handles)
% hObject    handle to Edit_matrix_name (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of Edit_matrix_name as text
%        str2double(get(hObject,'String')) returns contents of Edit_matrix_name as a double


classdef LaunchVehicleViewProfileRefFrameData < matlab.mixin.SetGet
    %LaunchVehicleViewProfileUserRefFrameData Summary of this class goes here
    %   Detailed explanation goes here

    properties
        %these are for vehicle trajectory data and not the point itself!
        timesArr(1,:) cell = {};
        xInterps(1,:) cell = {};
        yInterps(1,:) cell = {};
        zInterps(1,:) cell = {};
        vxInterps(1,:) cell = {};
        vyInterps(1,:) cell = {};
        vzInterps(1,:) cell = {};

        markerPlot = matlab.graphics.GraphicsPlaceholder.empty(1,0)
        refFrame AbstractGeometricRefFrame
        viewFrame AbstractReferenceFrame
    end

    methods
        function obj = LaunchVehicleViewProfileRefFrameData(refFrame, viewFrame)
            obj.refFrame = refFrame;
            obj.viewFrame = viewFrame;
        end

        function addData(obj, times, rVects, vVects)
            obj.timesArr(end+1) = {times};

            if(length(times) >= 3)
                method = 'pchip';
            else
                method = 'linear';
            end

            obj.xInterps{end+1} = griddedInterpolant(times, rVects(:,1), method, 'linear');
            obj.yInterps{end+1} = griddedInterpolant(times, rVects(:,2), method, 'linear');
            obj.zInterps{end+1} = griddedInterpolant(times, rVects(:,3), method, 'linear');
            obj.vxInterps{end+1} = griddedInterpolant(times, vVects(:,1), method, 'linear');
            obj.vyInterps{end+1} = griddedInterpolant(times, vVects(:,2), method, 'linear');
            obj.vzInterps{end+1} = griddedInterpolant(times, vVects(:,3), method, 'linear');
        end

        function plotRefFrameAtTime(obj, time, hAx)
            for(i=1:length(obj.timesArr))
                times = obj.timesArr{i};

                if(time >= min(floor(times)) && time <= max(ceil(times)))
                    xInterp = obj.xInterps{i};
                    x = xInterp(time);

                    yInterp = obj.yInterps{i};
                    y = yInterp(time);

                    zInterp = obj.zInterps{i};
                    z = zInterp(time);

                    vxInterp = obj.vxInterps{i};
                    vx = vxInterp(time);

                    vyInterp = obj.vyInterps{i};
                    vy = vyInterp(time);

                    vzInterp = obj.vzInterps{i};
                    vz = vzInterp(time);

                    vehElemSet = CartesianElementSet(time, [x;y;z], [vx;vy;vz], obj.viewFrame);
                    [posOffsetOrigin, ~, ~, rotMatToInertial] = obj.refFrame.getRefFrameAtTime(time, vehElemSet, obj.viewFrame);

                    scaleFactor = obj.refFrame.scaleFactor;
                    xAxis = [posOffsetOrigin(:), posOffsetOrigin(:) + rotMatToInertial(:,1)*scaleFactor];
                    yAxis = [posOffsetOrigin(:), posOffsetOrigin(:) + rotMatToInertial(:,2)*scaleFactor];
                    zAxis = [posOffsetOrigin(:), posOffsetOrigin(:) + rotMatToInertial(:,3)*scaleFactor];

                    if(isempty(obj.markerPlot))
                        hold(hAx,'on');
                        obj.markerPlot(end+1) = plot3(hAx, xAxis(1,:), xAxis(2,:), xAxis(3,:), 'Color',obj.refFrame.xAxisColor.color, 'LineWidth',obj.refFrame.xAxisLineWidth, 'LineStyle',obj.refFrame.xAxisLineSpec.linespec);
                        obj.markerPlot(end+1) = plot3(hAx, yAxis(1,:), yAxis(2,:), yAxis(3,:), 'Color',obj.refFrame.yAxisColor.color, 'LineWidth',obj.refFrame.yAxisLineWidth, 'LineStyle',obj.refFrame.yAxisLineSpec.linespec);
                        obj.markerPlot(end+1) = plot3(hAx, zAxis(1,:), zAxis(2,:), zAxis(3,:), 'Color',obj.refFrame.zAxisColor.color, 'LineWidth',obj.refFrame.zAxisLineWidth, 'LineStyle',obj.refFrame.zAxisLineSpec.linespec);
                        hold(hAx,'off');
                    else
                        obj.markerPlot(1).XData = xAxis(1,:);
                        obj.markerPlot(1).YData = xAxis(2,:);
                        obj.markerPlot(1).ZData = xAxis(3,:);

                        obj.markerPlot(2).XData = yAxis(1,:);
                        obj.markerPlot(2).YData = yAxis(2,:);
                        obj.markerPlot(2).ZData = yAxis(3,:);

                        obj.markerPlot(3).XData = zAxis(1,:);
                        obj.markerPlot(3).YData = zAxis(2,:);
                        obj.markerPlot(3).ZData = zAxis(3,:);
                    end
                end
            end
        end
    end
end


function y = horzcat(varargin)
    % Horizontal concatenation for sym arrays.
    %   C = HORZCAT(A, B, ...) horizontally concatenates the symbolic
    %   variable arrays A, B, ... .  For matrices, all inputs must have the
    %   same number of rows.
    %
    %   C = HORZCAT(A,B) is called for the syntax [A B].
    %
    %   See also VERTCAT.

    % Call the superclass method
    str = horzcat@SymExpression(varargin{:});

    % create a new object with the evaluated string
    y = SymVariable(str);

end


function [tSnrImageArray, fileTsnrArray, ...
            tSnrRatioImageArray, fileTsnrRatioArray ] = ...
    tapas_physio_compute_tsnr_gains(physio, SPM, indexContrastForSnrRatio, ...
    namesPhysContrasts)
% Computes tSNR gains through physiological noise correction for all
% confound regressor sets modelled, after estimation of the SPM-GLM
%
%   [fileTsnrGainArray, fileTsnrArray] = ...
%           tapas_physio_compute_tsnr_gains(physio, SPM, doSave);
%
%
% IN
%   physio      physio-structure (or filename with structure), after estimating multiple_regressors.txt
%   SPM         SPM variable (or filename with saved structure)
%               after estimation of general linear model (GLM)
%   indexContrastForSnrRatio
%               contrast id for comparison to get relative tSNR values
%               default: 0 (raw time series after filtering/pre-whitening)
% OUT
%   fileTsnrGainArray
%               cell(nPhysioSets,1) of nii-filenames holding tSNR gain
%               images for all physiological regressor sets (in percent?)
%
%   fileTsnrArray
%               cell(nPhysioSets+1,1) of nii-filenames for tSNR images of
%               for all physiological regressor sets
%               and, as last element, raw tSNR (after preprocessing)
% EXAMPLE
%   tapas_physio_compute_tsnr_gains
%
%   See also tapas_physio_compute_tsnr_spm spm_write_residuals

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

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   0. Check variable structure, cast for convenience
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin < 3
    indexContrastForSnrRatio = 0; % contrast for comparison
end

if nargin < 4
    namesPhysContrasts = tapas_physio_get_contrast_names_default();
end

% load physio-variable, if filename given
if ~isstruct(physio)
    % load SPM variable from file
    if iscell(physio)
        filePhysio = physio{1};
    else
        filePhysio = physio;
    end
    load(filePhysio, 'physio');
end

% load SPM-variable, if filename given
if ~isstruct(SPM)
    % load SPM variable from file
    if iscell(SPM)
        fileSpm = SPM{1};
    else
        fileSpm = SPM;
    end
    load(fileSpm, 'SPM');
end

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 1. Determine which physiological contrasts could be created with existing
% model and create the missing ones
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

SPM = tapas_physio_create_missing_physio_contrasts(SPM, physio.model, ...
    namesPhysContrasts);

nContrasts = numel(namesPhysContrasts);

%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 2. Compute tSNR maps via tapas_physio_compute_tsnr_spm, as follows
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

tSnrImageArray = cell(nContrasts,1);
fileTsnrArray = cell(nContrasts,1);
tSnrRatioImageArray = cell(nContrasts,1);
fileTsnrRatioArray = cell(nContrasts,1);

for c = 1:nContrasts
    % First try, whether inverted contrast already exists, then no
    % additional computation has to be performed!
    indContrast = tapas_physio_check_get_xcon_index(SPM, ...
        ['All but: ' namesPhysContrasts{c}]);
    doComputeInvertedContrast = indContrast == 0; % not found, do invert
    doSaveNewContrasts = doComputeInvertedContrast; % and save contrasts for later
    if doComputeInvertedContrast % find contrast before inversion
        indContrast = tapas_physio_check_get_xcon_index(SPM, ...
            namesPhysContrasts{c});
    end

    if indContrast > 0
        % if contrast exist, compute tSNR and save it!
        [tSnrImageArray{c}, fileTsnrArray{c}, ...
            tSnrRatioImageArray{c}, fileTsnrRatioArray{c}] = ...
            tapas_physio_compute_tsnr_spm(SPM, indContrast, ...
            indexContrastForSnrRatio, doComputeInvertedContrast, doSaveNewContrasts);

        % rename files for better human readability
        filenameSfx = regexprep(namesPhysContrasts{c}, ' ', '_');
        fileTsnrOld = fileTsnrArray{c};
        fileTsnrArray{c} = regexprep(fileTsnrArray{c}, ...
            sprintf('con%04d', indContrast), filenameSfx);

        fileTsnrRatioOld = fileTsnrRatioArray{c};
        fileTsnrRatioArray{c} = regexprep(fileTsnrRatioArray{c}, ...
            sprintf('con%04dvs%04d', indContrast, indexContrastForSnrRatio), ...
            [filenameSfx '_vs_Raw']);

        movefile(fileTsnrOld, fileTsnrArray{c});
        movefile(fileTsnrRatioOld, fileTsnrRatioArray{c});
    end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create JSON using MATLAB for MEG BIDS:
%
% This template is for MEG data of any kind,
% including but not limited to task-based, resting-state, and noise recordings.
%
% If multiple Tasks were performed within a single Run,
% the task description can be set to "task-multitask".
%
% The _meg.json SHOULD contain details on the Tasks.
%
% Some manufacturers data storage
% conventions use folders which contain data files of various nature:
% for example: CTF's .ds format, or 4D/BTi.
%
% Please refer to Appendix VI for examples from a selection of MEG manufacturers
%
% By @Cofficer, Created 9/03/2018
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Writing json files relies on the JSONio library
% https://github.com/bids-standard/bids-matlab
%
% Make sure it is in the matab/octave path
try
    bids.bids_matlab_version;
catch
    warning('%s\n%s\n%s\n%s', ...
            'Writing the JSON file seems to have failed.', ...
            'Make sure that the following library is in the matlab/octave path:', ...
            'https://github.com/bids-standard/bids-matlab');
end

clear;

this_dir = fileparts(mfilename('fullpath'));
root_dir = fullfile(this_dir, '..', filesep, '..');

project = 'templates';

sub_label = '01';
ses_label = '01';
task_label = 'FullExample';
acq_label = 'CTF';
run_label = '1';

% A "proc" (processed) label has been added, especially useful for files coming from Maxfilter
% (for example: sss, tsss, trans, quat, mc, etc.)
proc_label = 'sss';

name_spec.modality = 'meg';
name_spec.suffix = 'meg';
name_spec.ext = '.json';
name_spec.entities = struct('sub', sub_label, ...
                            'acq', acq_label, ...
                            'ses', ses_label, ...
                            'task', task_label, ...
                            'run', run_label, ...
                            'proc', proc_label);

% using the 'use_schema', true
% ensures that the entities will be in the correct order
bids_file = bids.File(name_spec, 'use_schema', true);

% Contrust the fullpath version of the filename
json_name = fullfile(root_dir, project, bids_file.bids_path, bids_file.filename);

%% Adding metadata
% Assign the fields in the Matlab structure that can be saved as a json.
% The following fields must be defined:

% to get the definition of each metadata,
% you can use the bids.Schema class from bids matlab
% For example
schema = bids.Schema;
def = schema.get_definition('TaskName');
fprintf(def.description);

json.TaskName = task_label;
json.InstitutionName = '';
json.InstitutionAddress = '';
json.Manufacturer = '';
json.ManufacturersModelName = '';
json.SoftwareVersions = '';
json.TaskDescription = '';
json.Instructions = '';
json.CogPOID = 'http://www.cogpo.org/ontologies/CogPOver1.owl#FIXME';
json.DeviceSerialNumber = '';

%%
% The following MEG specific fields must also be defined:
json.SamplingFrequency = '';
json.PowerLineFrequency = '';
json.DewarPosition = '';
json.SoftwareFilters = '';
json.DigitizedLandmarks = '';

json.DigitizedHeadPoints = '';

%%
% The following fields should be present for MEG:
json.MEGChannelCount = [];
json.MEGREFChannelCount = [];
json.EEGChannelCount = [];
json.ECOGChannelCount = [];
json.SEEGChannelCount = [];
json.EOGChannelCount = [];
json.ECGChannelCount = [];
json.EMGChannelCount = [];
json.MiscChannelCount = [];
json.TriggerChannelCount = [];
json.RecordingDuration = [];
json.RecordingType = '';
json.EpochLength = '';
json.ContinuousHeadLocalization = '';
json.HeadCoilFrequency = [];
json.MaxMovement = '';
json.SubjectArtefactDescription = '';
json.AssociatedEmptyRoom = '';

%%
% Specific EEG fields if recorded with MEG
% SHOULD be present:
json.EEGSamplingFrequency = [];
json.EEGPlacementScheme = '';
json.ManufacturersAmplifierModelName = '';
json.EEGReference = '';

%% Write JSON
% Make sure the directory exists
bids.util.mkdir(fileparts(json_name));
bids.util.jsonencode(json_name, json);


function svgOffset(s, source, offset, result)
% Adds a feOffset SVG filter
% PRELIMINARY IMPLEMENTATION (Parameters may change)
%
% svgOffset(s, source, offset, result)
% Parameters:
%   s : Array of plot object handles
%   source : Any previous defined filter result string, 'SourceGraphic',
%            or 'SourceAlpha'.
%   offset : Offset value [x y]
%   result : String that identifies the filter result for following filter
%            stages.
for i = 1:length(s)
    userdata = get(s(i),'UserData');
    if isfield(userdata, 'svg') && isfield(userdata.svg, 'Filter')
        next = length(userdata.svg.Filter) + 1;
    else
        next = 1;
    end
    userdata.svg.Filter(next).Subfilter.Type = 'feOffset';
    userdata.svg.Filter(next).Subfilter.Source = source;
    userdata.svg.Filter(next).Subfilter.Offset = offset;
    userdata.svg.Filter(next).Subfilter.Result = result;
    set(s(i),'UserData', userdata);
end


function outarg = meshAngle(command, name, V);
%
% outarg = meshAngle([command], [name of angle], [Volume View]);
%
% Load/Save camera angles for viewing a mesh from canonical views.
% Angles are stored in the same directory as the mesh, in the file
% 'MeshAngles.mat'. These can be saved/restored for any meshes in that
% directory, so if both right and left hemishpheres are saved, it
% might be good to name it something like 'lateral-right' or
% 'dorsolateral-left'.
%
% Volume view: view w/ the mesh attached. [defaults to selected gray]
% command: 'load', 'save', or 'list'. [defaults to 'list']
% name: name of the mesh to save.
%
% Returns a different output argument depending on the command:
%   'list': returns a struct containing the saved angles. (If meshAngle is
%   called as meshAngle(V, 'list', 'quiet'), will only return in the
%   struct and not print to the command window.)
%   'load': returns the cRot value loaded.
%   'save': returns the path of the save file.
%
% Example: meshAngle(getSelectedGray, 'save', 'ventral') saves
% the view under the name 'ventral';
% meshAngle(getSelectedGray, 'load', 'ventral') restores it.
% meshAngle(getSelectedGray, 'list') lists the saved angles for this
% mesh, if any.
%
% ras, 10/2005.
if ieNotDefined('V'), V = getSelectedGray; end
if ieNotDefined('command'), command = 'list'; end

mesh = viewGet(V, 'mesh');

anatPath = getVAnatomyPath;
meshDir = fullfile(fileparts(anatPath), 'Meshes');

switch lower(command)
    case 'load',
        % get angles (and perform file check while we're at it)
        angles = meshAngle('list', 'quiet', V);
        angleNames = {angles.name};

        % if no name specified, get from dialog
        if ieNotDefined('name')
            dlg.fieldName = 'name';
            dlg.style = 'listbox';
            dlg.string = 'Load which angle?';
            dlg.list = angleNames;
            dlg.value = 1;
            resp = generaldlg2(dlg,'Load Camera Angle...');
            name = resp.name{1};
        end

        % check that the named angle has been stored in the file
        I = cellfind(angleNames, lower(name));
        if isempty(I)
            fprintf('Angle %s not found. Saved angles include:\n',name);
            for i = 1:length(angleNames)
                fprintf('%s \n', angleNames{i});
            end
            error('Selected angle not found');
        else
            cRot = angles(I).cRot;
            mrmSet(mesh,'camerarotation',cRot);
        end

        outarg = cRot;

    case 'save',
        cRot = mrmGet(mesh,'camerarotation');

        % if no name specified, get from dialog.
        if ieNotDefined('name')
            name = inputdlg({'Name of Angle to Save:'},...
                    'Save Camera Angle...',1,{'angle1'});
            if isempty(name{1}), return; end  % user canceled
            name = lower(name{1});
        end

        % load any angles that may exist.
        pth = fullfile(meshDir, 'MeshAngles.mat');
        if exist(pth,'file'),
            load(pth,'angles');
            angles(end+1).name = lower(name);
        else
            angles.name = lower(name);
        end
        angles(end).cRot = cRot;
        angles(end).saved = datestr(clock);

        % save the angles.
        if exist(pth,'file')
            save(pth,'angles','-append');
        else
            save(pth,'angles')
        end
        fprintf('Saved camera rotation as angles(%i) in %s.\n',...
                length(angles),pth);

        outarg = pth;

    case 'list',
        % check if the Angles.mat file exists
        pth = fullfile(meshDir, 'MeshAngles.mat');
        if ~exist(pth, 'file')
            msg = sprintf(['No angles have been stored for ' ...
                           'this segmentation: %s.'], mesh.path);
            myWarnDlg(msg);
            angles = [];
            return
        else
            load(pth,'angles');
        end

        if ieNotDefined('name') | ~isequal(lower(name),'quiet')
            disp('***********************')
            disp('Angles Saved: ')
            for i = 1:length(angles)
                fprintf('%s \n', angles(i).name);
            end
            disp('***********************')
        end

        outarg = angles;

    otherwise, help(mfilename); warning('Unknown command');
end

return


function options = dsdpset(varargin)
%DSDPSET  Create or alter the options for Optimization with DSDP
%
% options = dsdpset('param1',value1,'param2',value2,...) creates an DSDP
% options structure with the parameters 'param' set to their corresponding
% values in 'value'. Parameters not specified will be set to the DSDP
% default.
%
% options = dsdpset(oldopts,'param1',value1,...) creates a copy of the old
% options 'oldopts' and then fills in (or writes over) the parameters
% specified by 'param' and 'value'.
%
% options = dsdpset() creates an options structure with all fields set to
% dsdpset defaults.
%
% dsdpset() prints a list of all possible fields and their function.
%
% See supplied DSDP Documentation for further details of these options.

%   Copyright (C) 2013 Jonathan Currie (I2C2)

% Print out possible values of properties.
if (nargin == 0) && (nargout == 0)
    printfields();
    return
end
%Names and Defaults
Names = {'drho';'rpos';'r0';'penalty';'rho';'dbound';'gaptol';'rtol';'mu0';'maxtrust';...
         'steptol';'ptol';'pnormtol';'reuse';'zbar';'dlbound';'ybound';'fixed'};
Defaults = {1;0;-1;1e8;5;1e20;1e-7;1e-6;-1;1e10;0.05;1e-4;1e30;4;[];[];[];[]};

%Enter and check user args
try
    options = opticheckset(Names,Defaults,@checkfield,varargin{:});
catch ME
    throw(ME);
end

function checkfield(field,value)
%Check a field contains correct data type
switch lower(field)
    %Scalar double
    case {'r0','penalty','rho','mu0','dbound','pnormtol','zbar','dlbound','ybound'}
        err = opticheckval.checkScalarDbl(value,field);
    %Scalar non negative double
    case {'rtol','ptol','maxtrust','gaptol','steptol'}
        err = opticheckval.checkScalarNonNeg(value,field);
    %Scalar 0/1
    case {'rpos','drho'}
        err = opticheckval.checkScalar01(value,field);
    %Scalar non-negative integer
    case 'reuse'
        err = opticheckval.checkScalarIntNonNeg(value,field);
    %Double column vector
    case 'fixed'
        err = opticheckval.checkDualCol(value,field);
    otherwise
        err = MException('OPTI:SetFieldError','Unrecognized parameter name ''%s''.', field);
end
if(~isempty(err)), throw(err); end

function printfields()
%Print out fields with defaults
fprintf('          rpos: [ Use Penalty Parameter to enforce Feasibility {0}, 1 ] \n');
fprintf('          drho: [ Use Dynamic Strategy to choose Rho: 0, {1} ] \n');
fprintf('            r0: [ Set initial value for variable r in Dual {-1} ] \n');
fprintf('       penalty: [ Penalty Parameter Gamma {1e8} \n');
fprintf('           rho: [ Potential Parmater: {5} ] \n');
fprintf('           mu0: [ Barrier Parameter: {-1} ] \n');
fprintf('          rtol: [ Classify Dual as feasible if r is less than this tolerance: {1e-6} ] \n');
fprintf('          ptol: [ Classify Primal as feasible if infeasibility is less than this tolerance: {1e-4} ] \n');
fprintf('      maxtrust: [ Maximum Trust Radius on Step Direction: {1e10} ] \n');
fprintf('        gaptol: [ Convergence Gap Tolerance: {1e-7} ] \n');
fprintf('       steptol: [ Terminate solver if step length in Dual is below this tolerance: {0.05} ] \n');
fprintf('        dbound: [ Terminate solver if Dual Objective greater than this Value {1e20} ] \n');
fprintf('      pnormtol: [ Terminate the solver when duality gap is sufficiently small and pnorm is less than this quantity: {1e30} ] \n');
fprintf('         reuse: [ Number of times the Hessian of the Barrier Function will be reused {4} ] \n');
fprintf('          zbar: [ Upper bound on objective value at the solution {[]} ] \n');
fprintf('       dlbound: [ Lower bound on dual value {[]} ] \n');
fprintf('        ybound: [ Bound on the dual variables y {[]} ] \n');
fprintf('         fixed: [ Matrix of fixed variables, column 1 variable indices, column 2, fixed values {[]} ] \n');
fprintf('\n');


function [sx,dsdx,dsdP] = sparsify(x,P)
% legacy code
s = warning ('on');
warning ('*** The function `sparsify` is now deprecated. Please see `VBA_sparsifyPrior` for an alternative.')
warning (s);

% fallback
[sx,dsdx,dsdP]  = VBA_sparsifyPrior(x, P);


function OutputFiles = bst_project_grid(ResultsFiles, iSubjectDest, isInteractive)
% BST_PROJECT_GRID: Project volume-based source files the template (files must have been computed from a template grid).
%
% USAGE:  OutputFiles = bst_project_grid(ResultsFiles, iSubjectDest=[group], isInteractive=1)
%
% INPUT:
%    - ResultsFiles  : Relative path to sources file to project
%    - iSubjectDest  : Index of destination subject (by default: "Group analysis")
%    - isInteractive : If 1, displays questions and dialog boxes
%                      If 0, consider it is running from a process (no user interactions)

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2016

% ===== INITIALIZATION ======
% Parse inputs
if (nargin < 3) || isempty(isInteractive)
    isInteractive = 1;
end
if (nargin < 2) || isempty(iSubjectDest)
    [sSubjectDest, iSubjectDest] = bst_get('NormalizedSubject');
else
    sSubjectDest = bst_get('Subject', iSubjectDest);
end
OutputFiles = {};
errMsg = [];
isFirstWarning = 1;

% ===== GET DESTINATION SUBJECT =====
% Check for errors
if isempty(sSubjectDest) || isempty(sSubjectDest.Anatomy) || isempty(sSubjectDest.iAnatomy)
    errMsg = 'Cannot get destination subject.';
    ResultsFiles = [];
end
% Get destination MRI
MriFileDest = sSubjectDest.Anatomy(sSubjectDest.iAnatomy).FileName;
sMriDest = in_mri_bst(MriFileDest);
if isempty(sMriDest) || ~isfield(sMriDest, 'NCS') || ((~isfield(sMriDest.NCS, 'R') || isempty(sMriDest.NCS.R)) && (~isfield(sMriDest.NCS, 'y') || isempty(sMriDest.NCS.y)))
    errMsg = 'You should compute the MNI normalization for the destination MRI first.';
    ResultsFiles = [];
end

% ===== PROJECT FILES =====
iUpdatedStudies = [];
% Progress bar
bst_progress('start', 'Project sources', 'Projecting files...', 0, length(ResultsFiles));
% Loop on input source files
for iRes = 1:length(ResultsFiles)
    % === GET SOURCE SUBJECT ===
    % Find file in database
    [sStudySrc, iStudySrc, iFile, DataType] = bst_get('AnyFile', ResultsFiles{iRes});
    if isempty(sStudySrc)
        errMsg = ['File is not resgistered in database: ' ResultsFiles{iRes}];
        break;
    end
    % Get corresponding subject
    [sSubjectSrc, iSubjectSrc] = bst_get('Subject', sStudySrc.BrainStormSubject);
    if isempty(sSubjectSrc) || isempty(sSubjectSrc.Anatomy) || isempty(sSubjectSrc.iAnatomy)
        errMsg = 'Cannot get source subject.';
        break;
    elseif (iSubjectSrc == iSubjectDest)
        errMsg = 'Source and destination anatomies are the same: nothing ot project.';
        break;
    end
    % Get destination MRI
    MriFileSrc = sSubjectSrc.Anatomy(sSubjectSrc.iAnatomy).FileName;
    sMriSrc = in_mri_bst(MriFileSrc);
    if isempty(sMriSrc) || ~isfield(sMriSrc, 'NCS') || ((~isfield(sMriSrc.NCS, 'R') || isempty(sMriSrc.NCS.R)) && (~isfield(sMriSrc.NCS, 'y') || isempty(sMriSrc.NCS.y)))
        errMsg = 'You should compute the MNI normalization for the source MRI first.';
        ResultsFiles = [];
        break;
    end

    % === LOAD SOURCE FILE ===
    switch (DataType)
        case 'timefreq'
            % Load file
            ResultsMat = in_bst_timefreq(ResultsFiles{iRes}, 1);
            ResFile = ResultsFiles{iRes};
            % Check the data type: timefreq must be source/surface based, and no kernel-based file
            if ~strcmpi(ResultsMat.DataType, 'results')
                errMsg = 'Only source results can be projected.';
                break;
            end
            % Get source model type
            if isfield(ResultsMat, 'HeadModelType') && ~isempty(ResultsMat.HeadModelType)
                % Nothing to do
            elseif ~isempty(ResultsMat.DataFile)
                % Load related source file
                [AssociateMat,AssociateFile] = in_bst_results(ResultsMat.DataFile, 0, 'HeadModelType', 'HeadModelFile');
                ResultsMat.HeadModelType = AssociateMat.HeadModelType;
                ResultsMat.HeadModelFile = AssociateMat.HeadModelFile;
            else
                % By default: volume
                ResultsMat.HeadModelType = 'volume';
            end
            % Remove link to parent file
            ResultsMat.DataFile = [];
            ResultsMat.SurfaceFile = [];
        case {'results', 'link'}
            % Load file
            [ResultsMat, ResFile] = in_bst_results(ResultsFiles{iRes}, 1);
            % If it depends on the data file: try to use the comment of the data file
            if ~isempty(ResultsMat.DataFile) && strcmpi(file_gettype(ResultsMat.DataFile), 'data')
                % Find parent file in database
                [sStudy, iStudy, iData] = bst_get('DataFile', ResultsMat.DataFile);
                % If file was found: use its comment
                if ~isempty(sStudy) && ~isempty(sStudy.Data(iData).Comment)
                    ResultsMat.Comment = sStudy.Data(iData).Comment;
                end
            end
            % Unconstrained sources: Make a flat map
            if (ResultsMat.nComponents ~= 1)
                ResultsMat = process_source_flat('Compute', ResultsMat);
            end
            % Remove link to parent file
            ResultsMat.DataFile = [];
            ResultsMat.ChannelFlag = [];
            ResultsMat.GoodChannel = [];
            ResultsMat.SurfaceFile = [];
            ResultsMat.SourceDecompSa = [];
            ResultsMat.SourceDecompVa = [];
    end

    % Check source model type
    if strcmpi(ResultsMat.HeadModelType, 'surface')
        errMsg = 'To process surface-based source maps, use function bst_project_sources.m instead.';
        break;
    elseif strcmpi(ResultsMat.HeadModelType, 'mixed')
        errMsg = 'Mixed head models are not supported yet.';
        break;
    elseif ~isfield(ResultsMat, 'GridLoc') || isempty(ResultsMat.GridLoc)
        errMsg = ['No field "GridLoc" in the file to project.' 10 'To process surface-based source maps, use function bst_project_sources.m instead.'];
        break;
    end
    % Remove link to parent file
    if isfield(ResultsMat, 'DataFile') && ~isempty(ResultsMat.DataFile)
        ResultsMat.DataFile = [];
    end

    % === GET EXISTING GROUP COORDINATES ===
    GridLoc = [];
    SurfaceFile = [];
    isDestGroup = strcmpi(sSubjectDest.Name, bst_get('NormalizedSubjectName'));
    % Load forward model (only when projecting TO group analysis subject)
    if isDestGroup && isfield(ResultsMat, 'HeadModelFile') && ~isempty(ResultsMat.HeadModelFile)
        HeadModelMat = in_bst_headmodel(ResultsMat.HeadModelFile, 0, 'GridOptions');
        % If this file was computed from a template grid
        if ~isempty(HeadModelMat.GridOptions) && isfield(HeadModelMat.GridOptions, 'Method') && strcmpi(HeadModelMat.GridOptions.Method, 'group') && isfield(HeadModelMat.GridOptions, 'FileName') && ~isempty(HeadModelMat.GridOptions.FileName)
            % Get template source grid
            TemplateFile = HeadModelMat.GridOptions.FileName;
            % If this template file still exists
            if ~isempty(bst_get('HeadModelFile', TemplateFile))
                % Load template source grid
                TemplateMat = in_bst_headmodel(TemplateFile, 0, 'GridLoc', 'SurfaceFile');
                % If the file exists and is not empty
                if ~isempty(TemplateMat) && ~isempty(TemplateMat.GridLoc)
                    GridLoc     = TemplateMat.GridLoc;
                    SurfaceFile = TemplateMat.SurfaceFile;
                end
            else
                disp(['BST> Warning: Template grid file does not exist anymore: ' TemplateFile]);
            end
        end
    end

    % === CONVERT COORDINATES ===
    % If there is no group grid: project with the MNI transformation
    if isempty(GridLoc)
        % Convert grid coordinates: Source SCS => MNI
        GridLoc = cs_convert(sMriSrc, 'scs', 'mni', ResultsMat.GridLoc);
        if isempty(ResultsMat.GridLoc)
            errMsg = 'Cannot convert grid locations to MNI coordinates.';
            break;
        end
        % Convert grid coordinates: MNI => Destination SCS
        GridLoc = cs_convert(sMriDest, 'mni', 'scs', GridLoc);
        % This is an error only when projecting TO the group analysis subject
        if isDestGroup
            % Display warning
            disp('BST> Warning: This source file was not computed based on a template grid.');
            if isInteractive && isFirstWarning
                isFirstWarning = 0;
                java_dialog('warning', ['Warning: This source file was not computed based on a template grid.' 10 ...
                    'You will not be able to average sources from multiple subjects.' 10 10 ...
                    'In order to get a common grid of points for all the subjects:' 10 ...
                    ' - Right-click on "Group analysis" > Generate source grid' 10 ...
                    ' - For each subject, compute the forward model with option "Use template grid"'], 'Project sources');
            end
        end
    end
    % If the surface is not defined (or not on the correct subject): get the default cortex in destination folder
    if (isempty(SurfaceFile) || ~strcmpi(bst_fileparts(SurfaceFile), bst_fileparts(sSubjectDest.FileName))) && ~isempty(sSubjectDest.Surface) && ~isempty(sSubjectDest.iCortex)
        SurfaceFile = sSubjectDest.Surface(sSubjectDest.iCortex).FileName;
    end
    % Update grid in the file structure
    ResultsMat.GridLoc     = GridLoc;
    ResultsMat.SurfaceFile = SurfaceFile;

    % === OUTPUT STUDY ===
    % New condition name
    NewCondition = strrep(sStudySrc.Condition{1}, '@raw', '');
    % Get condition
    [sStudyDest, iStudyDest] = bst_get('StudyWithCondition', [sSubjectDest.Name '/' NewCondition]);
    % Create condition if doesnt exist
    if isempty(iStudyDest)
        iStudyDest = db_add_condition(sSubjectDest.Name, NewCondition, 0);
        if isempty(iStudyDest)
            error(['Cannot create condition: "' sSubjectDest.Name  '/' NewCondition '".']);
        end
        sStudyDest = bst_get('Study', iStudyDest);
    end

    % === SAVE NEW RESULTS ===
    % Use source filename as a base
    [fPath, fBase] = bst_fileparts(ResFile);
    % Remove KERNEL tag for saving full source files
    fBase = strrep(fBase, '_KERNEL', '');
    % Build full filename
    newResultsFileFull = bst_fullfile(bst_fileparts(file_fullpath(sStudyDest.FileName)), [fBase, '_', file_standardize(sSubjectSrc.Name), '.mat']);
    newResultsFileFull = file_unique(newResultsFileFull);
    newResultsFile = file_short(newResultsFileFull);
    % Update comment (add source filename)
    ResultsMat.Comment = [sSubjectSrc.Name '/' ResultsMat.Comment];
    % History: project source
    ResultsMat = bst_history('add', ResultsMat, 'project', ['Project source grid: ' sSubjectSrc.Name ' => ' sSubjectDest.Name]);
    % Save new results file
    bst_save(newResultsFileFull, ResultsMat, 'v6');

    % === ADD FILE IN DATABASE ===
    % Create Results/Timefreq structure for database
    switch (DataType)
        case 'timefreq'
            sNewResults = db_template('Timefreq');
            sNewResults.FileName = newResultsFile;
            sNewResults.Comment  = ResultsMat.Comment;
            sNewResults.DataFile = ResultsMat.DataFile;
            sNewResults.DataType = ResultsMat.DataType;
            % Add new result
            sStudyDest.Timefreq(end + 1) = sNewResults;
        case {'results', 'link'}
            sNewResults = db_template('Results');
            sNewResults.FileName = newResultsFile;
            sNewResults.Comment  = ResultsMat.Comment;
            sNewResults.DataFile = ResultsMat.DataFile;
            sNewResults.isLink   = 0;
            sNewResults.HeadModelType = ResultsMat.HeadModelType;
            % Add new result
            sStudyDest.Result(end + 1) = sNewResults;
    end
    % Update study in database
    bst_set('Study', iStudyDest, sStudyDest);
    iUpdatedStudies = [iUpdatedStudies, iStudyDest];
    % Add to list of returned files
    OutputFiles{end+1} = newResultsFile;

    % Increment progress bar
    bst_progress('inc', 1);
end
% Error handling
if ~isempty(errMsg)
    if isInteractive
        bst_error(errMsg, 'Project sources', 0);
        bst_progress('stop');
    else
        bst_report('Error', 'process_project_sources', ResultsFiles, errMsg);
    end
    return;
end

% ===== UDPATE DISPLAY =====
if isInteractive
    bst_progress('stop');
end
if isempty(OutputFiles)
    return;
end
% Update tree display
% panel_protocols('UpdateTree');
% Update node
panel_protocols('UpdateNode', 'Study', unique(iUpdatedStudies));
% Select first output study
panel_protocols('SelectStudyNode', iUpdatedStudies(1));
% Select first output file
panel_protocols('SelectNode', [], OutputFiles{1});
% Save database
db_save();


function [ gFile, qFile, vFile, wFile, pFile, rFile ] = tsgMakeFilenames( sGridName )
%
% [ gFile, qFile, vFile, wFile, pFile, rFile ] = tsgMakeFilenames( sGridName )
%
% given the paths from tsgGetPaths() it returns the filenames of all files associated with the name
%

[ sFiles, sTasGrid ] = tsgGetPaths();

gFile = [sFiles,'gFile_',sGridName]; % the filename to store the grid

qFile = [sFiles,'qFile_',sGridName]; % file with the quadrature points

vFile = [sFiles,'vFile_',sGridName]; % file with values to be loaded

wFile = [sFiles,'wFile_',sGridName]; % file with anisotropic weights

pFile = [sFiles,'pFile_',sGridName]; % file with points to evaluate the surrogate

rFile = [sFiles,'rFile_',sGridName]; % file with the result of the evaluation

end


function [dbBool, noDocMets] = checkFormulaValidty(model)
% Assesses whether metabolites in model are likely to be documented in databases.
%
% USAGE:
%
%    [dbBool, noDocMets] = checkFormulaValidty(model)
%
% INPUT:
%    model:        Model structure array
%
% OUTPUTS:
%    dbBool:       A boolean vector where the number of rows is equal to the number of
%                  metabolites in model. Contains a logical 1 in rows for metabolites that
%                  are likely to be documented in databases and a logical 0 elsewhere.
%    noDocMets:    A cell array containing a list of all metabolites in model that
%                  are not likely to be documented in any database.
%
% .. Author: - Ronan Fleming

[nMets, nRxns] = size(model.S);

dbBool = ones(nMets,1);

for n = 1:nMets;

    if ~isempty(strfind(model.mets{n},'_hs'))
        dbBool(n)=0;
    end
    if ~isempty(strfind(model.mets{n},'hs_'))
        dbBool(n)=0;
    end
    if ~isempty(strfind(model.mets{n},'retn'))
        dbBool(n)=0;
    end
    if ~isempty(strfind(model.mets{n},'vitd'))
        dbBool(n)=0;
    end
    if ~isempty(strfind(model.mets{n},'rtotal'))
        dbBool(n)=0;
    end
    if ~isempty(strfind(model.mets{n},'deg'))
        dbBool(n)=0;
    end
    if ~isempty(strfind(model.metFormulas{n},'R'))
        dbBool(n)=0;
    end
    if ~isempty(strfind(model.metFormulas{n},'FULLR'))
        dbBool(n)=0;
    end
    if ~isempty(strfind(model.metFormulas{n},'X'))
        dbBool(n)=0;
    end

end

noDocMets = model.mets(~dbBool, 1);


function compareFigures(fig1, fig2)
%COMPAREFIGURES - places the second figure next to the first one
%
% Syntax:
%   compareFigures(fig1, fig2) places the contents of fig2 next to the
%   contents of fig1, inside fig2

% Copyright 2008 The MathWorks, Inc.

pos1 = get(fig1,'Position');
pos2 = get(fig2,'Position');

%set absolute units to prevent resizing
setChildrenToPixel(fig1);
setChildrenToPixel(fig2);

%move the item from the second figure to the first
moveChildren(fig2,fig1,pos1(2));
%get rid of the second figure
close(fig2);

%resize the first figure to accodate the second
pos1(3) = pos1(3) + pos2(3);
pos1(4) = max(pos1(4),pos2(4));
set(fig1, 'Position', pos1);

%center on screen
set(fig1,'units','normalized');
pos1 = get(fig1,'Position');
pos1(1) = (1 - pos1(3)) / 2;
pos1(2) = (1 - pos1(4)) / 2;
set(fig1,'Position',pos1);
%bring to the front
figure(fig1);

function setChildrenToPixel(fig)
children = get(fig,'Children');
for i=1:length(children)
    set(children(i),'Units','pixels')
end

function moveChildren(from,to,x)
children = get(from,'Children');
for i=1:length(children)
    pos = get(children(i),'Position');
    pos(1) = x;
    set(children(i),'Parent',to,'Position', pos);
end


function ArgStruct=parseArgs(args,ArgStruct,varargin)
% Helper function for parsing varargin.
%
%
% ArgStruct=parseArgs(varargin,ArgStruct[,FlagtypeParams[,Aliases]])
%
% * ArgStruct is the structure full of named arguments with default values.
% * Flagtype params is params that don't require a value. (the value will be set to 1 if it is present)
% * Aliases can be used to map one argument-name to several argstruct fields
%
%
% example usage:
% --------------
% function parseargtest(varargin)
%
% %define the acceptable named arguments and assign default values
% Args=struct('Holdaxis',0, ...
%        'SpacingVertical',0.05,'SpacingHorizontal',0.05, ...
%        'PaddingLeft',0,'PaddingRight',0,'PaddingTop',0,'PaddingBottom',0, ...
%        'MarginLeft',.1,'MarginRight',.1,'MarginTop',.1,'MarginBottom',.1, ...
%        'rows',[],'cols',[]);
%
% %The capital letters define abrreviations.
% %  Eg. parseargtest('spacingvertical',0) is equivalent to  parseargtest('sv',0)
%
% Args=parseArgs(varargin,Args, ... % fill the arg-struct with values entered by the user
%           {'Holdaxis'}, ... %this argument has no value (flag-type)
%           {'Spacing' {'sh','sv'}; 'Padding' {'pl','pr','pt','pb'}; 'Margin' {'ml','mr','mt','mb'}});
%
% disp(Args)
%
%
%
%
% % Aslak Grinsted 2003

Aliases={};
FlagTypeParams='';

if (length(varargin)>0)
    FlagTypeParams=strvcat(varargin{1});
    if length(varargin)>1
        Aliases=varargin{2};
    end
end

%---------------Get "numeric" arguments
NumArgCount=1;
while (NumArgCount<=size(args,2))&(~ischar(args{NumArgCount}))
    NumArgCount=NumArgCount+1;
end
NumArgCount=NumArgCount-1;
if (NumArgCount>0)
    ArgStruct.NumericArguments={args{1:NumArgCount}};
else
    ArgStruct.NumericArguments={};
end

%--------------Make an accepted fieldname matrix (case insensitive)
Fnames=fieldnames(ArgStruct);
for i=1:length(Fnames)
    name=lower(Fnames{i,1});
    Fnames{i,2}=name; %col2=lower
    AbbrevIdx=find(Fnames{i,1}~=name);
    Fnames{i,3}=[name(AbbrevIdx) ' ']; %col3=abreviation letters (those that are uppercase in the ArgStruct) e.g. SpacingHoriz->sh
    %the space prevents strvcat from removing empty lines
    Fnames{i,4}=isempty(strmatch(Fnames{i,2},FlagTypeParams)); %Does this parameter have a value? (e.g. not flagtype)
end
FnamesFull=strvcat(Fnames{:,2});
FnamesAbbr=strvcat(Fnames{:,3});

if length(Aliases)>0
    for i=1:length(Aliases)
        name=lower(Aliases{i,1});
        FieldIdx=strmatch(name,FnamesAbbr,'exact'); %try abbreviations (must be exact)
        if isempty(FieldIdx)
            FieldIdx=strmatch(name,FnamesFull); %&??????? exact or not?
        end
        Aliases{i,2}=FieldIdx;
        AbbrevIdx=find(Aliases{i,1}~=name);
        Aliases{i,3}=[name(AbbrevIdx) ' ']; %the space prevents strvcat from removing empty lines
        Aliases{i,1}=name; %dont need the name in uppercase anymore for aliases
    end
    %Append aliases to the end of FnamesFull and FnamesAbbr
    FnamesFull=strvcat(FnamesFull,strvcat(Aliases{:,1}));
    FnamesAbbr=strvcat(FnamesAbbr,strvcat(Aliases{:,3}));
end

%--------------get parameters--------------------
l=NumArgCount+1;
while (l<=length(args))
    a=args{l};
    if ischar(a)
        paramHasValue=1; % assume that the parameter has is of type 'param',value
        a=lower(a);
        FieldIdx=strmatch(a,FnamesAbbr,'exact'); %try abbreviations (must be exact)
        if isempty(FieldIdx)
            FieldIdx=strmatch(a,FnamesFull);
        end
        if (length(FieldIdx)>1) %shortest fieldname should win
            [mx,mxi]=max(sum(FnamesFull(FieldIdx,:)==' ',2));
            FieldIdx=FieldIdx(mxi);
        end
        if FieldIdx>length(Fnames) %then it's an alias type.
            FieldIdx=Aliases{FieldIdx-length(Fnames),2};
        end

        if isempty(FieldIdx)
            error(['Unknown named parameter: ' a])
        end
        for curField=FieldIdx' %if it is an alias it could be more than one.
            if (Fnames{curField,4})
                val=args{l+1};
            else
                val=1; %parameter is of flag type and is set (1=true)....
            end
            ArgStruct.(Fnames{curField,1})=val;
        end
        l=l+1+Fnames{FieldIdx(1),4}; %if a wildcard matches more than one
    else
        error(['Expected a named parameter: ' num2str(a)])
    end
end


function selected = atlasSelectAtlas
%
%     selected = atlasSelectAtlas
%
% Author: BW, AAB,
% Purpose:
%    List dialogue to let the user select from the existing atlases (if selected >=1)
%    indicate the user wants a new atlas (selected == 0)
%    or the user decided to cancel, selected = [].
%

global dataTYPES;

atlasTypeNum = existDataType('Atlases',[],0);
str{1} = 'New Atlas';
if all(atlasTypeNum > 0)   % only if we have at least one atlas
	for ii=2:(length(atlasTypeNum)+1);
        str{ii} = dataTYPES(atlasTypeNum(ii-1)).name;
    end
end

[s,valid] = listdlg('PromptString','Select an Atlas:',...
    'SelectionMode','single',...
    'ListString',str);

%
if valid
    s = s - 1;
    if s > 0,  selected = atlasTypeNum(s);
    else       selected = 0;
    end
else
    selected = [];
end

return;


classdef Var < Param
%VAR Defines a network variable explicitly
%   Var(VALUE) or Var('value', VALUE) defines an explicit variable in the
%   network, with a given value.
%
%   Most of the time this is not needed; variables are created implicitly
%   to hold the values of any Inputs, Params, and output values computed by
%   Layers (typically instantiated with overloaded function calls).
%   Constants such as strings or Matlab arrays are stored as arguments to
%   any function call that uses them (in a Layer).
%
%   An explicit variable (Var) acts like a constant argument to a Layer,
%   but may still be useful for the following reasons:
%   1. Its value can be moved to and from the GPU using NET.USEGPU.
%   2. Its value can be set after network construction, with NET.SETVALUE.
%   3. Its derivative can be retrieved with NET.GETDER.
%
%   Internally, a Var is just a Param with trainMethod set to 'none'.

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

  methods
    function obj = Var(varargin)
      if isscalar(varargin)
        % special syntax, just passed in the value
        varargin = {'value', varargin{1}} ;
      end

      obj@Param('trainMethod','none', 'weightDecay',0, ...
        'learningRate',0, varargin{:})
    end
  end
end