function positions = GetPositions(varargin)

%GetPositions - Get position samples.
%
%  USAGE
%
%    positions = GetPositions(<options>)
%
%    <options>      optional list of property-value pairs (see table below)
%
%    =========================================================================
%     Properties    Values
%    -------------------------------------------------------------------------
%     'mode'         'all' gets all position samples, 'clean' discards bad
%                    position samples (lights undetected, out of boundaries,
%                    too close, etc. - see SETTINGS) (default 'clean')
%     'coordinates'  'video' gets position samples in video frame coordinates
%                    (e.g., [0..368]x[0..284]), 'normalized' uses normalized
%                    values (i.e. [0..1]x[0..1]), 'real' converts pixels to
%                    centimeters (default 'normalized')
%     'pixel'        size of the video pixel in cm (no default value)
%     'discard'      discard position samples when one or more LED is missing
%                    ('partial', default) or only when no LEDs are detected
%                    ('none', coordinates for missing LEDs are set to NaN)
%     'distances'    min and max distances [m M] allowed between LEDs
%                    (in pixels, default [0 Inf])
%    =========================================================================
%
%  EXAMPLES
%
%    p = GetPositions;
%    p = GetPositions('mode','all');
%
%  CUSTOM DEFAULTS
%
%    Properties 'mode', 'coordinates', 'pixel' and 'distances' can have custom
%    default values (type 'help CustomDefaults' for details).

% Copyright (C) 2004-2014 by Michaël Zugaro
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% (at your option) any later version.

global DATA SETTINGS;
if isempty(DATA),
	error('No session defined (did you forget to call SetCurrentSession? Type ''help Data'' for details).');
end

% Default values (customizable defaults must be empty at this point)
mode = '';
coordinates = '';
pixel = [];
distances = [];
discard = 'partial';

if mod(length(varargin),2) ~= 0,
	error('Incorrect number of parameters (type ''help GetPositions'' for details).');
end

% Parse options
for i = 1:2:length(varargin),
	if ~ischar(varargin{i}),
		error(['Parameter ' num2str(i+1) ' is not a property (type ''help GetPositions'' for details).']);
	end
	switch(lower(varargin{i})),
		case 'mode',
			mode = lower(varargin{i+1});
			if ~isstring_FMAT(mode,'clean','all'),
				error('Incorrect value for property ''mode'' (type ''help GetPositions'' for details).');
			end
		case 'coordinates',
			coordinates = lower(varargin{i+1});
			if ~isstring_FMAT(coordinates,'video','normalized','real'),
				error('Incorrect value for property ''coordinates'' (type ''help GetPositions'' for details).');
			end
		case 'pixel',
			pixel = varargin{i+1};
			if ~isdscalar(pixel,'>0'),
				error('Incorrect value for property ''pixel'' (type ''help GetPositions'' for details).');
			end
		case 'discard',
			discard = lower(varargin{i+1});
			if ~isstring_FMAT(discard,'partial','none'),
				error('Incorrect value for property ''discard'' (type ''help GetPositions'' for details).');
			end
		case 'distances',
			distances = lower(varargin{i+1});
			if ~isdvector(distances,'#2','>=0'),
				error('Incorrect value for property ''distances'' (type ''help GetPositions'' for details).');
			end
		otherwise,
			error(['Unknown property ''' num2str(varargin{i}) ''' (type ''help GetPositions'' for details).']);
	end
end

% Customizable defaults (if not already set)
mode = GetCustomDefaults(mode,'mode','clean');
coordinates = GetCustomDefaults(coordinates,'coordinates','normalized');
pixel = GetCustomDefaults(pixel,'pixel',[]);
distances = GetCustomDefaults(distances,'distances',[0 Inf]);

minDistance = distances(1);
maxDistance = distances(2);

if strcmp(coordinates,'real') & isempty(pixel),
	error(['Missing ''pixel'' property-value pair (type ''help GetPositions'' for details).']);
end

positions = DATA.positions;
if isempty(positions), return; end

% Discard positions with incorrect distance between lights
if strcmp(mode,'clean'),
	if size(positions,2) == 5,
		% Two head lamps
		distance = sqrt((positions(:,4)-positions(:,2)).^2+(positions(:,5)-positions(:,3)).^2);
		selected = ( ...
				distance >= minDistance ...
				& distance <= maxDistance ...
			);
		positions = positions(selected,:);
	end
end

% Mark undetects (by convention, values of -1)
if strcmp(discard,'none'),
	undetected = all(positions(:,2:end) == -1,2);
	partiallyDetected = positions == -1;
	positions(partiallyDetected) = NaN;
else
    undetected = any(positions(:,2:end) == -1,2);

end
%  positions(undetected,2:end) = -1; % Make sure all values are -1
good = ~undetected;

% Clip if necessary (but issue warning)
m = min(positions(good,2:end));
M = max(positions(good,2:end));
%  if any(m<0)||any(M(1:2:end)>DATA.maxX|M(2:2:end)>DATA.maxY),
%  	warning(['Position data should stay within [0,' num2str(DATA.maxX) ']x[0,' num2str(DATA.maxY) ']. The data will now be clipped accordingly.']);
%  	positions(good,2) = Clip(positions(good,2),0,DATA.maxX);
%  	positions(good,3) = Clip(positions(good,3),0,DATA.maxY);
%  end

if strcmp(coordinates,'normalized'),
	% Normalize coordinates
	maxima = M(1:2);%[DATA.maxX DATA.maxY];
	positions(good,2:end) = positions(good,2:end) ./ repmat(maxima,sum(good),(size(positions,2)-1)/2);
elseif strcmp(coordinates,'real'),
	% Convert to cm
	positions(good,2:end) = positions(good,2:end) * pixel;
end

% Discard undetects
if strcmp(mode,'clean'),
	positions(undetected,:) = [];
end


function rawdata = ReadRawDataFile(datafile)

metadatafns = {'mouse','exp','id','upper'};
metadataisnum = [true,false,false,false];

datafnsspecial = {'auto_Grab_success','auto_Grab_successtype'};

fid = fopen(datafile,'r');

% read headers
l = fgetl(fid);
headers = regexp(l,',','split');
idxdata = find(~cellfun(@isempty,regexp(headers,'^auto','once')) & ...
  ~ismember(headers,datafnsspecial));% & ...
  %cellfun(@isempty,regexp(headers,'successfultrial')));
metadatai = nan(1,numel(metadatafns));
for i = 1:numel(metadatafns),
  metadatai(i) = find(strcmpi(headers,metadatafns{i}));
end

successi = find(strcmpi(headers,'auto_Grab_success'),1);
successtypei = find(strcmpi(headers,'auto_Grab_successtype'),1);

datei = find(strcmpi(headers,'date'),1);
parentdiri = find(strcmpi(headers,'upper'),1);
expi = find(strcmpi(headers,'exp'),1);

datafns = headers(idxdata);

rawdata = [];

while true,
  l = fgetl(fid);
  if ~ischar(l),
    break;
  end
  if isempty(l),
    continue;
  end
  s = regexp(l,',','split');

  rawdatacurr = struct;

  m = regexp(s{datei},'^(\d+)([^\d]*)$','once','tokens');
  rawdatacurr.date = m{1};
  rawdatacurr.iscno = strcmpi(m{2},'CNO');
  m = regexp(s{parentdiri},'[\\/]([^\\/]+)$','tokens','once');
  rawdatacurr.session = m{1};
  m = regexp(s{expi},'_[vV](\d+)$','tokens','once');
  rawdatacurr.trial = str2double(m{1});

  for i = 1:numel(metadatafns),
    fn = metadatafns{i};
    rawdatacurr.(fn) = s{metadatai(i)};
    if metadataisnum(i),
      rawdatacurr.(fn) = str2double(rawdatacurr.(fn));
    end
  end

  rawdatacurr.success = find(strcmpi(s{successi},{'false','true'}))-1;
  rawdatacurr.successtype = s{successtypei};

  for i = 1:numel(datafns),
    fn = datafns{i};
    rawdatacurr.(fn) = str2double(s{idxdata(i)});
  end

  if isfield(rawdatacurr,'exp') && ~isfield(rawdatacurr,'expfull'),
    rawdatacurr.expfull = rawdatacurr.exp;
  end

  rawdata = structappend(rawdata,rawdatacurr);

end

fclose(fid);


classdef FullInnerMeshCreator_Matlab < InnerMeshExporter

    methods (Access = public)

        function obj = FullInnerMeshCreator_Matlab(cParams)
            obj.init(cParams)

        end

        function m = export(obj)
            coordInner     = obj.unfittedMesh.innerMesh.mesh.coord;
            connecInner    = obj.unfittedMesh.innerMesh.mesh.connec;
            coordCutInner  = obj.unfittedMesh.innerCutMesh.mesh.coord;
            connecCutInner = obj.unfittedMesh.innerCutMesh.mesh.connec;
            ncoord = size(coordInner,1);
            connecCutInner = connecCutInner + ncoord;
            s.coord  = [coordInner;  coordCutInner];
            s.connec = [connecInner; connecCutInner];
            m = Mesh(s);
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.unfittedMesh  = cParams.unfittedMesh;
        end

    end

end


function test_bug1412

% MEM 3gb
% WALLTIME 00:10:00
% DEPENDENCY ft_read_header loadcnt

hdr = ft_read_header(dccnpath('/home/common/matlab/fieldtrip/data/test/bug1412/Sub1_1.cnt'));

assert(hdr.nSamples == 1505200);


function [tstop,res] = testProblem(optObj,solvers)
%TESTPROBLEM  Test an OPTI Problem against all available solvers
%
%   [times,results] = testProblem(optObj) runs the supplied OPTI problem
%   against all available solvers for the given problem type.
%
%   [times,results] = testProblems(optObj,solvers) runs only the selected
%   solvers across the supplied problem.

%   Copyright (C) 2011 Jonathan Currie (I2C2)

%Setup default arguments
if(~exist('solvers','var') || isempty(solvers))
    solvers = checkSolver(['all_' optObj.prob.type]);
end
if(~iscell(solvers))
    solvers = {solvers};
end

%Remove troublesome solvers
ind = strcmpi(solvers,'lipsol');
if(any(ind))
    solvers(ind) = [];
end

%Setup problem generation function (for warm up)
switch(lower(optObj.prob.type))
    case 'lp'
        testSet = @lp_prob;
    case 'milp'
        testSet = @milp_prob;
    case 'bilp'
        testSet = @bilp_prob;
    case 'qp'
        testSet = @qp_prob;
    case 'qcqp'
        testSet = @qcqp_prob;
    case 'sdp'
        testSet = @sdp_prob;
    case 'miqp'
        testSet = @miqp_prob;
    case 'nlp'
        testSet = @nlp_prob;
        if(isempty(optObj.prob.x0))
            error('Please include x0 in optiprob when using this function on NLPs');
        end
    case 'minlp'
        testSet = @minlp_prob;
        if(isempty(optObj.prob.x0))
            error('Please include x0 in optiprob when using this function on MINLPs');
        end
    otherwise
        error('Unknown problem type: %s',optObj.prob.type);
end

%Remove troublesome solvers
if(strcmpi(optObj.prob.type,'lp'))
    ind = strcmpi(solvers,'SEDUMI'); solvers(ind) = []; %no good with neq = nvar
end

%Setup no runs
len = length(solvers);
%confirm solver exists!
for i = 1:len
    rub = checkSolver(solvers{i}); %#ok<NASGU>
end

%Setup wait bar
h = waitbar(0,['Solver: ' upper(solvers{1})],'name','OPTI Problem Test','CreateCancelBtn','setappdata(gcbf,''canceling'',1)');

%Preallocate
tstop = zeros(len,1);
res = struct('sol',{cell(len,1)},'fval',zeros(len,1),'ok',zeros(len,1),'msg',{cell(len,1)});

%Clear display warnings etc
opts = optiset(optObj.prob,'display','off','warnings','off');

try
    for i = 1:len
        %Check Cancel
        if getappdata(h,'canceling')
            break;
        end
        %Assign the new solver
        solver = solvers{i};
        opts = optiset(opts,'solver',solver);
        %Initialize with two solves of problem 1
        prob = testSet(1);
        Opt = opti(prob,opts);
        solve(Opt); solve(Opt);
        %Now run our problem
        Opt = opti(getProb(optObj),opts);
        [x,sval,~,stat] = solve(Opt);
        res.sol{i} = x;
        res.fval(i) = sval;
        res.ok(i) = checkSol(Opt);
        res.msg{i} = stat.Status;
        tstop(i) = stat.Time;
        %Update Waitbar
        waitbar(i/len,h,['Solver: ' upper(solvers{min(len,i+1)})]);
    end
catch ME
    delete(h);
    rethrow(ME);
end

delete(h);

%Draw Table
fprintf('\nTest Problem [%s] Result\n',Opt.prob.type);
fprintf('--------------------------------------------------\n');
fprintf('  Solver    Status        Fval         Time\n');
for i = 1:len
    fprintf('%8s    %4s    %+12.4f     %1.4fs\n',solvers{i},status(res.ok(i)),res.fval(i),tstop(i));
end
fprintf('--------------------------------------------------\n');

function msg = status(ok)

if(ok)
    msg = 'OK';
else
    msg = 'FAIL';
end


function c = eval_get_color_new(cidxs)

% http://colorbrewer2.org/

color = cell(8,4);

% qualitative
color{1}{1} = [55,126,184];
color{2}{1} = [255,127,0];
color{3}{1} = [255,255,51];%[178,223,138];
color{4}{1} = [0,0,0];
color{5}{1} = [77,175,74];
color{6}{1} = [228,26,28];
% color{6}{1} = [255,255,51];
color{7}{1} = [152,78,163];
color{8}{1} = [247,129,191];

% sequential
color{1}{2} = [253,141,60];
color{1}{3} = [254,204,92];
color{1}{4} = [255,255,178];
color{1}{5} = [254,240,217];

color{2}{2} = [107,174,214];
color{2}{3} = [189,215,231];
color{2}{4} = [117,107,177];

color{3}{2} = [194,230,153];

color{4}{2} = [140,150,198];
color{4}{3} = [179,205,227];
color{4}{4} = [237,248,251];

c = color{cidxs(1)}{cidxs(2)};

end


%% DeglitchStack
% removes images from stack
% S = complete stack struct
% badEnergy=

function Snew=DeglitchStack(S,badEnergy)

numbad=length(badEnergy);
resolution=0.1;            % Half of best energy resolution in scan definition

Snew=S;

for counter=1:numbad            % Find bad energy points

    rmindex=find(Snew.eVenergy < badEnergy(counter)+resolution & ...
        Snew.eVenergy > badEnergy(counter)-resolution);

     if isempty(rmindex)==0

        Snew.eVenergy(rmindex)=[];
        Snew.spectr(:,:,rmindex)=[];

    else

        displayeV=num2str(badEnergy(counter));
        display(strcat('Error: no energy match for input = ',displayeV,' eV! Image not removed!!!'))
        clear displayeV;

    end

    clear rmindex

end

return


% ------------------------------------------------------------------------
%  Copyright (C)
%  Universitat Politecnica de Catalunya BarcelonaTech (UPC) - Spain
%
%  Jordi Pont-Tuset <jordi.pont@upc.edu>
%  June 2013
% ------------------------------------------------------------------------

function [combined_stats,conv_hull_stats,params]= combine_masks(stats1, stats2, measure)
if nargin<3
    measure = 'jaccard_class';
end

n_res1 = length(stats1.mean_n_masks);
n_res2 = length(stats2.mean_n_masks);

%% Combinations
% Single results
for kk=1:n_res1
    combined_stats{kk,n_res2+1} = extract_one_from_all(stats1,kk); %#ok<AGROW>
end
for ii=1:n_res2
    combined_stats{n_res1+1,ii} = extract_one_from_all(stats2,ii); %#ok<AGROW>
end
% Combined results
for kk=1:n_res1
    for ii=1:n_res2
        combined_stats{kk,ii} = join_masks(combined_stats{kk,n_res2+1}, combined_stats{n_res1+1,ii}); %#ok<AGROW>
    end
end
% No results
combined_stats{n_res1+1,n_res2+1}.mean_n_masks = 0;
combined_stats{n_res1+1,n_res2+1}.(measure) = 0;

%% Get convex hull
nn = 1;
all_n_masks = zeros((n_res1+1)*(n_res2+1),1);
xx = zeros((n_res1+1)*(n_res2+1),1);
yy = zeros((n_res1+1)*(n_res2+1),1);
for kk=1:n_res1+1
    for ii=1:n_res2+1
        all_n_masks(nn) = combined_stats{kk,ii}.mean_n_masks;
        xx(nn) = kk;
        yy(nn) = ii;
        nn = nn+1;
    end
end
all_n_masks(end) = [];
xx(end) = [];
yy(end) = [];

nn = 1;
all_J = zeros((n_res1+1)*(n_res2+1),1);
for kk=1:n_res1+1
    for ii=1:n_res2+1
        all_J(nn)   = combined_stats{kk,ii}.(measure);
        nn = nn+1;
    end
end
all_J(end) = [];

if length(all_n_masks)==1
    sel_stats = 1;
else
    % Pareto front
    sel_stats = find(paretoGroup([all_n_masks, -all_J]));
    [~,tmp_ids] = sort(all_n_masks(sel_stats));
    sel_stats = sel_stats(tmp_ids);

    % Convex hull to simplify
    sel_stats_hull = convhull(all_n_masks(sel_stats), all_J(sel_stats),'simplify',true);
    sel_stats = sel_stats(sel_stats_hull);
end

for ii=1:length(sel_stats)
    c_hull_stats(ii) = combined_stats{xx(sel_stats(ii)), yy(sel_stats(ii))}; %#ok<AGROW>
    params(ii).params1 = xx(sel_stats(ii)); %#ok<AGROW>
    params(ii).params2 = yy(sel_stats(ii)); %#ok<AGROW>
end

%% Put the convex hull in the same struct
% Sorted in order of n_masks
[~, sel_stats_ids] = sort([c_hull_stats.mean_n_masks]);
params = params(sel_stats_ids);
conv_hull_stats = c_hull_stats(sel_stats_ids(1));
conv_hull_stats.gt_set = stats1.gt_set;
for ii=2:length(sel_stats_ids)
    conv_hull_stats.all_n_masks  = [conv_hull_stats.all_n_masks c_hull_stats(sel_stats_ids(ii)).all_n_masks];
    conv_hull_stats.max_J        = [conv_hull_stats.max_J c_hull_stats(sel_stats_ids(ii)).max_J];
    conv_hull_stats.max_fp       = [conv_hull_stats.max_fp c_hull_stats(sel_stats_ids(ii)).max_fp];
    conv_hull_stats.max_fn       = [conv_hull_stats.max_fn c_hull_stats(sel_stats_ids(ii)).max_fn];
    conv_hull_stats.max_inters   = [conv_hull_stats.max_inters c_hull_stats(sel_stats_ids(ii)).max_inters];
    conv_hull_stats.jaccard_object = [conv_hull_stats.jaccard_object c_hull_stats(sel_stats_ids(ii)).jaccard_object];
    conv_hull_stats.mean_n_masks = [conv_hull_stats.mean_n_masks c_hull_stats(sel_stats_ids(ii)).mean_n_masks];
    conv_hull_stats.jaccard_class  = [conv_hull_stats.jaccard_class c_hull_stats(sel_stats_ids(ii)).jaccard_class];

    for kk=1:length(c_hull_stats(sel_stats_ids(ii)).per_class_results)
        conv_hull_stats.per_class_results{kk}.max_J         = [conv_hull_stats.per_class_results{kk}.max_J c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.max_J];
        conv_hull_stats.per_class_results{kk}.max_fp        = [conv_hull_stats.per_class_results{kk}.max_fp c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.max_fp];
        conv_hull_stats.per_class_results{kk}.max_fn        = [conv_hull_stats.per_class_results{kk}.max_fn c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.max_fn];
        conv_hull_stats.per_class_results{kk}.max_inters    = [conv_hull_stats.per_class_results{kk}.max_inters c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.max_inters];
        conv_hull_stats.per_class_results{kk}.meanmax       = [conv_hull_stats.per_class_results{kk}.meanmax c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.meanmax];

        conv_hull_stats.per_class_results{kk}.global_fp     = [conv_hull_stats.per_class_results{kk}.global_fp c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.global_fp];
        conv_hull_stats.per_class_results{kk}.global_fn     = [conv_hull_stats.per_class_results{kk}.global_fn c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.global_fn];
        conv_hull_stats.per_class_results{kk}.global_inters = [conv_hull_stats.per_class_results{kk}.global_inters c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.global_inters];

        conv_hull_stats.per_class_results{kk}.global_J      = [conv_hull_stats.per_class_results{kk}.global_J c_hull_stats(sel_stats_ids(ii)).per_class_results{kk}.global_J];
    end
end

%% Some sanity checks
% Compute global mean
tmp = [];
for ii=1:length(conv_hull_stats.per_class_results)
    tmp = [tmp; conv_hull_stats.per_class_results{ii}.global_J]; %#ok<AGROW>
end
assert(isequal(conv_hull_stats.jaccard_class,mean(tmp)));
% Per-class means
for ii=1:length(conv_hull_stats.per_class_results)
    tmp =   conv_hull_stats.per_class_results{ii}.global_inters ./...
            (conv_hull_stats.per_class_results{ii}.global_inters+...
             conv_hull_stats.per_class_results{ii}.global_fp    +...
             conv_hull_stats.per_class_results{ii}.global_fn);
    tmp(isnan(tmp)) = 0;
    assert(isequal(tmp, conv_hull_stats.per_class_results{ii}.global_J))
end

%% Debug
% subplot(1,2,1)
% plot(all_n_masks,all_J,'b+')
% hold on
% plot(all_n_masks(sel_stats),all_J(sel_stats),'k')

end


classdef ImageTile < handle
    % ImageTile This class holds a list of images.
    %
    % Upon request they can be placed into a single image in a given pattern.
    % Any non-color image will be converted to a color image.
    %
    % Copyright by Holger Caesar, 2014

    properties
        images
    end

    methods (Access = public)
        function[obj] = ImageTile()
            % [obj] = ImageTile()
            %
            % Initialize and empty image tile.

            obj.images = cell(0, 1);
        end

        function addImage(obj, image)
            % addImage(obj, image)
            %
            % Stores a copy of the image in the tile.

            obj.images{end+1, 1} = image;
        end

        function addTiling(obj, tiling)
            % addTiling(obj, tiling)
            %
            % Copies all images from that tiling to the current one.

            obj.images(end+1:end+numel(tiling.images), 1) = tiling.images;
        end

        function[totalX] = getTotalX(obj)
            totalX = numel(obj.images);
        end

        function[image] = getImage(obj, idx)
            image = obj.images{idx};
        end

        function[] = setImage(obj, idx, image)
            obj.images{idx} = image;
        end

        function[totalImage] = getTiling(obj, varargin)
            % [totalImage] = getTiling(obj, varargin)
            %
            % Compute an image that contains all images held by this tiling.

            % Get essential values
            numImages = numel(obj.images);
            sqNumImages = ceil(sqrt(numImages));

            % Parse input
            p = inputParser;
            addParameter(p, 'totalX', sqNumImages);
            addParameter(p, 'totalY', []);
            addParameter(p, 'delimiterPixels', 0);
            addParameter(p, 'minTotalSize', [0, 0]);
            addParameter(p, 'keepAspectRatio', true);
            addParameter(p, 'backgroundBlack', true);
            parse(p, varargin{:});

            totalX = p.Results.totalX;
            totalY = p.Results.totalY;
            delimiterPixels = p.Results.delimiterPixels;
            minTotalSize = p.Results.minTotalSize;
            keepAspectRatio = p.Results.keepAspectRatio;
            backgroundBlack = p.Results.backgroundBlack;

            % Early abort if there are no images
            if isempty(obj.images) || any(cellfun(@isempty, obj.images)),
                totalImage = [];
                return;
            end;

            % Compute tiling if only one size is known
            if isempty(totalY) && ~isempty(totalX),
                totalY = ceil(numImages / totalX);
            end;
            if isempty(totalX) && ~isempty(totalY),
                totalX = ceil(numImages / totalY);
            end;
            assert(totalY * totalX >= numImages);

            % Determine mean image size
            imSizes = cell2mat(cellfun(@(x) [size(x, 1), size(x, 2)], obj.images, 'UniformOutput', false));
            meanImSize = ceil(mean(imSizes, 1));

            % Determine total image size
            totalSize = meanImSize .* [totalY, totalX];

            % Correct mean image size if specified (and then meanImSize as
            % well)
            if totalSize(1) < minTotalSize(1),
                totalSize(1) = minTotalSize(1);
                meanImSize(1) = ceil(totalSize(1) / totalY);
            end;
            if totalSize(2) < minTotalSize(2),
                totalSize(2) = minTotalSize(2);
                meanImSize(2) = ceil(totalSize(2) / totalX);
            end;

            % Add delimiter pixels
            totalSize(1) = totalSize(1) + delimiterPixels * (totalY - 1);
            totalSize(2) = totalSize(2) + delimiterPixels * (totalX - 1);

            % Initialize image
            if backgroundBlack,
                totalImage = zeros(totalSize(1), totalSize(2), 3, 'uint8');
            else
                totalImage = ones(totalSize(1), totalSize(2), 3, 'uint8') * 255;
            end;

            for posIdx = 1 : numImages,
                % Get current image
                posImage = obj.images{posIdx};

                % Convert to color if necessary
                if size(posImage, 3) ~= 3,
                    posImage = repmat(posImage, [1, 1, 3]);
                end;

                % Convert to 8 bit if necessary
                posImage = im2uint8(posImage);

                if keepAspectRatio,
                    % Scale longer side to mean size and fill missing
                    % pixels with white color

                    % Resize longer side to mean size
                    imageSize = [size(posImage, 1), size(posImage, 2)];
                    imageRatio = imageSize(1) / imageSize(2);
                    meanImRatio = meanImSize(1) / meanImSize(2);
                    if imageRatio > meanImRatio,
                        % Image is too high
                        targetSize = [meanImSize(1), nan];
                    elseif imageRatio < meanImRatio,
                        % Image is too wide
                        targetSize = [nan, meanImSize(2)];
                    else
                        % Ratio is correct
                        targetSize = meanImSize;
                    end;
                    posImage = imresize(posImage, targetSize);

                    % Fill missing pixels with black color
                    fullPosImage = repmat(uint8(255), [meanImSize, 3]);
                    moveYStart = 1 + floor((meanImSize(1) - size(posImage, 1)) / 2);
                    moveYEnd = moveYStart + size(posImage, 1) - 1;
                    moveXStart = 1 + floor((meanImSize(2) - size(posImage, 2)) / 2);
                    moveXEnd = moveXStart + size(posImage, 2) - 1;
                    fullPosImage(moveYStart:moveYEnd, moveXStart:moveXEnd, :) = posImage;
                    posImage = fullPosImage;
                else
                    % Scale to mean size and destroy ratio
                    posImage = imresize(posImage, meanImSize);
                end;

                % Find out current position (go through x first!)
                posY = 1 + floor((posIdx - 1) / totalX);
                posX = posIdx - (posY-1) * totalX;

                % Insert current image into totalImage
                startY = 1 + meanImSize(1) * (posY-1) + delimiterPixels * (posY - 1);
                endY = meanImSize(1) * posY           + delimiterPixels * (posY - 1);

                startX = 1 + meanImSize(2) * (posX-1) + delimiterPixels * (posX - 1);
                endX = meanImSize(2) * posX           + delimiterPixels * (posX - 1);

                totalImage(startY:endY, startX:endX, :) = posImage;
            end;
        end
    end
end


function iimg_write_images(dat, volInfo, outnames)
% Write a series of Analyze images given inputs.
%
% :Usage:
% ::
%
%     iimg_write_images(dat,volInfo,outnames)
%
% :Inputs:
%
%   **dat:**
%        voxels x images matrix of image data in index format
%
%   **volInfo:**
%        spm-style info structure; see iimg_read_img
%
%   **outnames:**
%        a string matrix (or cell array) of output filenames, or the name of a 4-D file to create

    if isempty(outnames)
        error('You must specify a string array of output names, or a single 4-D image file name');
    end

    if iscell(outnames)
        outnames = char(outnames{:});
    end

    n = size(dat,2);
    if size(outnames,1) ~= n
        error('Number of images (columns of dat) must == number of output img names.');
    end

    if volInfo.nvox ~= size(dat,1)
        error('Dims of dat (vox x images) and volInfo do not match.');
    end

    is4d = 0;
    if size(dat, 2) > 1 && size(outnames, 1) == 1, is4d = 1; end

    if is4d
        iimg_reconstruct_vols(dat,volInfo,'outname',deblank(outnames));

    else
        for i = 1:n
            %iimg_reconstruct_3dvol(dat(:,i),volInfo,'outname',deblank(outnames(i,:)));
            % This handles volume creation, etc.  It also works for a 4-D
            % image (but all volumes must be created at once)
            iimg_reconstruct_vols(dat(:,i),volInfo,'outname',deblank(outnames(i,:)));
        end
    end

end


% ------------------------------------------------------------------------
%  Copyright (C)
%  Universitat Politecnica de Catalunya BarcelonaTech (UPC) - Spain
%  University of California Berkeley (UCB) - USA
%
%  Jordi Pont-Tuset <jordi.pont@upc.edu>
%  Pablo Arbelaez <arbelaez@berkeley.edu>
%  June 2014
% ------------------------------------------------------------------------
% This file is part of the MCG package presented in:
%    Arbelaez P, Pont-Tuset J, Barron J, Marques F, Malik J,
%    "Multiscale Combinatorial Grouping,"
%    Computer Vision and Pattern Recognition (CVPR) 2014.
% Please consider citing the paper if you use this code.
% ------------------------------------------------------------------------
function  write_boxes_to_file( stats, filename )

% Create the columns for different recall levels
str_header  = 'ncands\t';
str_pattern = '%d\t';
for ii=1:length(stats.overlap_levels)
    str_header = [str_header '\trec_at_' num2str(stats.overlap_levels(ii))]; %#ok<AGROW>
    str_pattern = [str_pattern '\t%f']; %#ok<AGROW>
end
str_header  = [str_header  '\n'];
str_pattern = [str_pattern '\n'];

fid = fopen(filename,'w');
fprintf(fid, str_header);
fprintf(fid, str_pattern, [stats.mean_n_masks; stats.rec_at_overlap]);
fclose(fid);


function y = cvx_isaffine( x, full )
error( nargchk( 1, 2, nargin ) );
y = cvx_vexity( x );
if nargin < 2,
    y = nnz( y ) == 0;
else
    y = cvx_reshape( y == 0, x.size_ );
end

% Copyright 2010 Michael C. Grant and Stephen P. Boyd.
% See the file COPYING.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function fig_state= fig_set(varargin)
%FIG_SET - Setup a new figure
%
%Synposis:
% FIG_STATE= fig_set(FN)
% FIG_STATE= fig_set(FN, <OPT>)
% FIG_STATE= fig_set(<OPT>)
%
%Input:
% FN:  figure number
% OPT: property/value list or struct of options with fields/properties:
%  .Fn          - figure number, alternative to using the first argument
%  .Name        - name of figure window, default: ''
%  .Silent      - if true, doesn't bring figure to the foreground,
%                 default: false
%  .Hide        - if true, sets the figure 'Visible' property to false,
%                 default: false
%  .Toolsoff    - if true, turns off the toolbar of the figure window,
%                 default: true
%  .Clf         - if true, clears the figure, default: false
%  .Resize      - resize the automatically defined dimensions of the figure
%                 (width, height) by the factors [wf hf], default: [1 1]
%  .GridSize    - figures are successively arranged in a [M x N] grid that
%                 covers the whole screen, according to their figure
%                 number, default: [2 2]
%
%Output:
% FIG_STATE: structure with a 'WasVisible' field, to use with function
%            fig_publish

props= {'Fn'              1            '!INT'
        'Name'            ''           'CHAR'
        'Silent'          0            '!BOOL'
        'Hide'            0            '!BOOL'
        'ToolsOff'        1            '!BOOL'
        'Clf'             0            '!BOOL'
        'Resize'          [1 1]        '!DOUBLE[2]'
        'Square'          0            '!BOOL'
        'GridSize'        [2 2]        '!DOUBLE[2]'
        'Props'           {}           'PROPLIST'
        'ShiftUpwards'    1            '!BOOL'
        'DesktopBorder'   [0 30 0 0]   '!DOUBLE[4]'
        'WindowBorder'    [5 20]       '!DOUBLE[2]'
       };

if nargin>0 && isnumeric(varargin{1}),
  opt= opt_proplistToStruct(varargin{2:end});
  opt.Fn= varargin{1};
else
  opt= opt_proplistToStruct(varargin{:});
end
[opt, isdefault]= opt_setDefaults(opt, props);
opt_checkProplist(opt, props);

pos_screen= get(0, 'ScreenSize');
actualsize(1)= pos_screen(3) - opt.GridSize(2)*2*opt.WindowBorder(1);
actualsize(2)= pos_screen(4) - opt.GridSize(1)*sum(opt.WindowBorder);
actualsize= actualsize - sum(opt.DesktopBorder([1 2; 3 4]));

fig_size= floor(actualsize./fliplr(opt.GridSize));
iv= mod(opt.GridSize(1) - 1 - floor((opt.Fn-1)/opt.GridSize(2)), opt.GridSize(1));
ih= mod(opt.Fn-1, opt.GridSize(2));

incr= fig_size + [2*opt.WindowBorder(1) sum(opt.WindowBorder)];
fig_pos= opt.DesktopBorder([1 2]) + opt.WindowBorder([1 1]) + [ih iv].*incr;

fig_state= struct('WasVisible',[]);
if ishandle(opt.Fn),
  fig_state.WasVisible= get(opt.Fn, 'Visible');
end
if opt.Silent && ishandle(opt.Fn),
  set(0, 'CurrentFigure',opt.Fn);
else
  figure(opt.Fn);
end
if opt.Hide,
  set(opt.Fn, 'Visible','off');
end
if opt.ToolsOff,
  set(gcf, 'ToolBar','none', 'MenuBar','none');
end
fig_size_orig= fig_size;
fig_size= round(fig_size .* opt.Resize);
if opt.ShiftUpwards && fig_size(2)~=fig_size_orig(2),
  fig_pos(2)= fig_pos(2) + fig_size_orig(2) - fig_size(2);
end
drawnow;
set(opt.Fn, 'Position', [fig_pos fig_size]);
if opt.Square,
  oldUnits= get(gcf, 'Units');
  set(gcf, 'Units','Points');
  pos= get(gcf, 'Position');
  pos([3 4])= min(pos([3 4]));
  set(gcf, 'Position',pos);
  set(gcf, 'Units',oldUnits);
end

if ~isdefault.Name,
  set(opt.Fn, 'Name',opt.Name);
end
if ~isempty(opt.Props),
  set(opt.Fn, opt.Props{:});
end
if opt.Clf,
  clf;
end

if nargout==0,
  clear fig_state;
end


function obj = setFuncs(obj, funcs)
    % This function specify the functions (name) that calculates the
    % the function
    %
    % Parameters:
    % funcs:
    %
    % Required fields of Funcs:
    %   Func: a string of the function that computes the
    %   function value @type char
    %   Jac: a string of the function that computes the
    %   function Jacobian @type char
    %   JacStruct: a string of the function that computes the
    %   sparsity structure of function Jacobian @type char
    %   Hess: a string of the function that computes the
    %   function Hessian @type char
    %   HessStruct: a string of the function that computes the
    %   sparsity structure of function Hessian @type char
    % @type struct

    assert(isstruct(funcs),...
        'The input argument must be a struct.');

    assert(all(isfield(funcs, {'Func', 'Jac', 'JacStruct', 'Hess', 'HessStruct'})),...
        ['Required fields missing. \n',...
        'Following fields must be present: %s'], ...
        implode({'Func', 'Jac', 'JacStruct', 'Hess', 'HessStruct'},', '));

    obj.Funcs = funcs;

end


function format_colorbar(axes_handle, scalar)
chkarg(istypesizeof(scalar, 'Scalar2d') || istypesizeof(scalar, 'Scalar3d'), ...
	'"scalar" shuold be instancef of either Scalar2d or Scalar3d.');

% axes_handle = colorbar;

% Make sure that 0 is ticked when 0 is the minimum of the colorbar.
crange = caxis(gca);  % caxis is the property of the axes handle for a figure
ticks = get(axes_handle, 'YTick');
if crange(1) == 0 && ticks(1) > 0
	crange(1) = -eps * crange(2);
	caxis(gca, crange);
	ticks = [0 ticks];
end
set(axes_handle, 'YTick', ticks);

% Prevent 'x10^n' from showing on top of the colorbar.
ticklabel = textscan(num2str(ticks),'%s');
ticklabel = ticklabel{1};
set(axes_handle, 'YTickLabel', ticklabel);

% if scalar.unitvalue ~= 1e0
% 	str = [' (', char(hex2dec('00D7')), num2str(scalar.unitvalue, '%.2e'), ')'];
% 	title(axes_handle, str, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'baseline');
% end
str = [' (', char(hex2dec('00D7'))];
if scalar.unitvalue < 1e4 && scalar.unitvalue > 1e-3
	str = [str, num2str(scalar.unitvalue), ')'];
else
	str = [str, num2str(scalar.unitvalue, '%.2e'), ')'];
end
title(axes_handle, str, 'HorizontalAlignment', 'left', 'VerticalAlignment', 'baseline');


function F = diff(d, varargin)
%DIFF      Differentiation operator.
%   This function is deprecated. Use OPERATORBLOCK.DIFF.

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

F = linop( operatorBlock.diff(double(d), varargin{:}) );

end


classdef RectangularSensorState < AbstractSensorState
    %RectangularSensorState Summary of this class goes here
    %   Detailed explanation goes here

    properties
        sensor RectangularSensor

        activeTf(1,1) logical = true;
        steeringModel(1,1) AbstractSensorSteeringModel
        azAngle(1,1) double {mustBeGreaterThan(azAngle,0)} = deg2rad(10);
        decAngle(1,1) double {mustBeGreaterThan(decAngle,0)} = deg2rad(10);
        range(1,1) double {mustBeGreaterThan(range,0)} = 1;
    end

    methods
        function obj = RectangularSensorState(sensor, activeTf, steeringModel, azAngle, decAngle, range)
            arguments
                sensor(1,1) RectangularSensor
                activeTf(1,1) logical
                steeringModel(1,1) AbstractSensorSteeringModel
                azAngle(1,1) double {mustBeGreaterThanOrEqual(azAngle,0)}
                decAngle(1,1) double {mustBeGreaterThanOrEqual(decAngle,0)}
                range(1,1) double {mustBeGreaterThan(range, 0)}
            end
            obj.sensor = sensor;
            obj.activeTf = activeTf;
            obj.steeringModel = steeringModel;
            obj.azAngle = azAngle;
            obj.decAngle = decAngle;
            obj.range = range;
        end

        function sensor = getSensor(obj)
            sensor = obj.sensor;
        end

        function activeTf = getSensorActiveState(obj)
            activeTf = obj.activeTf;
        end

        function setSensorActiveState(obj, activeTf)
            obj.activeTf = activeTf;
        end

        function steeringModel = getSensorSteeringMode(obj)
            steeringModel = obj.steeringModel;
        end

        function setSteeringModel(obj, steeringModel)
            obj.steeringModel = steeringModel;
        end

        function range = getSensorMaxRange(obj)
            range = obj.range;
        end

        function setSensorMaxRange(obj, range)
            obj.range = range;
        end

        function azAngle = getSensorAzAngle(obj)
            azAngle = obj.azAngle;
        end

        function setSensorAzAngle(obj, azAngle)
            obj.azAngle = azAngle;
        end

        function decAngle = getSensorDecAngle(obj)
            decAngle = obj.decAngle;
        end

        function setSensorDecAngle(obj, decAngle)
            obj.decAngle = decAngle;
        end

        function angle = getMaxAngle(obj)
            angle = max([obj.getSensorAzAngle, obj.getSensorDecAngle()]);
        end
    end
end


function alpha = p19_alpha ( )

%*****************************************************************************80
%
%% P19_ALPHA returns ALPHA for problem 19.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    28 December 2011
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, real ALPHA, the value of ALPHA.
%
  alpha = 0.0;

  return
end


function setmap(hObj,event) %#ok<INUSD>
% Called when user activates popup menu
val = get(hObj,'Value');
if val ==1
        colormap(jet)
elseif val == 2
        colormap(hsv)
elseif val == 3
        colormap(hot)
elseif val == 4
        colormap(cool)
elseif val == 5
        colormap(gray)
end


function [goodTF, msg] = verifyCelBodyData(celBodyData)
    %verifyCelBodyData Summary of this function goes here
    %   Detailed explanation goes here
    goodTF = true;
    msg = {};

    numTopLvlBodies = 0;
    topLevelBodies = KSPTOT_BodyInfo.empty(1,0);
    bodyIds = [];
    bodyNames = {};
    topLevelBodyIdStrs = {};
    celBodyFields = fields(celBodyData);
    for(i=1:length(celBodyFields))
        bInfo = celBodyData.(celBodyFields{i});
        bodyIds(end+1) = bInfo.id; %#ok<AGROW>
        bodyNames{end+1} = bInfo.name; %#ok<AGROW>

        if(isempty(bInfo.parentBodyInfo))
            numTopLvlBodies = numTopLvlBodies + 1;
            topLevelBodies(end+1) = bInfo; %#ok<AGROW>
            topLevelBodyIdStrs{end+1} = fullAccNum2Str(bInfo.id); %#ok<AGROW>
        end
    end

    if(numTopLvlBodies ~= 1)
        goodTF = false;

        idStr = strjoin(topLevelBodyIdStrs,', ');
        msg{end+1} = sprintf('Multiple bodies have been detected without parents.  Only one body should be the "top-level" body without a parent body.  Detected body IDs: %s', idStr);
    end

    if(numel(bodyIds) ~= numel(unique(bodyIds)))
        goodTF = false;

        msg{end+1} = 'Duplicate body IDs were found.  Check to ensure that all bodies have unique integer ID numbers.';
    end

    if(numel(bodyNames) ~= numel(unique(bodyNames)))
        goodTF = false;

        msg{end+1} = 'Duplicate body names were found.  Check to ensure that all bodies have unique name.';
    end
end


classdef Feature2 < handle

    properties
        feature
        descriptor
    end

    methods
        function f = Feature2(ff, dd)
            if nargin == 0
                f.feature = rand(100, 3);
                f.descriptor = rand(100, 20);
            elseif nargin == 1
                f.feature =ff;
                f.descriptor = [];
            elseif nargin == 2
                f.feature =ff;
                f.descriptor = dd;
            end
        end

        function s = char(f)
            s = '';
            for i=1:numrows(f.feature)
                s = char(s, sprintf('%f %f', f.feature(i,1:2)));
            end
        end

        function display(f)
            disp( f.char() );
        end

        function z = bob(f, a,b,c)
            fprintf('nargin=%d, a=%f\n', nargin, a);
            z = a;
        end

        function out = end(f,k,n)
            k,n
            %out = end(A.feature,k,n);
            if k == 1
                out = numrows(f.feature);
            else
                out = 1;
            end
        end

        function s = size(f)
            s = [numrows(f.feature) 1];
        end

        function n = length(f)
            n = numrows(f.feature);
        end
        %{
        function n = numel(f)
            n = numrows(f.feature);
        end
        %}
    end % methods
end % classdef


function formatPlot(fig,titleString,subtitleStrings,xString,yString,X,Y,legendStrings,notes)
% Creates a set of 1x3 subplots for the given input data. Adds formatting
% based on the given x and y axes labels, legend, title, subtitles and
% notes.
%
% Parameters
% ----------
%     fig : [1 1] handle
%         Figure handle that the plots are created on
%
%     titleString : [1 1] string
%         Overall title shown above all subplots
%
%     subTitleStrings : [1 3] cell of strings
%         Subplot titles shown above each subplot
%
%     xString : [1 3] cell of strings
%         X axis label shown on each subplot
%
%     yString : [1 3] cell of strings
%         Y axis label shown on each subplot
%
%     X : [1 1] struct
%         Struct of X data. Fields numbered sequentially. The number of
%         fields is the number of datasets being plotted. Each field must
%         correspond to one field of Y (e.g. X.X1 will be the x-axis for
%         all values in Y.Y1)
%
%     Y : [1 1] struct
%         Struct of Y data. Fields numbered sequentially. The number of
%         fields is the number of datasets being plotted. Each field must
%         correspond to one field of Y and have a size of 3 in dimension 1
%
%     legendStrings : [: :] cell of strings
%         Strings shown in the legend. The size of dimension 1 must be the
%         size of Y.Y1 dimension 2. The size of dimension 2 must be the
%         number of fields in Y
%
%     notes : [1 :] cell of strings
%         Annotations shown below all subplots. Each column corresponds to
%         a new line of text

% Overall title for all subplots
sgtitle(titleString,'Interpreter','latex','FontWeight','bold','FontSize',12);

legendStrings1D = legendStrings(:);
legendStrings1D = legendStrings1D(~cellfun(@isempty, legendStrings1D));

% Figures
nHydro = length(fieldnames(X));
nBodiesTotal = 0;
for iHydro = 1:nHydro
    tmp1 = strcat('X',num2str(iHydro));
    tmp2 = strcat('Y',num2str(iHydro));
    [~,nBodies,~] = size(Y.(tmp2));
    nBodiesTotal = nBodiesTotal + nBodies;

    % Surge
    subplot('Position',[0.0731 0.3645 0.2521 0.4720])
    hold('on');
    box('on');
    for iBody = 1:nBodies
        plot(X.(tmp1),squeeze(Y.(tmp2)(1,iBody,:)),'LineWidth',1)
    end
    if iHydro == nHydro
        legend(legendStrings1D,'location','best','Box','off','Interpreter','none')
        title(subtitleStrings(1));
        xlabel(xString(1),'Interpreter','latex');
        ylabel(yString(1),'Interpreter','latex');
    end

    % Heave
    subplot('Position',[0.3983 0.3645 0.2521 0.4720]);
    hold('on');
    box('on');
    for iBody = 1:nBodies
        plot(X.(tmp1),squeeze(Y.(tmp2)(2,iBody,:)),'LineWidth',1);
    end
    if iHydro == nHydro
        legend(legendStrings1D,'location','best','Box','off','Interpreter','none')
        title(subtitleStrings(2));
        xlabel(xString(2),'Interpreter','latex');
        ylabel(yString(2),'Interpreter','latex');
    end

    % pitch
    subplot('Position',[0.7235 0.3645 0.2521 0.4720]);
    hold('on');
    box('on');
    for iBody = 1:nBodies
        plot(X.(tmp1),squeeze(Y.(tmp2)(3,iBody,:)),'LineWidth',1);
    end
    if iHydro == nHydro
        legend(legendStrings1D,'location','best','Box','off','Interpreter','none')
        title(subtitleStrings(3));
        xlabel(xString(3),'Interpreter','latex');
        ylabel(yString(3),'Interpreter','latex');
    end
end

% Footer
annotation(fig,'textbox',[0.0 0.0 1.0 0.2628],...
    'String',notes,...
    'Interpreter','latex',...
    'FitBoxToText','off',...
    'EdgeColor','none');

end


function output_image = PTKSimpleRegionGrowing(threshold_image, start_points_global, reporting)
    % PTKSimpleRegionGrowing. Performs 3D region growing through the supplied
    %     binary threshold image, starting from the specified points
    %
    %
    %     Syntax:
    %         output_image = PTKSimpleRegionGrowing(threshold_image, start_points_global, reporting)
    %
    %         Inputs:
    %         ------
    %             threshold_image - The threshold image in a PTKImage class. 1s
    %                 represents voxels which are connected
    %             start_points - an array of points, where each point is a
    %                 coordinate in the form [i, j, k]. The region growing will
    %                 begin from all these points simultaneously
    %             reporting - an object implementing CoreReportingInterface
    %                             for reporting progress and warnings
    %
    %         Outputs:
    %         -------
    %             output_image - A binary PTKImage containing the segmented region
    %                 of all voxels connected to the starting points
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    % Check the input image is of the correct form
    if ~isa(threshold_image, 'PTKImage')
        error('Requires a PTKImage as input');
    end

    if exist('reporting', 'var')
        reporting.ShowProgress('Region growing');
    end

    output_image = threshold_image.BlankCopy;
    segmented_image = zeros(threshold_image.ImageSize, 'uint8');

    [linear_offsets, ~] = MimImageCoordinateUtilities.GetLinearOffsets(threshold_image.ImageSize);
    start_points_matrix = cell2mat(start_points_global');
    start_points_matrix = threshold_image.GlobalToLocalCoordinates(start_points_matrix);
    next_points = MimImageCoordinateUtilities.FastSub2ind(threshold_image.ImageSize, start_points_matrix(:, 1), start_points_matrix(:, 2), start_points_matrix(:, 3));

    threshold_image = logical(threshold_image.RawImage);
    number_points = length(segmented_image(:));

    number_of_points_to_grow = sum(threshold_image(:));
    iteration = 0;

    while ~isempty(next_points)
        if mod(iteration, 100) == 0
            points_to_do = sum(threshold_image(:));
            reporting.UpdateProgressStage(number_of_points_to_grow - points_to_do, number_of_points_to_grow);
        end
        iteration = iteration + 1;
        all_points = GetNeighbouringPoints(next_points, linear_offsets);
        all_points = all_points(all_points > 0 & all_points <= number_points);

        list_of_neighbours_indices = all_points(threshold_image(all_points))';
        segmented_image(list_of_neighbours_indices) = 1;
        threshold_image(list_of_neighbours_indices) = false;

        next_points = list_of_neighbours_indices';
    end
    output_image.ChangeRawImage(segmented_image);

    if exist('reporting', 'var')
        reporting.CompleteProgress;
    end
 end

function list_of_point_indices = GetNeighbouringPoints(point_indices, linear_offsets)
    list_of_point_indices = repmat(point_indices, 1, 6) + repmat(linear_offsets, length(point_indices), 1);
    list_of_point_indices = unique(list_of_point_indices(:));
end


%Navigation Navigation superclass
%
% An abstract superclass for implementing planar grid-based navigation classes.
%
% Methods::
%   plot        Display the occupancy grid
%   visualize   Display the occupancy grid (deprecated)
%   plan        Plan a path to goal
%   path        Return/animate a path from start to goal
%   display     Display the parameters in human readable form
%   char        Convert to string
%
%   rand        Uniformly distributed random number
%   randn       Normally distributed random number
%   randi       Uniformly distributed random integer
%
% Properties (read only)::
%   occgrid   Occupancy grid representing the navigation environment
%   goal      Goal coordinate
%   seed0     Random number state
%
% Methods that must be provided in subclass::
%   plan      Generate a plan for motion to goal
%   next      Returns coordinate of next point along path
%
% Methods that may be overriden in a subclass::
%   goal_set        The goal has been changed by nav.goal = (a,b)
%   navigate_init   Start of path planning.
%
% Notes::
% - Subclasses the MATLAB handle class which means that pass by reference semantics
%   apply.
% - A grid world is assumed and vehicle position is quantized to grid cells.
% - Vehicle orientation is not considered.
% - The initial random number state is captured as seed0 to allow rerunning an
%   experiment with an interesting outcome.
%
% See also Dstar, Dxform, PRM, RRT.

% Copyright (C) 1993-2014, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

% Peter Corke 8/2009.

% TODO
%  keep dimensions of workspace in this object, have a setaxes() method
%  which transfers the dimensions to the current axes.

classdef Navigation < handle

    properties
        occgrid     % occupancy grid
        goal        % goal coordinate

        navhook     % function handle, called on each navigation iteration
        verbose     % verbosity
        seed            % current random seed
        spincount

        randstream
        seed0
    end

    % next() should be protected and abstract, but this doesnt work
    % properly
    methods (Abstract)
        plan(obj)
        n = next(obj)
    end % method Abstract

    methods

        % TODO fix up set methods for goal
        % setup argument callback like features, can we inherit from that.
        % occ grid should be an option

        % constructor

        function nav = Navigation(varargin)
        %Navigation.Navigation Create a Navigation object
        %
        % N = Navigation(OCCGRID, OPTIONS) is a Navigation object that holds an
        % occupancy grid OCCGRID.  A number of options can be be passed.
        %
        % Options::
        % 'navhook',F   Specify a function to be called at every step of path
        % 'goal',G      Specify the goal point (2x1)
        % 'verbose'     Display debugging information
        % 'inflate',K   Inflate all obstacles by K cells.
        % 'private'     Use private random number stream.
        % 'reset'       Reset random number stream.
        % 'seed',S      Set the initial state of the random number stream.  S must
        %               be a proper random number generator state such as saved in
        %               the seed0 property of an earlier run.
        %
        % Notes::
        % - In the occupancy grid a value of zero means free space and non-zero means
        %   occupied (not driveable).
        % - Obstacle inflation is performed with a round structuring element (kcircle)
        %   with radius given by the 'inflate' option.
        % - The 'private' option creates a private random number stream for the methods
        %   rand, randn and randi.  If not given the global stream is used.

            if nargin >= 1 && isnumeric(varargin{1}) && ~isscalar(varargin{1})
                nav.occgrid = varargin{1};
                varargin = varargin(2:end);
            end

            % default values of options
            opt.goal = [];
            opt.inflate = 0;
            opt.navhook = [];
            opt.private = false;
            opt.reset = false;
            opt.seed = [];

            [opt,args] = tb_optparse(opt, varargin);

            % optionally inflate the obstacles
            if opt.inflate > 0
                nav.occgrid = idilate(nav.occgrid, kcircle(opt.inflate));
            end

            % copy other options into the object
            nav.verbose = opt.verbose;
            nav.navhook = opt.navhook;
            if ~isempty(opt.goal)
                nav.goal = opt.goal(:)';
            end

            % create a private random number stream if required
            if opt.private
                nav.randstream = RandStream.create('mt19937ar');
            else
                nav.randstream = RandStream.getGlobalStream();
            end

            % reset the random number stream if required
            if opt.reset
                nav.randstream.reset();
            end

            % return the random number stream to known state if required
            if ~isempty(opt.seed)
                set(nav.randstream.set(opt.seed));
            end

            % save the current state in case it later turns out to give interesting results
            nav.seed0 = nav.randstream.State;

            nav.spincount = 0;
        end

        function r = rand(nav, varargin)
        %Navigation.rand Uniformly distributed random number
        %
        % R = N.rand() return a uniformly distributed random number from
        % a private random number stream.
        %
        % R = N.rand(M) as above but return a matrix (MxM) of random numbers.
        %
        % R = N.rand(L,M) as above but return a matrix (LxM) of random numbers.
        %
        % Notes::
        % - Accepts the same arguments as rand().
        % - Seed is provided to Navigation constructor.
        % - Provides an independent sequence of random numbers that does not
        %   interfere with any other randomised algorithms that might be used.
        %
        % See also Navigation.randi, Navigation.randn, rand, RandStream.
            r = nav.randstream.rand(varargin{:});
        end

        function r = randn(nav, varargin)
        %Navigation.randn Normally distributed random number
        %
        % R = N.randn() returns a normally distributed random number from
        % a private random number stream.
        %
        % R = N.randn(M) as above but returns a matrix (MxM) of random numbers.
        %
        % R = N.randn(L,M) as above but returns a matrix (LxM) of random numbers.
        %
        %
        % Notes::
        % - Accepts the same arguments as randn().
        % - Seed is provided to Navigation constructor.
        % - Provides an independent sequence of random numbers that does not
        %   interfere with any other randomised algorithms that might be used.
        %
        % See also Navigation.rand, Navigation.randi, randn, RandStream.
            r = nav.randstream.randn(varargin{:});
        end

        function r = randi(nav, varargin)
        %Navigation.randi Integer random number
        %
        % I = N.randi(RM) returns a uniformly distributed random integer in the
        % range 1 to RM from a private random number stream.
        %
        % I = N.randi(RM, M) as above but returns a matrix (MxM) of random integers.
        %
        % I = N.randn(RM, L,M) as above but returns a matrix (LxM) of random integers.
        %
        %
        % Notes::
        % - Accepts the same arguments as randn().
        % - Seed is provided to Navigation constructor.
        % - Provides an independent sequence of random numbers that does not
        %   interfere with any other randomised algorithms that might be used.
        %
        % See also Navigation.rand, Navigation.randn, randi, RandStream.
            r = nav.randstream.randi(varargin{:});
        end

        % invoked whenever the goal is set
        function set.goal(nav, goal)

            if ~isempty(nav.occgrid) && nav.occgrid( goal(2), goal(1)) == 1
                error('Navigation: cant set goal inside obstacle');
            end

            goal = goal(:);
            if ~(all(size(goal) == size(nav.goal)) && all(goal == nav.goal))
                % goal has changed
                nav.goal = goal(:);
                nav.goal_change();
            end
        end

        function goal_change(nav)
            %Navigation.goal_change Notify change of goal
            %
            % Invoked when the goal property of the object is changed.  Typically this
            % is overriden in a subclass to take particular action such as invalidating
            % a costmap.
        end

        function pp = path(nav, start)
            %Navigation.path Follow path from start to goal
            %
            % N.path(START) animates the robot moving from START (2x1) to the goal (which is a
            % property of the object).
            %
            % N.path() as above but first displays the occupancy grid, and prompts the user to
            % click a start location.
            % the object).
            %
            % X = N.path(START) returns the path (2xM) from START to the goal (which is a property of
            % the object).
            %
            % The method performs the following steps:
            %
            %  - Get start position interactively if not given
            %  - Initialize navigation, invoke method N.navigate_init()
            %  - Visualize the environment, invoke method N.plot()
            %  - Iterate on the next() method of the subclass until the goal is
            %    achieved.
            %
            % See also Navigation.plot, Navigation.goal.

            % if no start point given, display the map, and prompt the user to select
            % a start point
            if nargin < 2
                % display the world
                nav.plot();

                % prompt the user to click a goal point
                fprintf('** click a starting point ');
                [x,y] = ginput(1);
                fprintf('\n');
                start = round([x;y]);
            end
            start = start(:);

            % if no output arguments given, then display the world
            if nargout == 0
                % render the world
                nav.plot();
                hold on
            end

            nav.navigate_init(start);

            p = [];
            % robot is a column vector
%             if nav.backProp()==1
%                 % subclass algorithm calls for back propagation
%                 robot = nav.goal(:);
%             else
%                 robot = start;
%             end
robot = start;

            % iterate using the next() method until we reach the goal
            while true
                if nargout == 0
                    plot(robot(1), robot(2), 'g.', 'MarkerSize', 12);
                    drawnow
                end

                % move to next point on path
                robot = nav.next(robot);

                % are we there yet?
                if isempty(robot)
                    % yes, exit the loop
                    break
                else
                    % no, append it to the path
                    p = [p; robot(:)'];
                end

                % invoke the navhook function
                if isa(nav.navhook, 'function_handle')
                    nav.navhook(nav, robot(1), robot(2));
                end
            end

            % only return the path if required
            if nargout > 0
                pp = p;
            end
        end

        function visualize(nav, varargin)
            warning('visualize method deprecated for Navigation classes, use plot instead');
            nav.plot(varargin{:});
        end

        function plot(nav, varargin)
        %Navigation.plot  Visualize navigation environment
        %
        % N.plot() displays the occupancy grid in a new figure.
        %
        % N.plot(P) as above but overlays the points along the path (2xM) matrix.
        %
        % Options::
        %  'goal'         Superimpose the goal position if set
        %  'distance',D   Display a distance field D behind the obstacle map.  D is
        %                 a matrix of the same size as the occupancy grid.
        %
        % Notes::
        % - The distance field at a point encodes its distance from the goal, small
        %   distance is dark, a large distance is bright.  Obstacles are encoded as
        %   red.

            opt.goal = false;
            opt.distance = [];

            [opt,args] = tb_optparse(opt, varargin);

            clf
            if isempty(opt.distance)
                % create color map for free space + obstacle:
                %   free space, color index = 1, white,
                %   obstacle, color index = 2, red
                cmap = [1 1 1; 1 0 0];  % non obstacles are white
                image(nav.occgrid+1, 'CDataMapping', 'direct');
                colormap(cmap)

            else
                % create color map for distance field + obstacle:
                %   obstacle, color index = 1, red
                %   free space, color index > 1, greyscale

                % find maximum distance, ignore infinite values in
                % obstacles
                d = opt.distance(isfinite(opt.distance));
                maxdist = max(d(:)) + 1;

                % create the color map
                cmap = [1 0 0; gray(maxdist)];

                % ensure obstacles appear as red pixels
                opt.distance(nav.occgrid > 0) = 0;

                % display it with colorbar
                image(opt.distance+1, 'CDataMapping', 'direct');
                set(gcf, 'Renderer', 'Zbuffer')
                colormap(cmap)
                colorbar
            end

            % label the grid
            set(gca, 'Ydir', 'normal');
            xlabel('x');
            ylabel('y');
            grid on
            hold on

            if ~isempty(args)
                p = args{1};
                if numcols(p) ~= 2
                    error('expecting Nx2 matrix of points');
                end
                plot(p(:,1), p(:,2), 'g.', 'MarkerSize', 12);
            end

            if ~isempty(nav.goal) && opt.goal
                plot(nav.goal(1), nav.goal(2), 'bd', 'MarkerFaceColor', 'b');
            end
            hold off
        end

        function navigate_init(nav, start)
            %Navigation.navigate_init Notify start of path
            %
            % N.navigate_init(start) is called when the path() method is invoked.
            % Typically overriden in a subclass to take particular action such as
            % computing some path parameters. start is the initial position for this
            % path, and nav.goal is the final position.
        end

        function display(nav)
        %Navigation.display Display status of navigation object
        %
        % N.display() displays the state of the navigation object in
        % human-readable form.
        %
        % Notes::
        % - This method is invoked implicitly at the command line when the result
        %   of an expression is a Navigation object and the command has no trailing
        %   semicolon.
        %
        % See also Navigation.char.
            loose = strcmp( get(0, 'FormatSpacing'), 'loose');
            if loose
                disp(' ');
            end
            disp([inputname(1), ' = '])
            disp( nav.char() );
        end % display()

        function s = char(nav)
        %Navigation.char Convert to string
        %
        % N.char() is a string representing the state of the navigation
        % object in human-readable form.
            s = [class(nav) ' navigation class:'];
            s = char(s, sprintf('  occupancy grid: %dx%d', size(nav.occgrid)));
            if ~isempty(nav.goal)
                if length(nav.goal) == 2
                    s = char(s, sprintf('  goal: (%d,%d)', nav.goal) );
                else
                    s = char(s, sprintf('  goal: (%g,%g, %g)', nav.goal) );

                end
            end
        end

        function verbosity(nav, v)
        %Navigation.verbosity Set verbosity
        %
        % N.verbosity(V) set verbosity to V, where 0 is silent and greater
        % values display more information.
            nav.verbose = v;
        end

        % called at each point on the path as
        %   navhook(nav, robot)
        %
        % can be used for logging data, animation, etc.
        function navhook_set(nav, navhook)
            nav.navhook = navhook;
        end

        function message(nav, varargin)
        %Navigation.message Print debug message
        %
        % N.message(S) displays the string S if the verbose property is true.
        %
        % N.message(FMT, ARGS) as above but accepts printf() like semantics.
            if nav.verbose
                fprintf([class(nav) ' debug:: ' sprintf(varargin{:}) '\n']);
            end
        end

        function spinner(nav)
        %Navigation.spinner Update progress spinner
        %
        % N.spinner() displays a simple ASCII progress spinner, a rotating bar.
            spinchars = '-\|/';
            nav.spincount = nav.spincount + 1;
            fprintf('\b%c', spinchars( mod(nav.spincount, length(spinchars))+1 ) );
        end

    end % method

end % classde


function [vw,newMeshNum] = meshBuild(vw,hemisphere)
% Build a 3D mesh for visualization and analysis
%
%   [vw,newMeshNum] = meshBuild(vw,[hemisphere]);
%
%  Using mrVista data, build a mesh, save it in a file in the anatomy
%  directory, and add the mesh to the 3D Control Window pull down
%  options.
%
% vw:          A VISTASOFT view structure
% hemisphere:  left, right or both.  Default: left
%
% A mrMesh window is opened as well, showing the computed mesh.
%
% Example:
%    [VOLUME{1},newMeshNum] = meshBuild(VOLUME{1},'left');
%    VOLUME{1} = viewSet(VOLUME{1},'currentmeshn',newMeshNum);
%
% See also:  meshBuildFromClass, meshBuildFromNiftiClass, meshSmooth,
%            meshColor
%
% 11/05 ras: also saves mesh path.
%
% (c) Stanford VISTA Team 2008

% Programming TODO.  Check this!
%   We have (or had?) trouble for building 'both' meshes.  We need a new
%   procedure.

% Be sure anatomy is loaded (we need it for the mmPerVox field)
if isempty(vw.anat), vw = loadAnat(vw); end
if ieNotDefined('hemisphere'), hemisphere = 'left'; end

newMeshNum = viewGet(vw,'nmesh') + 1;

% Parameters we establish in this routine
[meshName,numGrayLayers,hemiNum] = readParams(newMeshNum,hemisphere);
if isempty(meshName), newMeshNum = newMeshNum - 1; return; end   % User pressed cancel.

% mmPerVox = viewGet(vw,'mmPerVoxel');

wbar = mrvWaitbar(0.1, ...
    sprintf('meshBuild: Combining white and gray matter...'));

% Load left, right, or both hemispheres.
if (hemiNum==1)
    [voxels,vw] = meshGetWhite(vw, 'left', numGrayLayers);
elseif (hemiNum==2)
    [voxels,vw] = meshGetWhite(vw, 'right', numGrayLayers);
elseif (hemiNum == 0)
    [voxels,vw] = meshGetWhite(vw, 'left', numGrayLayers);
    [voxels,vw] = meshGetWhite(vw, 'right', numGrayLayers,voxels);
end

% host = 'localhost';
% windowID = -1;

% We build a smoothed (mesh) and an unsmoothed mesh (tenseMesh) with these calls
mrvWaitbar(0.35,wbar,sprintf('Building mesh'));
[newMesh, tenseMesh] = mrmBuild(voxels,viewGet(vw,'mmPerVox'),1);

% Must have a name
newMesh   = meshSet(newMesh,'name',meshName);
tenseMesh = meshSet(tenseMesh,'name',sprintf('%s-tense',meshName));

% mrvWaitbar(0.65,wbar,sprintf('meshBuild: Unsmoothed mesh vertex to gray mapping'));
initVertices = meshGet(tenseMesh,'vertices');
newMesh = meshSet(newMesh,'initialvertices',initVertices);
vertexGrayMap = mrmMapVerticesToGray(...
    initVertices, ...
    viewGet(vw,'nodes'), ...
    viewGet(vw,'mmPerVox'),...
    viewGet(vw,'edges'));

newMesh = meshSet(newMesh,'vertexGrayMap',vertexGrayMap);
newMesh = meshSet(newMesh,'name',meshName);
newMesh = meshSet(newMesh,'nGrayLayers',numGrayLayers);

mrvWaitbar(0.9,wbar,sprintf('meshBuild: Saving mesh file %s',meshGet(newMesh,'name')));

% Save mesh file
[newMesh newMesh.path] = mrmWriteMeshFile(newMesh);

mrvWaitbar(1,wbar,sprintf('meshBuild: Done'));
pause(0.5);
close(wbar);

% Now refresh the UI
vw = viewSet(vw,'add and select mesh',newMesh);

return;

%---------------------------------------
function classFile = verifyClassFile(vw,hemisphere)

classFile =  viewGet(vw,'classFileName',hemisphere);
str = sprintf('Class %s',classFile);

r=questdlg(str);
if ~strcmp(r,'Yes')
    switch hemisphere
        case 'left'
            vw = viewSet(vw,'leftClassFileName',[]);
        case 'right'
            vw = viewSet(vw,'rightClassFileName',[]);
    end
    classFile =  viewGet(vw,'classFileName',hemisphere);
end

return;

%---------------------------------------
function voxels = classExtractWhite(voxels,data,voi,whiteValue)
%

% ras 05/07: the indexing of data seems off to me -- is this correct?
voxels(voi(1):voi(2), voi(3):voi(4), voi(5):voi(6)) = ...
    voxels(voi(1):voi(2), voi(3):voi(4), voi(5):voi(6)) ...
    | (data(voi(1):voi(2), voi(3):voi(4), voi(5):voi(6)) == whiteValue);

return;

%----------------------------------------
function [meshName,numGrayLayers,hemiNum,alpha,restrictVOI,relaxIterations] = ...
    readParams(newMeshNum,hemisphere)
%
%  readParams
%
% Internal routine to read the parameters for meshBuild
%
meshName = sprintf('%sSmooth',hemisphere);
numGrayLayers = 0;
switch hemisphere
    case 'left'
        hemiNum = 1;
    case 'right'
        hemiNum = 2;
    case 'both'
        hemiNum = 0;
end

% transparency level (transparency is off by default, but if it gets turned
% on, this alpha parameter will have an effect).
alpha = 200;
restrictVOI = 1;
relaxIterations = 0.2;

prompt = {'Mesh Name:',...
        'Number of Gray Layers (0-4):',...
        'Hemisphere (0=both, 1=left, 2=right):',...
        % 'Default alpha (0-255):',...
        % 'Inflation (0=none, 1=lots):',...
        % 'Restrict to class VOI (0|1):'};
        };
defAns = {meshName,...
        num2str(numGrayLayers),...
        num2str(hemiNum),...
        % num2str(alpha),...
        % num2str(relaxIterations),...
        % num2str(restrictVOI)};
        };

resp = inputdlg(prompt, 'meshBuild Parameters', 1, defAns);

if(~isempty(resp))
    meshName = resp{1};
    numGrayLayers = str2num(resp{2});
    hemiNum = str2num(resp{3});
    % alpha = str2num(resp{4});
    % relaxIterations = round(str2num(resp{5})*160);  % Arbitrary choice, scales iters [0,160]
    % restrictVOI = str2num(resp{6});
else
    meshName = [];
    numGrayLayers = [];
    hemiNum = [];
    % alpha = [];
    % relaxIterations = [];  % Arbitrary choice, scales iters [0,160]
    % restrictVOI = [];
end

return;

%---------------------------------
function [voxels,vw] = meshGetWhite(vw, hemiName, numGrayLayers, voxels)
%
%
%

if ieNotDefined('vw'), error('You must send in a volume vw'); end
if ieNotDefined('hemiName'), error('You must define right,left or both'); end
if ieNotDefined('numGrayLayers'), numGrayLayers = 0; end

classFile = verifyClassFile(vw,hemiName);
if isempty(classFile),
    close(wbar); newMeshNum = -1;
    voxels = [];
    return;
end
classFileParam = [hemiName,'ClassFile'];
vw       = viewSet(vw,classFileParam,classFile);

classData = viewGet(vw,'classdata',hemiName);
if ieNotDefined('voxels'),
    voxelsOld = uint8(zeros(classData.header.xsize, ...
        classData.header.ysize, ...
        classData.header.zsize));
else
    voxelsOld = voxels;
end
voxels = zeros(classData.header.xsize, ...
        classData.header.ysize, ...
        classData.header.zsize);

% Restrict the white matter volume to a size equal to the ROI in which it
% was selected
voxels = classExtractWhite(voxels,...
    classData.data,classData.header.voi,classData.type.white);
%   msh = meshColor(meshSmooth(meshBuildFromClass(voxels,[1 1 1])));
%   meshVisualize(msh);

% Add the gray matter
if(numGrayLayers>0)

    [nodes,edges,classData] = mrgGrowGray(classData,numGrayLayers);
    voxels = ...
        uint8( (classData.data == classData.type.white) | ...
        (classData.data == classData.type.gray));
end

voxels = uint8(voxels | voxelsOld);

return;


function spm_progress_bar(action,varargin)
% Display a 'Progress Bar' in the 'Interactive' window
% FORMAT spm_progress_bar('Init',height,xlabel,ylabel,flgs)
% Initialises the bar in the 'Interactive' window.
% If flgs contains a 't', then use tex interpreter for labels.
%
% FORMAT spm_progress_bar('Set',value)
% Sets the height of the bar itself.
%
% FORMAT spm_progress_bar('Clear')
% Clears the 'Interactive' window.
%_______________________________________________________________________
% Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging

% John Ashburner
% $Id$

if ~nargin, action = 'Init'; end

% Find the interactive window and exit if not
%-----------------------------------------------------------------------
Finter = spm_figure('FindWin','Interactive');
if isempty(Finter), return; end

switch lower(action)
    % Initialise
    %-------------------------------------------------------------------
    case 'init'
        error(nargchk(0,5,nargin));
        if nargin > 1, arg1 = varargin{1}; else arg1 = 1;           end
        if nargin > 2, arg2 = varargin{2}; else arg2 = 'Computing'; end
        if nargin > 3, arg3 = varargin{3}; else arg3 = '';          end
        if nargin > 4, arg4 = varargin{4}; else arg4 = ' ';         end
        if any(arg4 == 't'), interp = 'tex'; else interp = 'none';  end
        pb = struct('pointer',get(Finter,'Pointer'),...
                    'name'   ,get(Finter,'Name'),...
                    'buffer', get(Finter,'DoubleBuffer'));
        spm_progress_bar('Clear');
        set(Finter,'Pointer','watch');
        set(Finter,'Name',pb.name);
        set(Finter,'DoubleBuffer','on');
        pb.ax = axes('Position', [0.45 0.2 0.05 0.6],...
                     'XTick',    [],...
                     'Xlim',     [0 1],...
                     'Ylim',     [0 max([arg1 eps])],...
                     'Box',      'on',...
                     'Parent',   Finter);
        lab = get(pb.ax,'Xlabel');
        set(lab,'string',arg2,'FontSize',10,'Interpreter',interp);
        lab = get(pb.ax,'Ylabel');
        set(lab,'string',arg3,'FontSize',10,'Interpreter',interp);
        lab = get(pb.ax,'Title');
        set(lab,'string','0% Complete','Interpreter',interp);
        t = clock;
        str = sprintf('Began %2.0f:%02.0f:%02.0f',t(4),t(5),t(6));
        text(2,arg1/2,0,str,'FontSize',10,'Parent',pb.ax);
        l = line('Xdata',     [0.5 0.5],...
                 'Ydata',     [0 0],...
                 'LineWidth', 8,...
                 'Color',     [1 0 0],...
                 'Tag',       'ProgressBar',...
                 'Parent',    pb.ax);
        set(l,'UserData',pb);
        drawnow;

    % Set
    %-------------------------------------------------------------------
    case 'set'
        error(nargchk(1,2,nargin));
        if nargin == 1, value = 0; else  value = varargin{1}; end
        br = findobj(Finter,'Tag','ProgressBar');
        if ~isempty(br)
            pb = get(br,'UserData');
            set(br,'Ydata',[0 value]);
            lim = get(get(br,'Parent'),'Ylim');lim=lim(2);
            lab = get(pb.ax,'Title');
            set(lab,'string',sprintf('%.0f%% Complete',100*value/lim));
            drawnow;
        end

    % Clear
    %-------------------------------------------------------------------
    case 'clear'
        error(nargchk(1,1,nargin));
        pb = get(findobj(Finter,'Tag','ProgressBar'),'UserData');
        spm_figure('Clear',Finter);
        if isstruct(pb)
            set(Finter,'Pointer',     pb.pointer);
            set(Finter,'Name',        pb.name);
            set(Finter,'DoubleBuffer',pb.buffer);
        end
        drawnow;

    % Error
    %-------------------------------------------------------------------
    otherwise
        error('Unknown action string');
end


function NSxToHL(fname)

% NSxToHL
%
% Opens and reads an NSx file without the header information and saves
% the binary data into a .dat file with the same name. This can be used for
% specific applications that require this type of data, e.g. Klusters.
% Works with File Spec 2.1, 2.2 and 2.3.
%
% It does not support pauses at this time.
%
% Use OUTPUT = NSxToHL(fname)
%
% All input arguments are optional.
%
%   fname:        Name of the file to be opened. If the fname is omitted
%                 the user will be prompted to select a file.
%                 DEFAULT: Will open Open File UI.
%
%   OUTPUT:       Contains the binary data.
%
%   Example 1:
%   NSxToHL('c:\data\sample.ns5');
%
%   In the example above, the file c:\data\sample.ns5 will be opened and
%   the data will be read and saved without the header information in file
%   sample.ns5.dat.
%
%   Example 2:
%   NSxToHL;
%
%   In the example above, the file user will be prompted for the file. The
%   selected file (e.g. FILENAME.NSx) will be opened and the data will be
%   read and saved in the file FILENAME.NSx.dat.
%
%   Kian Torab
%   kian@blackrockmicro.com
%   Blackrock Microsystems
%   Version 1.0.0.0
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Version History
%
% 1.0.0.0:
%   - Initial release.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Opening the file
% Popup the Open File UI. Also, process the file name, path, and extension
% for later use, and validate the entry.
if ~exist('fname', 'var')
    if ~ismac
        [fname, path] = getFile('*.ns*', 'Choose an NSx file...');
    else
        [fname, path] = getFile('*.*', 'Choose an NSx file...');
    end
    if fname == 0
        disp('No file was selected.');
        if nargout
            clear variables;
        end
        return;
    end
else
    if isempty(fileparts(fname))
        fname = which(fname);
    end
    [path,fname, fext] = fileparts(fname);
    fname = [fname fext];
    path  = [path '/'];
end
if fname==0
    return;
end

%% Reading the headerless file
data = openNSxHL([path fname]);

%% Writing to file
% Determining the filename for the converted file
newFilename = [path fname '.dat'];

% Opening the output file for saving
FIDw = fopen(newFilename, 'w+', 'ieee-le');

% Writing data into file
disp('Writing the converted data into the new .dat file...');
fwrite(FIDw, data, 'int16');


function e = end(X,k,n)
%END Last index of indexing expression for tensor.
%
%   The expression X(end,:,:) will call END(X,1,3) to determine
%   the value of the first index.
%
%   See also TENSOR, TENSOR/SUBSREF, END.
%
%MATLAB Tensor Toolbox.
%Copyright 2012, Sandia Corporation.

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

if n > ndims(X)
  error('Subscript out of range.');
end
e = X.size(k);


function extractSubsetFeaturesfromFile(fileName, featureList)
% This function takes a tab delimited file of features (colums) and samples
% (rows) as input and extracts a desired subset of features and their
% corresponding value for each sample.
%
% INPUT
% fileName      file name
% featureList   list of features (must be overlapping with the feature
%               names given in the first row of the file)
%
% OUTPUT
% an output file will be written containing only the subset - the data will
% be comma separated
%
% Ines Thiele, July '22

clear keep colW tline rows fid

fid=fopen(fileName);
tline = fgetl(fid);

cnt = 1;
while ischar(tline)
    %disp(tline);
    % split line
    if cnt == 1 % header
        col = split(tline,'	');
        % get the wanted colum numbers
        colW = find(ismember(col,featureList));
        colW = [1;colW]; % add the first col with data point name
        keep{cnt,1} = col{colW(1)};
        s = ',';
        for i = 2 : length(colW)
            keep{cnt} = strcat(keep{cnt},s,col{colW(i)});
        end
        cnt = cnt + 1;
    else
        %now get only the wanted cols
        rows = split(tline,'	');
        keep{cnt,1} = rows{colW(1)};
        s = ',';
        for i = 2 : length(colW)
            keep{cnt} = strcat(keep{cnt},s,rows{colW(i)});
        end
        cnt = cnt + 1;
    end
    tline = fgetl(fid);
    if mod(cnt,1000)==1
        cnt
    end
end
fclose(fid);

fid =fopen([fileName '_subset' '.txt'], 'w');
for j = 1 : length(keep)-1
    fprintf(fid,strcat(keep{j},'\n'));
end


function F = lininterp1f(X,Y,XI,Ydefault)

disp('For fast linear interpolation, download lininterp1f from Mathworks')
disp('file exchange (File ID: #8627) or use alternative interpolator')
disp('http://www.mathworks.com/matlabcentral/fileexchange/8627-fast-linear-interpolation')
disp(' ')
disp('Place lininterp1f in CORE\utilities')


function rgb_display ( rgb, header )

%*****************************************************************************80
%
%% RGB_DISPLAY displays an RGB dataset.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 August 2013
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Nick Berry,
%    A "Practical" Use for Genetic Programming,
%    http://www.datagenetics.com/blog.html
%
%  Parameters:
%
%    Input, uint8 RGB(256,256,3), the RGB information.
%
%    Input, string HEADER, an identifier used for the title and filename.
%
  imshow ( rgb )
  title ( header, 'FontSize', 16 )

  filename = sprintf ( '%s.png', header );
  print ( '-dpng', filename );

  return
end


function pdvparamsgui(varargin)
%PDVPARAMSGUI Allows one to set PDV parameters through a GUI
%
% Written by: Tim Cox, NRL, and Wade Schwartzkopf, NGA/IDT
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

%% Parse input arguments
p = inputParser; % Extract parameter-value pairs
p.KeepUnmatched=true;
p.addParamValue('filename','');
p.addParamValue('aoi',[0 0 0 0]);
p.addParamValue('segment',1);
p.parse(varargin{:});

%% Draw figure
fig_hand = figure('MenuBar','none','Toolbar','none','NumberTitle','off',...
    'Name','PDV','Units','Pixels','Position',[0 0 300 250]);
movegui(fig_hand,'center');

% Pixel shift
uicontrol('Style','Text','String','Pixel Shift:',...
    'Units','normalized','Position',[.05 .7 .2 .1],'parent',fig_hand,...
    'BackgroundColor',get(fig_hand,'Color'));
edit_ps = uicontrol('Style','Edit','String','0.25',...
    'Units','normalized','Position',[.25 .7 .15 .11],'parent',fig_hand);

% Direction
bg_dir = uibuttongroup('Units','normalized','Position',[.05 .25 .35 .35],...
    'Title','Direction','BackgroundColor',get(fig_hand,'Color'));
radio_st = uicontrol('Style','Radio','String','Slow-Time',...
    'Units','normalized','Position',[.1 .65 .9 .2],'parent',bg_dir,...
    'BackgroundColor',get(fig_hand,'Color'));
radio_ft = uicontrol('Style','Radio','String','Fast-Time',...
    'Units','normalized','Position',[.1 .25 .9 .2],'parent',bg_dir,...
    'BackgroundColor',get(fig_hand,'Color'));

% Window size
uip_smooth = uipanel('Units','normalized','Position',[.45 .6 .5 .35],'parent',fig_hand,...
    'Title','Smoothing Window','BackgroundColor',get(fig_hand,'Color'));
uicontrol('Style','Text','String','Azimuth:',...
    'Units','normalized','Position',[.05 .6 .4 .3],'parent',uip_smooth,...
    'BackgroundColor',get(fig_hand,'Color'));
edit_az = uicontrol('Style','Edit','String','5',...
    'Units','normalized','Position',[.45 .6 .2 .35],'parent',uip_smooth);
uicontrol('Style','Text','String','Pixels',...
    'Units','normalized','Position',[.7 .6 .25 .3],'parent',uip_smooth,...
    'BackgroundColor',get(fig_hand,'Color'));
uicontrol('Style','Text','String','Range:',...
    'Units','normalized','Position',[.05 .1 .4 .3],'parent',uip_smooth,...
    'BackgroundColor',get(fig_hand,'Color'));
edit_rng = uicontrol('Style','Edit','String','5',...
    'Units','normalized','Position',[.45 .1 .2 .35],'parent',uip_smooth);
uicontrol('Style','Text','String','Pixels',...
    'Units','normalized','Position',[.7 .1 .25 .3],'parent',uip_smooth,...
    'BackgroundColor',get(fig_hand,'Color'));

% Fitler type
bg_ft = uibuttongroup('Units','normalized','Position',[.45 .25 .5 .35],...
    'Title','Filter Type','BackgroundColor',get(fig_hand,'Color'));
radio_mean = uicontrol('Style','Radio','String','Mean',...
    'Units','normalized','Position',[.1 .65 .9 .2],'parent',bg_ft,...
    'BackgroundColor',get(fig_hand,'Color'));
radio_med = uicontrol('Style','Radio','String','Median',...
    'Units','normalized','Position',[.1 .25 .9 .2],'parent',bg_ft,...
    'BackgroundColor',get(fig_hand,'Color'));
uicontrol('Style','pushbutton','String','Run','FontWeight','bold',...
    'Units','normalized','Position',[.35 .05 .3 .15],'parent',fig_hand,...
    'Callback',@Run_Callback);

    %% Callback for button press
    function Run_Callback(hObject, eventdata)
        if get(radio_st,'Val')
            Dim = 1;
        else
            Dim = 2;
        end

        if get(radio_mean,'Value')
            filtertype = 'mean';
        else
            filtertype = 'median';
        end

        if ~isempty(p.Results.filename)
            %now generate PDV for specified file and AOI
            if (p.Results.aoi(1) == 0)
                AzLimits = 'full';
                RgLimits = 'full';
            else
                AzLimits = round([p.Results.aoi(1)  p.Results.aoi(1)+p.Results.aoi(3)-1]);
                RgLimits = round([p.Results.aoi(2)  p.Results.aoi(2)+p.Results.aoi(4)-1]);
            end
            tmp_name=tempname;
            tmp_name2=tempname;

            pdvfile(p.Results.filename,tmp_name,...
                'azlimits',AzLimits,'rnglimits',RgLimits,...
                'framenumber',p.Results.segment,...
                'deltax',str2double(get(edit_ps,'String')),...
                'dim',Dim,...
                'filtersize',[str2double(get(edit_az,'String')) str2double(get(edit_rng,'String'))],...
                'filtertype',filtertype);
            chipfile(p.Results.filename,tmp_name2,...
                'azlimits',AzLimits,'rnglimits',RgLimits,...
                'framenumber',p.Results.segment);

            %launch MITM viewer to view PDV
            mitm_viewer({tmp_name tmp_name2},'initialRemap','linearremap');
            set(gcf,'DeleteFcn',@file_cleanup); % Delete temp files on closing
        else
            pdvdemo('deltax',str2double(get(edit_ps,'String')),...
                'dim',Dim,...
                'filtersize',[str2double(get(edit_az,'String')) str2double(get(edit_rng,'String'))],...
                'filtertype',filtertype);
        end
        close(fig_hand);

        function file_cleanup(obj, eventdata)
            delete(get(obj,'Children')); % Calls destructor for hg_mitm_viewer, which releases files
            % Clean up intermediate files
            delete(tmp_name);
            delete(tmp_name2);
        end
    end
end

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


function layer = genNetworkLSTMEncoderDecoderScale(para)

layer = genNetworkLSTMEncoderDecoder(para);

layerScale.name = 'Input';
layerScale.inputIdx = 3;
layerScale.dim = [1 1];
layerScale.next = 1;

layer = [layer(1:end-1) layerScale layer(end)];

layer{end-3}.next = 3;
layer{end-2}.next = 2;
layer{end}.prev = [-3 -2 -1];
% layer{end} = rmfield(layer{end}, 'costFrameSelection');

end


function hax = tsgpplot(x, Y, E, varargin)
% function tsgpplot(x, Mu, E)
%
% Plots d signals.
% x = inputs (n x 1)
% Y = expected outputs (n x d)
% E = errors of the outputs (n x d)

opts = struct('pseudoinputs', []);
[ opts, errmsg, wrnmsg ] = argschk( opts, varargin{:} );
if ~isempty(errmsg), error( errmsg ), end
if ~isempty(wrnmsg), warning( wrnmsg ), end

figure

n = size(Y,2);
for i=1:n
  params = {};
  if ~isempty(opts.pseudoinputs)
    params = [params(:); {'pseudoinputs'}; {opts.pseudoinputs{i}}];
  end
  hax(i) = subplot(n,1,i);
  gpplot(x(:),Y(:,i),E(:,i), params{:});

  set( gca, 'xlim', [ min(x) max(x) ] )

  pos_ax = get( gca, 'Position' );
  hgt_ax = (0.95 - 0.1) / ( n + (n-1)*0.1 );
  hgt_sp = hgt_ax * 0.1;
  pos_ax(1) = 0.1;
  pos_ax(2) = 0.95 - (i-1)*( hgt_ax + hgt_sp ) - hgt_ax;
  pos_ax(3) = 0.84;
  pos_ax(4) = hgt_ax;
  set( gca, 'Position', pos_ax )
  if i ~= n
    disp('removing x tick labels')
    set( gca, 'XTickLabel', [] )
  end
  axis tight

end

if nargout < 1
  clear hax;
end