% help2html() - Convert a Matlab m-file help-message header into an .html help file
%
% Usage:
%  >> linktext = help2html( filein, fileout, 'key1', val1, 'key2', val2 ...);
%
% Inputs:
%   filein       - input filename  (with .m extension)
%   fileout      - output filename (if empty, generated automatically)
%
% Optional inputs:
%   'header'     - command to insert in the header (i.e. javascript
%                   declaration or meta-tags). {default: none}.
%   'footer'     - command to insert at the end of the .html file (e.g.,
%                   back button). {default: none}.
%   'refcall'    - syntax to call references. {default: '%s.html'} For
%                  javascript function uses 'javascript:funcname(''%s.js'')'
%   'font'       - font name
%   'background' - background tag (i.e. '').
%                   {default: none}.
%   'outputlink' - html command text to link to the generated .html page.
%                  Must contain two '%s' symbols to the function title
%                  and to the function link.
%                  Ex: ... href="%s.html" ... {default: standard .html href}.
%   'outputtext' - Text used in the outputlink. {default: the function
%                  name}
%   'outputonly' - ['on'|'off'] Only generate the linktext {default: 'off'}
%
% Output:
%   fileout      - .html file written to disk
%   linktext      - html-text link to the output file
%
% M-file format:
%   The following lines describe the header format of an m-file function
%   to allow .html help file generation. Characters '-' and ':' are used
%   explicitly by the function for parsing.
%
%%    function_name() - description line 1
%%                      description line 2
%%                      etc.
%%
%%    Title1:
%%      descriptor1  - text line 1
%%                     text line 2
%%      descriptor2  - [type] text line 1
%%      "descriptor 3" - text line 1 (see notes)
%%                       etc.
%%
%%    Title2:
%%      text line 1 [...](see notes)
%%      text line 2
%%
%%    See also:
%%     function1(), function2()
%
% Author:  Arnaud Delorme, Salk Institute 2001
%
% Notes: 1) The text lines below Title2 are considered as is (i.e.,
%           preserving Matlab carriage returns) unless there is a
%           Matlab continuation cue ('...'). In this case, lines are
%           contcatenated. As below 'Title1', all text lines following
%           each  descriptor (i.e., single_word followed by '-' or '='
%           or multiple quoted words followed by a '-' or '=')
%           are concatenated.
%        2) The pattern 'function()' is detected and is printed in bold
%           if it is the first function descriptor. Otherwise,
%           it is used as a web link to the .html function file
%           'function.html' if this exists.
%        3) If a 'function.jpg' image file (with same 'function' name) exists,
%           the image is inserted into the function .html file following
%           the function description. If the .jpg file is absent, the function
%           checks for the presence of a .gif file.
%        4) Lines beginning by '%%' are not interpreted and will be printed as is.
%        5) if [type] is present in a "descriptor2  - [type] text line 1"
%           type is bolded.

% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function [linktext,allvars,alltext] = help2html( filename, htmlfile, varargin)

if nargin < 1
	help help2html;
	return;
end;
if nargin <3
   g = [];
else
   g = struct( varargin{:});;
end;

try, g.font; 			catch, g.font		= 'Helvetica'; 	end;

g.functionname = [ '%s' ];
g.description  = [ '%s' ];
g.title        = [ '%s' ];
g.var          = [ '
%s
' ];
g.vartext      = [ '%s' ];
g.text         = [ '%s' ];

g.normrow      = '
';
g.normcol1     = '';
g.normcol2     = '';
g.doublecol    = '';
g.seefile      = [ 'See the matlab file %s (may require other functions)

' ];

try, g.outputonly; 		catch, g.outputonly	= 'off'; end;
try, g.background; 		catch, g.background	= ''; 	end;
try, g.header; 			catch, g.header		= ''; 	end;
try, g.footer; 			catch, g.footer		= ''; 	end;
try, g.refcall; 		catch, g.refcall	= '%s.html'; 	end;
try, g.outputlink; 		catch, g.outputlink = [ g.normrow g.normcol1 '%s.html	' g.normcol2 '%s
' ]; end;

g.footer      = [ '' g.footer '' ];

if nargin < 1
	help help2html;
	return;
end;

% output file
% -----------
if nargin < 2 | isempty(htmlfile);
	indexdot = findstr( filename, '.');
	if isempty(indexdot), indexdot = length(filename)+1; end;
	htmlfile = [ filename(1:indexdot(end)-1) '.html' ];
else
	indexdot = findstr( filename, '.');
end;

% open files
% ----------
fid = fopen( filename, 'r');
if fid == -1
	error('Input file not found');
end;
if ~strcmp(g.outputonly, 'on')
	fo = fopen(htmlfile, 'w');
	if fo == -1
		error('Cannot open output file');
	end;
	% write header
	% ------------
	fprintf(fo, '%s\n%s\n
\n', g.header, g.background);
end;

cont = 1;
% scan file
% -----------
str = fgets( fid );
% if first line is the name of the function, reload
if str(1) ~= '%', str = fgets( fid ); end;

% state variables
% -----------
maindescription 	 = 1;
varname = [];
oldvarname = [];
vartext = [];
newvar  	 = 0;
allvars = {};
alltext = {};
indexout = 1;

while (str(1) == '%')
   str = deblank(str(2:end-1));

   % --- DECODING INPUT
   newvar  	 = 0;
   str = deblank2(str);

   if ~isempty(str)

	  % find a title
	  % ------------
	  i2d = findstr(str, ':');
	  newtitle = 0;
	  if ~isempty(i2d)
	  	 i2d = i2d(1);
	  	 switch lower(str(1:i2d))
	  		case { 'usage:' 'authors:' 'author:' 'notes:' 'note:' 'input:' ...
	  		'inputs:' 'outputs:' 'output:' 'example:' 'examples:' 'see also:' }, newtitle = 1;
		 end;
		 if (i2d == length(str)) & (str(1) ~= '%'), newtitle = 1; end;
   	  end;
      if newtitle
  			tilehtml = str(1:i2d);
  			newtitle = 1;
	        oldvarname = varname;
			oldvartext = vartext;
        	if i2d < length(str)
         			vartext = formatstr(str(i2d+1:end), g.refcall);
         	else	vartext = [];
         	end;
         	varname = [];
      else
	  % not a title
	  % ------------
         % scan lines
         [tok1 strrm] = mystrtok( str );
         [tok2 strrm] = strtok( strrm );

         if ~isempty(tok2) & ( tok2 == '-' | tok2 == '=') % new variable
            newvar = 1;
            oldvarname = varname;
            oldvartext = vartext;
			if ~maindescription
				varname = formatstr( tok1, g.refcall);
            else
				varname = tok1;
			end;
			strrm = deblank(strrm);            % remove tail blanks
            strrm = deblank(strrm(end:-1:1));	% remove initial blanks
           	strrm = formatstr( strrm(end:-1:1), g.refcall);
            vartext = strrm;
         else
            % continue current text
            str = deblank(str);            % remove tail blanks
            str = deblank(str(end:-1:1));	% remove initial blanks
            str = formatstr( str(end:-1:1), g.refcall );
            if isempty(vartext)
               vartext = str;
            else
               if ~isempty(varname)
               	    vartext = [ vartext ' ' str]; % espace if in array
               else
               		if all(vartext(	end-2:end) == '.')
               			vartext = [ deblank2(vartext(1:end-3)) ' ' str]; % espace if '...'
               		else
                    	vartext = [ vartext '
' str];    % CR otherwise
                    end;
               end;
            end;
         end;
         newtitle = 0;
      end;
	  % --- END OF DECODING

   	  str = fgets( fid );

      % test if last entry
      % ------------------
      if str(1) ~= '%'
  	 	 if ~newtitle
  	 	 	if ~isempty(oldvarname)
				allvars{indexout} = oldvarname;
				alltext{indexout} = oldvartext;
				indexout = indexout + 1;
           		fprintf( fo, [ '
' g.normrow g.normcol1 g.var '	\n' ], oldvarname);
           		fprintf( fo, [ g.normcol2 g.vartext '
\n' ], finalformat(oldvartext));
       	 	else
       			if ~isempty(oldvartext)
           			fprintf( fo, [ g.normcol2 g.text '
\n' ], finalformat(oldvartext));
       			end;
         	end;
         	newvar = 1;
         	oldvarname = varname;
         	oldvartext = vartext;
         end;
      end;

      % test if new input for an array
      % ------------------------------
      if newvar | newtitle
         if maindescription
            if ~isempty(oldvartext) % FUNCTION TITLE
               maintext = oldvartext;

			   % generate the output command
			   % ---------------------------
			   try, g.outputtext; 		catch, g.outputtext	= ''; 	end;
			   if isempty(g.outputtext),  g.outputtext	=  filename(1:indexdot(end)-1); end;
			   linktext = sprintf( g.outputlink, g.outputtext,  filename(1:indexdot(end)-1), maintext );
			   if strcmp(g.outputonly, 'on')
                   fclose(fid);
				   return;
			   end;

               maindescription = 0;
               functioname = oldvarname( 1:findstr( oldvarname, '()' )-1);
               fprintf( fo, [g.normrow g.normcol1 g.functionname '	\n'],upper(functioname));
               fprintf( fo, [g.normcol2 g.description '
\n'], [ upper(oldvartext(1)) oldvartext(2:end) ]);

               % INSERT IMAGE IF PRESENT
               imagename = [];
               imagename1 = [ htmlfile( 1:findstr( htmlfile, functioname )-1) functioname '.jpg' ];
               imagename2 = [ htmlfile( 1:findstr( htmlfile, functioname )-1) functioname '.gif' ];
			   if exist( imagename2 ), imagename = imagename2; end;
			   if exist( imagename1 ), imagename = imagename1; end;
               if ~isempty(imagename) % do not make link if the file does not exist
                   imageinfo = imfinfo(imagename);
                   if imageinfo.Width < 600
                       fprintf(fo, [ g.normrow g.doublecol ...
                                     '

' ]);
                   else
                       fprintf(fo, [ g.normrow g.doublecol ...
                                     '

' ]);
                   end;

               end;
            end;
   		elseif ~isempty(oldvarname)
			allvars{indexout} = oldvarname;
			alltext{indexout} = oldvartext;
			indexout = indexout + 1;
       		fprintf( fo, [ '
' g.normrow g.normcol1 g.var '	\n' ], oldvarname);
       		fprintf( fo, [ g.normcol2 g.vartext '
\n' ], finalformat(oldvartext));
   	 	else
   			if ~isempty(oldvartext)
       			fprintf( fo, [ g.normcol2 g.text '
\n' ], finalformat(oldvartext));
   			end;
         end;
      end;

      % print title
      % -----------
      if newtitle
		 fprintf( fo, [ g.normrow g.doublecol '

' g.normrow g.normcol1 g.title '	\n' ], tilehtml);
      	 if str(1) ~= '%' % last input
         	fprintf( fo, [ g.normcol2 g.text '
\n' ], vartext);
         end;
         oldvarname = [];
         oldvartext = [];
      end;
   else
      str = fgets( fid );
   end;
end;
fprintf( fo, [ '
\n
' g.seefile '%s'], lower(filename), filename, g.footer);
fclose( fid );
fclose( fo  );

return;

% -----------------
% sub-functions
% -----------------
function str = deblank2( str ); % deblank two ways
   str = deblank(str(end:-1:1));    % remove initial blanks
   str = deblank(str(end:-1:1));	% remove tail blanks
return;

function strout = formatstr( str, refcall );
	[tok1 strrm] = strtok( str );
		strout = [];
		while ~isempty(tok1)
			tokout = functionformat( tok1, refcall );
			if isempty( strout)
				strout = tokout;
			else
				strout = [strout ' ' tokout ];
			end;
			[tok1 strrm] = strtok( strrm );
		end;
return;

% final formating
function str = finalformat(str); % bold text in bracket if just in the beginning
    tmploc = sort(union(find(str == '['), find(str == ']')));
    if ~isempty(tmploc) & str(1) == '['
        if mod(length(tmploc),2) ~= 0, str, error('Opening but no closing bracket'); end;
        tmploc = tmploc(1:2);
        str = [ str(1:tmploc(1)) '' str(tmploc(1)+1:tmploc(2)-1) '' str(tmploc(2):end) ];
    end;

    %tmploc = find(str == '"');
    %if ~isempty(tmploc)
    %    if mod(length(tmploc),2) ~= 0, str, error('Opening but no closing parenthesis'); end;
    %    for index = length(tmploc):-2:1
    %        str = [ str(1:tmploc(index-1)-1) '' str(tmploc(index-1)+1:tmploc(index)-1) '' str(tmploc(index)+1:end) ];
    %    end;
    %end;

function tokout = functionformat( tokin, refcall );
	tokout = tokin;	% default
	[test, realtokin, tail, beg] = testfunc1( tokin );
	if ~test,  [test, realtokin, tail] = testfunc2( tokin ); end;
	if test
		i1 = findstr( refcall, '%s');
		i2 = findstr( refcall(i1(1):end), '''');
		if isempty(i2) i2 = length( refcall(i1(1):end) )+1; end;
		filename  = [ realtokin refcall(i1+2:i1+i2-2)]; % concatenate filename and extension
		%disp(filename)
		if exist( filename ) % do not make link if the file does not exist
			tokout =  sprintf( [ beg '%s' tail ' ' ], realtokin, realtokin );
		end;
	end;
return;

function [test, realtokin, tail, beg] = testfunc1( tokin ) % test if is string is 'function()[,]'
	test = 0; realtokin = ''; tail = ''; beg = '';
	if ~isempty( findstr( tokin, '()' ) )
		if length(tokin)<3, return; end;
		realtokin = tokin( 1:findstr( tokin, '()' )-1);
		if length(realtokin) < (length(tokin)-2) tail = tokin(end); else tail = []; end;
		test = 1;
		if realtokin(1) == '(', realtokin = realtokin(2:end); beg = '('; end;
		if realtokin(1) == ',', realtokin = realtokin(2:end); beg = ','; end;
	end;
return;

function [test, realtokin, tail] = testfunc2( tokin ) % test if is string is 'FUNCTION[,]'
	test = 0; realtokin = ''; tail = '';
	if all( upper(tokin) == tokin)
		if tokin(end) == ','
			realtokin = tokin(1:end-1);
			tail = ',';
		else
			realtokin = tokin;
		end;
		testokin = realtokin;
		testokin(findstr(testokin, '_')) = 'A';
		testokin(findstr(testokin, '2')) = 'A';
		if all(double(testokin) > 64) & all(double(testokin) < 91)
			test = 1;
		end;
		realtokin = lower(realtokin);
	end;
return;

function [tok, str] = mystrtok(str)

    [tok str] = strtok(str);
    if tok(1) == '"'
        while tok(end) ~= '"'
            [tok2 str] = strtok(str);
            if isempty(tok2), tok, error('can not find closing quote ''"'' in previous text'); end;
            tok = [tok ' ' tok2];
        end;
    end;


function [ SICD_meta, NITF_meta ] = read_sicd_meta( filename )
%READ_SICD_META Read Sensor Independent Complex Data (SICD) metadata from
%file into a MATLAB structure
%
% SICD (version >= 0.3) is stored in a NITF container.  NITF is a
% complicated format that involves lots of fields and configurations
% possibilities. Fortunately, SICD only really uses a small, specific
% portion of the NITF format.  This function extracts only the few parts of
% the NITF metadata necessary for reading a SICD NITF file.
%
% Written by: Wade Schwartzkopf, NGA/IDT
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

%% Open file
NITF_meta = read_sicd_nitf_offsets(filename);
% SICD Volume 2, File Format Description, section 3.1.1 says that SICD XML
% metadata must be stored in first DES.
SICD_DES_Offset = NITF_meta.minimal.desOffsets(1);
SICD_DES_Length = NITF_meta.minimal.desLengths(1);

%% Read SICD XML metadata from the data extension segment
fid = fopen(filename);
fseek(fid,SICD_DES_Offset,'bof');
SICD_xml_string = fread(fid,SICD_DES_Length,'uint8=>char')';
fclose(fid);
SICD_meta = sicdxml2struct( xmlread( java.io.StringBufferInputStream( SICD_xml_string ) ) );

%% Adjust frequencies in metadata to be true, not offset values, if
% reference frequency is available
if isfield(SICD_meta,'RadarCollection') && isfield(SICD_meta.RadarCollection,'RefFreqIndex') && ...
        SICD_meta.RadarCollection.RefFreqIndex && exist('sicd_ref_freq','file')
    % Get reference frequency from function the user can place in MATLAB path
    SICD_meta = sicd_apply_ref_freq(SICD_meta, sicd_ref_freq());
end

end

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


function printOcclusionResult(im, bndinfo, lab, fn, fignum)

if ~exist('fignum', 'var') || isempty(fignum)
    fignum = 1;
end

if isfield(bndinfo, 'labels')
    objlab = bndinfo.labels;
elseif isfield(bndinfo, 'result') && isfield(bndinfo.result, 'geomProb')
    objlab = zeros(bndinfo.nseg, 1);
    [maxval, maxlab] = max(bndinfo.result.geomProb, [], 2);
    ind = find(maxlab>=2 & maxlab<=4);
    objlab(ind) = (3:2+numel(ind));
    objlab(maxlab==1) = 1;
    objlab(maxlab==5) = 2;
else
    objlab = [];
end

displayOcclusionResult(im, bndinfo, objlab, lab, {}, fignum);
set(gcf, 'PaperPositionMode', 'auto');
%print(['-f' num2str(fignum)], '-djpeg99', fn);
print(['-f' num2str(fignum)], '-depsc2', [fn(1:end-4) '.eps']);


%% EVENT OBJECT (event.m) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This class is designed to define a generic agent and import this variables
% into the simulation space for the purpose of multi-vehicle control simulation.

% Author: James A. Douthwaite

classdef eventDefinition
%%% EVENT BASE CLASS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % This class contains the basic properties of a generic event, neither
    properties
        % EVENT PARAMETERS
        eventID;
        name;
        type;
        time;
        info;
    end
%%  CLASS METHODS
    methods
%       CONSTRUCTION METHOD
       function obj = eventDefinition(time,name,summaryInfo)
            % This function is designed to generate an event with an
            % automatically defined ID number and basic properties
            % INPUTS:
            % time
            % name
            % summaryInfo - Assigned description string
            % OUTPUTS:
            % obj     - The generated object

            % INPUT HANDLING
            % CONFIRM EVENT TIME
            if ~isnumeric(time)                    % Default time setting
                %             if ~exist('time','var') || ~isnumeric(time)                    % Default time setting
                obj.time = 0;
                %warning('An event time must be defined.');
                return
            else
                obj.time = time;
            end
            % CONFIRM NAME STRING
            if isnumeric(name) || isempty(name)    % Default name setting
                obj.name = 'EVENT';
            else
                obj.name = name;
            end
            % CONFIRM DEFAULT SUMMARY INFORMATION
            %             if ~exist('summaryInfo','var') || isempty(summaryInfo)
            if isempty(summaryInfo)
                obj.info = 'None.';                                        % Default information setting
            else
                obj.info = summaryInfo;
            end

            % ALLOCATE AUTOINCREMENTING ID NUMBER
            persistent eventcount;
            if isempty(eventcount)
                eventcount = 1;
            else
                eventcount = eventcount + 1;
            end
            obj.eventID = uint16(eventcount);   % Assign the number as an ID tag

            % ASSIGN THE DEFAULT TYP
            obj.type = eventType.event;         % Assign default enumeration of 'event'
       end
    end
    % PRIVATE METHODS (CLASS SPECIFIC TOOLS)
    methods (Access = private)
        % PRINT THE OBJECT SUMMARY
        function displaySummary(obj)
            fprintf('[%s]\tevent created (ID:%d @%.2fs):\t%s\n',obj.name,obj.eventID,obj.time,obj.info);
        end
    end
end


function db_reload_subjects( iSubjects )
% DB_RELOAD_SUBJECTS: Reload a set of subjects of the current protocol.
%
% USAGE:  db_reload_subjects( iSubjects );
%
% INPUT:  iSubjects: indices of subjects to modify in protocol subjects array
%                    or 0, to specify the protocol's default subject
%
% DESCRIPTION:
%     For each subject : Parse the subject's directory again and
%     replace Subject structure in Brainstorm database.

% @=============================================================================
% 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, 2008-2010

% Get protocol information
ProtocolInfo     = bst_get('ProtocolInfo');
ProtocolSubjects = bst_get('ProtocolSubjects');
% Check input subject index
if isempty(ProtocolSubjects) || any(iSubjects < 0) || any(iSubjects > length(ProtocolSubjects.Subject))
    error('Invalid subject indices');
end

% If no progressbar is visible: create one
isProgressBar = ~bst_progress('isVisible');
if isProgressBar
    bst_progress('start', 'Reload subject', 'Reloading subjects...', 0, 50 * length(iSubjects));
end
% Loop on all subjects
for i = 1:length(iSubjects)
    iSubject = iSubjects(i);
    % Get subject directory (for default subject or regular subject)
    if (iSubject == 0)
        subjectSubDir = bst_fileparts(ProtocolSubjects.DefaultSubject.FileName);
    else
        subjectSubDir = bst_fileparts(ProtocolSubjects.Subject(iSubject).FileName);
    end
    % Check the existance of the subject's directory
    if ~file_exist(bst_fullfile(ProtocolInfo.SUBJECTS, subjectSubDir))
        db_fix_protocol();
        bst_progress('stop');
        return
    end
    % Parse subject directory
    sSubject = db_parse_subject(ProtocolInfo.SUBJECTS, subjectSubDir, 50);
    % If subject could not be loaded
    if isempty(sSubject)
        db_fix_protocol();
        bst_progress('stop');
        return
    end
    % Else subject was reloaded: update in ProtocolSubjects structure
    if (iSubject == 0)
        ProtocolSubjects.DefaultSubject = sSubject;
    else
        ProtocolSubjects.Subject(iSubject) = sSubject;
    end
end

% Update Brainstorm database
bst_set('ProtocolSubjects', ProtocolSubjects);
% Update display
panel_protocols('UpdateNode', 'Subject', iSubjects);
% Save database
db_save();
% Hide progress bar if it was started here
if isProgressBar
    bst_progress('stop');
end


function varargout = img2mesh(varargin)
%
%  Format:
%      newworkspace = img2mesh or imgmesh(workspace)
%
%  A GUI for Iso2Mesh for streamlined mesh data processing
%
%  Author: Qianqian Fang <q.fang at neu.edu>
%
%  Input:
%        workspace (optional): a struct containing the below fields
%           .graph: a digraph object containing the i2m workspace data
%  Output:
%        newworkspace (optional): the updated workspace, with the same
%        subfields as the input.
%
%   If a user supplys an output variable, the GUI will not return until
%   the user closes the window; if a user does not provide any output,
%   the call will return immediately.
%
%   Please find more information at http://iso2mesh.sf.net/
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @i2m_OpeningFcn, ...
                   'gui_OutputFcn',  @i2m_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 i2m is made visible.
function i2m_OpeningFcn(hObject, eventdata, handles, varargin)

cm = uicontextmenu;
uimenu(cm,'Label','Plot','CallBack',{@processdata,handles});
uimenu(cm,'Label','Rename','CallBack',{@processdata,handles});
uimenu(cm,'Label','Delete','CallBack',{@processdata,handles});

mimeshing = uimenu(cm,'Label','Meshing');
miv2s = uimenu(mimeshing,'Label','Volume to surface','CallBack',{@processdata,handles});
uimenu(mimeshing,'Label','Volume to mesh','CallBack',{@processdata,handles});
uimenu(mimeshing,'Label','Surface to mesh','CallBack',{@processdata,handles});
uimenu(mimeshing,'Label','Surface to volume','CallBack',{@processdata,handles});
uimenu(mimeshing,'Label','Close and fill volume','CallBack',{@processdata,handles});
uimenu(mimeshing,'Label','Extract surface','CallBack',{@processdata,handles});
uimenu(mimeshing,'Label','Tessellate surface','CallBack',{@processdata,handles});

mirepair = uimenu(cm,'Label','Surface repair');
uimenu(mirepair,'Label','Clean surface','CallBack',{@processdata,handles});
uimenu(mirepair,'Label','Repair surface','CallBack',{@processdata,handles});
uimenu(mirepair,'Label','Smooth surface','CallBack',{@processdata,handles});
uimenu(mirepair,'Label','Simplify surface','CallBack',{@processdata,handles});
uimenu(mirepair,'Label','Remesh surface','CallBack',{@processdata,handles});
uimenu(mirepair,'Label','Simplify surface','CallBack',{@processdata,handles});
uimenu(mirepair,'Label','Reorient mesh elements','CallBack',{@processdata,handles});

mibool = uimenu(cm,'Label','Surface boolean');
uimenu(mibool,'Label','Or','CallBack',{@processdata,handles});
uimenu(mibool,'Label','And','CallBack',{@processdata,handles});
uimenu(mibool,'Label','All','CallBack',{@processdata,handles});
uimenu(mibool,'Label','Diff','CallBack',{@processdata,handles});
uimenu(mibool,'Label','First','CallBack',{@processdata,handles});
uimenu(mibool,'Label','Second','CallBack',{@processdata,handles});

mireport = uimenu(cm,'Label','Report');
uimenu(mireport,'Label','Containing data','CallBack',{@processdata,handles});
uimenu(mireport,'Label','Mesh quality histogram','CallBack',{@processdata,handles});
uimenu(mireport,'Label','Element volume histogram','CallBack',{@processdata,handles});
uimenu(mireport,'Label','Total volume','CallBack',{@processdata,handles});

mirefresh=uimenu(cm,'Label','Refresh','CallBack',{@miRefresh_Callback,handles});
uimenu(cm,'Label','Save as','CallBack',{@processdata,handles});

miv2s.Separator='on';
mimeshing.Separator='on';
mirefresh.Separator='on';

root=get(handles.fgI2M,'userdata');

if(isempty(root))
    root=struct('graph',digraph,'menu',cm);
end
set(handles.fgI2M,'userdata',root);
set(handles.axFlow,'position',[0 0 1 1]);
set(handles.axPreview,'position',[0 0 1 1]);

set(handles.fgI2M,'UIContextMenu',handles.meCreate);

axis(handles.axFlow,'off');
axis(handles.axPreview,'off');

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

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes i2m wait for user response (see UIRESUME)
% uiwait(handles.fgI2M);

function processdata(source,callbackdata,handles)

try
obj=get(handles.fgI2M,'currentobject');
if(strcmp(class(obj),'matlab.graphics.chart.primitive.GraphPlot')==0)
    if(~isempty(obj.UserData) && strcmp(class(obj.UserData),'matlab.graphics.chart.primitive.GraphPlot'))
        obj=obj.UserData;
    else
        return
    end
end
root=get(handles.fgI2M,'userdata');
pos=get(handles.axFlow,'currentpoint');
[nodedata,nodetype,nodeid]=getnodeat(root,obj,pos);

newtype=dummytype;
prefix='x';
switch source.Label
    case 'Volume to surface'
        if(isstruct(nodetype) && isfield(nodetype,'hasvol') && nodetype.hasvol)
            [newdata,newtype]=v2sgui(nodedata);
            prefix='Vol2Surf';
        else
            error('no volume data found');
        end
    case 'Volume to mesh'
        if(nodetype.hasvol)
            [newdata,newtype]=v2mgui(nodedata);
            prefix='Vol2Mesh';
        else
            error('no volume data found');
        end
    case 'Surface to mesh'
        if(nodetype.hasnode && nodetype.hasface)
            [newdata,newtype]=s2mgui(nodedata);
            prefix='Surf2Mesh';
        else
            error('no surface data found');
        end
    case 'Surface to volume'
        if(nodetype.hasnode && nodetype.hasface)
            ndiv = inputdlg('Division number along the shortest dimension:',...
                'surf2vol - rasterizing a surface mesh',1,{'50'});
            if(isempty(ndiv))
                return;
            end
            newdata.vol=s2v(nodedata.node,nodedata.face,str2num(ndiv{1}));
            newtype.hasvol=1;
            prefix='Surf2Vol';
        else
            error('no surface data found');
        end
    case 'Close and fill volume'
        if(nodetype.hasvol)
            rad=inputdlg('maximum gap length in voxel (scalar)','Close and fill a volume',1,{'1'});
            newdata.vol=fillholes3d(nodedata.vol,str2num(rad{1}));
            newtype=nodetype;
            prefix='FillVol';
        else
            error('no volume data found');
        end
    case 'Extract surface'
        if(isstruct(nodetype) && isfield(nodetype,'hasvol') && nodetype.hasvol)
            [newdata.node,newdata.face]=binsurface(nodedata.vol);
            prefix='BinSurf';
        elseif(nodetype.hasnode && nodetype.haselem)
            newdata.node=nodedata.node;
            newdata.face=volface(nodedata.elem(:,1:min(4,size(nodedata.elem,2))));
            [newdata.node,newdata.face]=removeisolatednode(newdata.node,newdata.face);
            prefix='VolSurf';
        elseif(nodetype.hasnode && nodetype.hasface)
            [newdata.node,newdata.face]=deal(nodedata.node,nodedata.face);
            prefix='CopySurf';
        end
        newtype.hasnode=1;
        newtype.hasface=1;
    case 'Clean surface'
        if(nodetype.hasnode && nodetype.hasface)
            [newdata.node,newdata.face]=meshcheckrepair(nodedata.node,nodedata.face,'deep');
            newtype=nodetype;
            prefix='CleanSurf';
        else
            error('no surface data found');
        end
    case 'Repair surface'
        if(nodetype.hasnode && nodetype.hasface)
            [newdata.node,newdata.face]=meshcheckrepair(nodedata.node,nodedata.face,'meshfix');
            newtype=nodetype;
            prefix='RepairSurf';
        else
            error('no surface data found');
        end
    case 'Smooth surface'
        if(nodetype.hasnode && nodetype.hasface)
            res = inputdlg({'Method (laplacian,laplacianhc,lowpass):','Iteration (integer):','Alpha (scalar):'},...
                'sms - smoothing a surface mesh',[1,1,1],{'lowpass','20','0.5'});
            if(isempty(res))
                return;
            end
            newdata=nodedata;
            newtype=nodetype;
            newdata.node=sms(nodedata.node,nodedata.face,str2num(res{2}),str2num(res{3}),res{1});
            prefix='SmoothSurf';
        else
            error('no surface data found');
        end
    case 'Simplify surface'
        if(nodetype.hasnode && nodetype.hasface)
            res = inputdlg('Percentage of edges to keep (0-1):',...
                'Simplify mesh',[1],{'1'});
            if(isempty(res))
                return;
            end
            [newdata.node,newdata.face]=meshresample(nodedata.node,nodedata.face,str2num(res{1}));
            newtype=nodetype;
            prefix='SimplifySurf';
        else
            error('no surface data found');
        end
    case 'Remesh surface'
        if(nodetype.hasnode && nodetype.hasface)
            res = inputdlg({'Rasterization voxel size (scalar):','Max gap to close (scalar):','Max surface element radis (scalar):'},...
                'Remesh surface',[1,1,1],{'1','20','3'});
            if(isempty(res))
                return;
            end
            opt.gridsize=str2num(res{1});
            opt.closesize=str2num(res{2});
            opt.elemsize=str2num(res{3});
            [newdata.node, newdata.face]=remeshsurf(nodedata.node,nodedata.face,opt);
            newtype.hasnode=1;
            newtype.hasface=1;
            prefix='RemeshSurf';
        else
            error('no surface data found');
        end
    case 'Tessellate surface'
        if(nodetype.hasnode && nodetype.hasface)
            [newdata.node,newdata.elem]=fillsurf(nodedata.node,nodedata.face);
            newdata.face=volface(newdata.elem(:,1:min(4,size(newdata.elem,2))));
            newtype=nodetype;
            newtype.haselem=1;
            prefix='TessMesh';
        else
            error('no surface data found');
        end
    case 'Reorient mesh elements'
        if(nodetype.hasnode && nodetype.haselem)
            [newdata.node,newdata.elem]=meshreorient(nodedata.node,nodedata.elem);
            newtype=nodetype;
            prefix='ReorientMesh';
        elseif(nodetype.hasnode && nodetype.hasface)
            [newdata.node,newdata.face]=surfreorient(nodedata.node,nodedata.face);
            newtype=nodetype;
            prefix='ReorientSurf';
        else
            error('no surface or tetrahedral mesh data found');
        end
    case 'Mesh quality histogram'
        if(nodetype.hasnode && nodetype.haselem)
            quality=meshquality(nodedata.node,nodedata.elem);
        elseif(nodetype.hasnode && nodetype.hasface)
            quality=meshquality(nodedata.node,nodedata.face);
        end
        if(exist('quality','var'))
            figure;
            hist(quality,50);
        end
        return;
    case 'Element volume histogram'
        if(nodetype.hasnode && nodetype.haselem)
            evol=elemvolume(nodedata.node,nodedata.elem);
        elseif(nodetype.hasnode && nodetype.hasface)
            evol=elemvolume(nodedata.node,nodedata.face);
        end
        if(exist('evol','var'))
            figure;
            hist(evol,50);
        end
        return;
    case 'Total volume'
        if(nodetype.hasnode && nodetype.haselem)
            evol=elemvolume(nodedata.node,nodedata.elem);
        elseif(nodetype.hasnode && nodetype.hasface)
            [no,el]=fillsurf(nodedata.node,nodedata.face);
            evol=elemvolume(no,el);
        end
        if(exist('evol','var'))
            msgbox(sprintf('Total volume is %f cubic voxel',sum(evol)),'Total volume');
        end
        return;
    case 'Containing data'
        msg='';
        if(nodetype.hasnode)
            msg=[msg sprintf('\nContaining %d nodes (%d columns)',size(nodedata.node,1),size(nodedata.node,2))];
        end
        if(nodetype.hasface)
            msg=[msg sprintf('\nContaining %d triangles (%d columns)',size(nodedata.face,1),size(nodedata.face,2))];
        end
        if(nodetype.haselem)
            msg=[msg sprintf('\nContaining %d tetrehedra (%d columns)',size(nodedata.elem,1),size(nodedata.elem,2))];
        end
        if(nodetype.hasvol)
            msg=[msg sprintf('\nContaining [%d x %d x %d ] volume',size(nodedata.vol,1),size(nodedata.vol,2),size(nodedata.vol,3))];
        end
        msgbox(msg,'Mesh data report');
        return;
    case 'Plot'
        if(isstruct(nodetype) && isfield(nodetype,'hasnode') && nodetype.hasnode)
            if(isfield(nodetype,'haselem') && nodetype.haselem)
                figure('keypressfcn',@plotfigevent,'userdata',struct('node',nodedata.node,'face',[],'elem',nodedata.elem));
                plotmesh(nodedata.node,[],nodedata.elem);
            else
                figure('keypressfcn',@plotfigevent,'userdata',struct('node',nodedata.node,'elem',[],'face',nodedata.face));
                plotmesh(nodedata.node,nodedata.face);
            end
        else
            figure('keypressfcn',@plotfigevent,'userdata',struct('vol',nodedata.vol));
            hs=slice(double(nodedata.vol),[],[ceil(size(nodedata.vol,2)*0.5)],ceil(size(nodedata.vol,3)*0.5));
            set(hs,'linestyle','none');
        end
    case {'Or','And','Diff','All','First','Second'}
        if(isstruct(nodetype) && isfield(nodetype,'hasnode'))
            if((nodetype.hasface || nodetype.haselem) && nodetype.hasnode)
                pt=ginput(1);
                [nodedata2,nodetype2,nodeid2]=getnodeat(root,obj,pt);
                if(~nodetype2.hasnode || ~nodetype2.hasface)
                    if(nodetype2.hasnode && nodetype2.haselem)
                        nodedata2.face=volface(nodedata2.elem);
                    else
                        error('Second operand does not contain a surface');
                    end
                end
                op=source.Label;
                if(strcmp(op,'Intersect'))
                    op='inter';
                end
                if(~nodetype.hasface)
                    nodedata.face=volface(nodedata.elem);
                end
                [newdata.node,newdata.face]=surfboolean(nodedata.node,nodedata.face,lower(op),nodedata2.node,nodedata2.face(:,[1 3 2]));
                newtype.hasnode=1;
                newtype.hasface=1;
                prefix=source.Label;
            else
                warndlg('Selected node does not contain a surface mesh');
            end
        end
    case 'Delete'
        button = questdlg('Are you sure to delete the selected node?', 'Confirm','No');
        if strcmpi(button, 'No') ||  strcmpi(button, 'Cancel')
	        return;
        end
        root.graph=rmnode(root.graph,root.graph.Nodes.Name{nodeid});
        updategraph(root,handles);
    case 'Rename'
        newname = inputdlg('Define a new name:',...
                'Rename',1,{root.graph.Nodes.Name{nodeid}});
        if(isempty(newname))
            return;
        end
        if(isempty(newname{1}) || ~isempty(cell2mat(regexp( root.graph.Nodes.Name, ['^' newname{1} '$']))))
            error('empty or duplicated node name');
        end
        root.graph.Nodes.Name{nodeid}=newname{1};
        updategraph(root,handles);
    case 'Save as'
        if(~nodetype.haselem && ~nodetype.hasnode)
            error('selected data does not have a mesh');
            return;
        end
        filter = {'*.jmesh';'*.*'};
        [file, path] = uiputfile(filter,'Export mesh');
        if ~isequal(file,0) && ~isequal(path,0)
            if(nodetype.haselem)
                savejmesh(nodedata.node,nodedata.face,nodedata.elem,fullfile(path,file));
            else
                savejmesh(nodedata.node,nodedata.face,fullfile(path,file));
            end
        end
end

if(exist('newdata','var') && exist('newtype','var'))
    cla(handles.axPreview);
    cla(handles.axFlow);
    newdata.preview=getpreview(newdata,newtype,[400,400]);
    [newkey,root.graph]=addnodewithdata(handles,newdata,newtype,prefix);
    root.graph=addedge(root.graph,{root.graph.Nodes.Name{nodeid}},{newkey});
    if(strcmp(source.Parent.Type, 'uimenu') && strcmp(source.Parent.Label,'Surface boolean'))
        root.graph=addedge(root.graph,{root.graph.Nodes.Name{nodeid2}},{newkey});
    end
    updategraph(root,handles);
end

catch ME
    msg=sprintf('Error: \n%s\n',ME.message);
    for e=1:length(ME.stack)
       msg=sprintf('%s\nFile: %s\nFunction: %s\nLine: %d\n\n',msg,ME.stack(e).file,ME.stack(e).name,ME.stack(e).line);
    end
	uiwait(warndlg(msg,'I2M ERROR'));
    updategraph(root,handles);
end

function plotfigevent(hobject,event)
data=get(hobject,'userdata');
plotpos=[];
if(isfield(data,'plotpos'))
    plotpos=data.plotpos;
end
if(isempty(plotpos))
    switch event.Key
        case {'rightarrow','uparrow'}
            plotpos=0;
        case {'leftarrow','downarrow'}
            plotpos=9;
        otherwise
    end
end
if(isfield(data,'node'))
    pmax=max(data.node);
    pmin=min(data.node);
    cla;
    switch event.Key
        case 'rightarrow'
            plotpos=min(plotpos+1,9);
            plotmesh(data.node,data.face,data.elem,sprintf('x>%f',(pmax(1)-pmin(1))*plotpos*0.1+pmin(1)))
        case 'leftarrow'
            plotpos=max(plotpos-1,0);
            plotmesh(data.node,data.face,data.elem,sprintf('x>%f',(pmax(1)-pmin(1))*plotpos*0.1+pmin(1)))
        case 'uparrow'
            plotpos=min(plotpos+1,9);
            plotmesh(data.node,data.face,data.elem,sprintf('y>%f',(pmax(2)-pmin(2))*plotpos*0.1+pmin(2)))
        case 'downarrow'
            plotpos=max(plotpos-1,0);
            plotmesh(data.node,data.face,data.elem,sprintf('y>%f',(pmax(2)-pmin(2))*plotpos*0.1+pmin(2)))
        otherwise
    end
end
data.plotpos=plotpos;
set(hobject,'userdata',data);
%----------------------------------------------------------------
function [nodedata,nodetype,nodeid]=getnodeat(root,obj,pos)
nodedist=[obj.XData(:)-pos(1,1) obj.YData(:)-pos(1,2)];
nodedist=sum(nodedist.*nodedist,2);
[mindist, nodeid]=min(nodedist);
nodedata=root.graph.Nodes.Data{nodeid};
nodetype=root.graph.Nodes.Type{nodeid};

%----------------------------------------------------------------
function mytype=dummytype
mytype.hasnode=0;
mytype.hasface=0;
mytype.haselem=0;
mytype.hasvol=0;

%----------------------------------------------------------------
function [newdata, newtype]=v2sgui(data)
prompt = {'Threshold (scalar or array):',...
    'Surface element radius bound (scalar):',...
    'Surface element distance bound (scalar)','Method: (cgalsurf,cgalmesh,simplify)'};
title = 'vol2surf - extracting surface mesh from volume';
dims = [1 1 1 1];
definput = {'0.5','5','1','cgalsurf'};
res = inputdlg(prompt,title,dims,definput);
newdata=[];
newtype=dummytype;
if(isempty(res))
    return;
end

opt=struct('radbound',str2num(res{2}),'distbound',str2num(res{3}));
[newdata.node,newdata.face]=v2s(data.vol,eval(res{1}),opt, res{4});
newtype.hasnode=1;
newtype.hasface=1;
%----------------------------------------------------------------
function [newdata, newtype]=v2mgui(data)
prompt = {'Threshold (scalar or []):',...
    'Surface element radius bound (scalar):',...
    'Surface element distance bound (scalar)',...
    'Max element volume (scalar):',...
    'Method (cgalsurf,cgalmesh,simplify):'};
title = 'vol2mesh - extracting tet mesh from volume';
dims = [1 1 1 1 1];
definput = {'[]','5','1','30','cgalmesh'};
res = inputdlg(prompt,title,dims,definput);
newdata=[];
newtype=dummytype;
if(isempty(res))
    return;
end

opt=struct('radbound',str2num(res{2}),'distbound',str2num(res{3}));
[newdata.node,newdata.elem,newdata.face]=v2m(data.vol,eval(res{1}),...
   opt, res{4});
newtype.hasnode=1;
newtype.hasface=1;
newtype.haselem=1;

%----------------------------------------------------------------
function img=getpreview(nodedata,nodetype,imsize)
hfpreview=figure('visible', 'off');
ax=axes('parent',hfpreview,'Units','pixels','position',[1, 1, imsize(1), imsize(2)]);
if(isfield(nodetype,'haselem') && nodetype.haselem)
    plotmesh(nodedata.node,[],nodedata.elem,'linestyle',':','edgealpha',0.3,'parent',ax);
elseif(isfield(nodetype,'hasface') && nodetype.hasface)
    plotmesh(nodedata.node,nodedata.face,'linestyle','-','parent',ax);
elseif(isfield(nodetype,'hasvol') && nodetype.hasvol)
    hs=slice(double(nodedata.vol),[],[ceil(size(nodedata.vol,2)*0.5)],ceil(size(nodedata.vol,3)*0.5),'parent',ax);
    set(hs,'linestyle','none');
elseif(isfield(nodetype,'hasnode') && nodetype.hasnode)
    plotmesh(nodedata.node,'.','parent',ax);
end
set(ax,'color','none')
axis(ax,'equal');
axis(ax,'off');
img=getframe(gca);
img=flipud(img.cdata);
delete(ax);
close(hfpreview);

%----------------------------------------------------------------
function [newdata, newtype]=s2mgui(data)
prompt = {'Simplification ratio (%edges to keep, 0-1):',...
    'Max element volume (scalar):',...
    'Method (tetgen,tetgen1.5,cgalpoly):',...
    'Region seeds (N x 3 array):',...
    'Hole seeds (N x 3 array):'};
title = 'surf2mesh - creating tet mesh from surfaces';
dims = [1 1 1 1 1];
definput = {'1','30','tetgen','[]','[]'};
res = inputdlg(prompt,title,dims,definput);
newdata=[];
newtype=dummytype;
if(isempty(res))
    return;
end

[newdata.node,newdata.elem,newdata.face]=...
   s2m(data.node,data.face,str2num(res{1}),...
     str2num(res{2}),res{3},eval(res{4}),eval(res{5}));
newtype.hasnode=1;
newtype.hasface=1;
newtype.haselem=1;

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

% Get default command line output from handles structure
handles.output=get(handles.fgI2M,'userdata');
varargout{1} = handles.output;

% --------------------------------------------------------------------
function miWeb_Callback(hObject, eventdata, handles)
web('http://iso2mesh.sourceforge.net');

% --------------------------------------------------------------------
function miDoc_Callback(hObject, eventdata, handles)
web('http://iso2mesh.sourceforge.net/cgi-bin/index.cgi?Doc');

% --------------------------------------------------------------------
function miAbout_Callback(hObject, eventdata, handles)
helpmsg={
'\bf\fontsize{12}I2M: An Integrated GUI for Iso2Mesh Meshing Toolbox\rm\fontsize{10}',
'',
'Copyright (c) 2018 Qianqian Fang <q.fang at neu.edu>',
''
'Computational Optics&Translational Imaging Lab (http://fanglab.org)',
'Department of Bioengineering',
'Northeastern University',
'360 Huntington Ave, Boston, MA 02115, USA',
'',
'URL:    http://iso2mesh.sourceforge.net',
''};

opt.Interpreter = 'tex';
opt.WindowStyle = 'modal';

msgbox(helpmsg,'About','help',opt);

% --------------------------------------------------------------------
function miSphere_Callback(hObject, eventdata, handles)
prompt = {'Center:','Radius (scalar):',...
    'Surface element radius bound (scalar)',...
    'Max element volume (scalar, 0 - only create surface):'};
title = 'Create Mesh';
dims = [1 1 1 1];
definput = {'[0 0 0]','50','6','20'};
res = inputdlg(prompt,title,dims,definput);
if(isempty(res))
    return;
end
newtype=dummytype;
opt=str2num(res{3});
if(str2num(res{4})==0)
   [newdata.node,newdata.face]=meshasphere(eval(res{1}),...
     str2num(res{2}),opt);
else
   [newdata.node,newdata.face,newdata.elem]=meshasphere(eval(res{1}),...
     str2num(res{2}),opt, str2num(res{4}));
   newtype.haselem=1;
end
newtype.hasnode=1;
newtype.hasface=1;

if(exist('newdata','var') && exist('newtype','var'))
    newkey=addnodewithdata(handles,newdata,newtype,'Sphere');
end

% --------------------------------------------------------------------
function miBox_Callback(hObject, eventdata, handles)
prompt = {'Diagonal end point 1 (1x3 vector):','Diagonal end point 2 (1x3 vector):',...
    'Surface element radius bound (scalar)',...
    'Max element volume (scalar, 0 - only create surface):'};
title = 'Create Mesh';
dims = [1 1 1 1];
definput = {'[0 0 0]','[100 60 30]','6','30'};
res = inputdlg(prompt,title,dims,definput);
if(isempty(res))
    return;
end
newtype=dummytype;
opt=str2num(res{3});
if(str2num(res{4})==0)
   [newdata.node,newdata.face]=meshabox(eval(res{1}),eval(res{2}),opt);
else
   [newdata.node,newdata.face,newdata.elem]=meshabox(eval(res{1}),...
     eval(res{2}),opt, str2num(res{4}));
   newtype.haselem=1;
end
newtype.hasnode=1;
newtype.hasface=1;

if(exist('newdata','var') && exist('newtype','var'))
    newkey=addnodewithdata(handles,newdata,newtype,'Box');
end

% --------------------------------------------------------------------
function miCylinder_Callback(hObject, eventdata, handles)
prompt = {'Axis end-point 1','Axis end-point 2','Radius (scalar):',...
    'Surface element radius bound (scalar)',...
    'Max element volume (scalar, 0 - only create surface):',...
    'Circle division:'};
title = 'Create Mesh';
dims = [1 1 1 1 1 1];
definput = {'[0 0 0]','[0 0 50]','10','3','20','20'};
res = inputdlg(prompt,title,dims,definput);
if(isempty(res))
    return;
end
newtype=dummytype;
opt=str2num(res{4});
maxvol=str2num(res{5});

if(maxvol==0)
   [newdata.node,newdata.face]=meshacylinder(eval(res{1}),eval(res{2}),...
     str2num(res{3}),opt);
else
   [newdata.node,newdata.face,newdata.elem]=meshacylinder(eval(res{1}),eval(res{2}),...
     str2num(res{3}),opt,maxvol);
   newtype.haselem=1;
end
newtype.hasnode=1;
newtype.hasface=1;

if(exist('newdata','var') && exist('newtype','var'))
    newkey=addnodewithdata(handles,newdata,newtype,'Cyl');
end

% --------------------------------------------------------------------
function miLoadVol_Callback(hObject, eventdata, handles)

nodedata=struct;
nodetype=dummytype;
filters={'*.nii;*.hdr;*.img;*.tif;*.tiff;*.inr;*.bin;*.ubj','3D volume file (*.nii;*.hdr;*.img;*.tif;*.tiff;*.inr;*.bin;*.ubj)';...
    '*.nii','Nifti file (*.nii)';...
    '*.hdr;*.img','Analyze 7.5 file (*.hdr;*.img)';...
    '*.tif;*.tiff','Multipage TIFF file (*.tif)';...
    '*.inr','INR image (*.inr)';...
    '*.bin','Binary file (*.bin)';...
    '*.ubj','Universal JSON (*.ubj)';...
    '*.*','All (*.*)'};
[file,path,idx] = uigetfile(filters);
if isequal(file,0)
   return;
else
   if(regexp(file,'\.[Nn][Ii][Ii]$'))
       im=readnifti(fullfile(path,file));
       nodedata.vol=im.img;
       nodetype.hasvol=1;
   elseif(regexp(file,'(\.[Hh][Dd][Rr]$|\.[Ii][Mm][Gg]$)'))
       im=readnifti(fullfile(path,file));
       nodedata.vol=im.img;
       nodetype.hasvol=1;
   elseif(regexp(file,'\.[Tt][Ii][Ff][Ff]*$'))
       nodedata.vol=readmptiff(fullfile(path,file));
       nodetype.hasvol=1;
   elseif(regexp(file,'\.[Ii][Nn][Rr]$'))
       nodedata.vol=readinr(fullfile(path,file));
       nodetype.hasvol=1;
   elseif(regexp(file,'\.[Bb][Ii][Nn]$'))
       prompt = {'Dimension (1x3 vector):',...
            'Datatype (short,float,double,integer,...):'};
       title = 'Load generic binary file';
       dims = [1 1];
       definput = {'[]','short'};
       [res,isok] = inputdlg(prompt,title,dims,definput);
       if(isok==0)
           return;
       end
       nodedata.vol=loadmc2(fullfile(path,file),eval(res{1}),res{2});
       nodetype.hasvol=1;
   elseif(regexp(file,'\.[Uu][Bb][Jj]$'))
       nodedata=loadbj(fullfile(path,file));
       if(isstruct(nodedata) && isfield(nodedata,'vol'))
           nodetype.hasvol=1;
       end
   end
end

if(exist('nodedata','var'))
    nodetype=getnodetype(nodedata);
    if(nodetype.hasvol)
        addnodewithdata(handles,nodedata,nodetype,'Vol');
    end
else
    warndlg('no valid mesh data found','Warning');
end

% --------------------------------------------------------------------
function miLoadMesh_Callback(hObject, eventdata, handles)

nodedata=struct;
nodetype=dummytype;
filters={'*.jmesh;*.off;*.medit;*.smf;*.json','3D Mesh files (*.jmesh;*.off;*.medit;*.smf;*.json)';...
    '*.jmesh','JSON mesh (*.jmesh)';...
    '*.off','OFF file (*.off)';...
    '*.medit','Medit file (*.medit)';...
    '*.ele','Tetgen element mesh file (*.ele)';...
    '*.json','JSON file (*.json)';'*.*','All (*.*)'};
[file,path,idx] = uigetfile(filters);
if isequal(file,0)
   return;
else
   if(regexp(file,'\.[Oo][Ff][Ff]$'))
       [nodedata.node, nodedata.face]=readoff(fullfile(path,file));
   elseif(regexp(file,'\.[Mm][Ee][Dd][Ii][Tt]$'))
       [nodedata.node, nodedata.elem]=readmedit(fullfile(path,file));
   elseif(regexp(file,'\.[Ee][Ll][Ee]$'))
       [pathstr,name,ext] = fileparts(fullfile(path,file));
       [nodedata.node, nodedata.elem]=readtetgen(fullfile(pathstr,name));
   elseif(regexp(file,'\.[Jj][Mm][Ee][Ss][Hh]$'))
       nodedata=importjmesh(fullfile(path,file));
   elseif(regexp(file,'\.[Jj][Ss][Oo][Nn]$'))
       nodedata=loadjson(fullfile(path,file));
   end
end
if(exist('nodedata','var'))
    adddatatograph(handles,nodedata);
else
    warndlg('no valid mesh data found','Warning');
end

% --------------------------------------------------------------------
function miLoadSurf_Callback(hObject, eventdata, handles)
nodedata=struct;
nodetype=dummytype;
filters={'*.jmesh;*.off;*.asc;*.smf;*.smf;*.json','3D Mesh files (*.jmesh;*.off;*.asc;*.smf;*.smf;*.json)';...
    '*.jmesh','JSON mesh (*.jmesh)';...
    '*.off','OFF file (*.off)';...
    '*.asc','ASC file (*.asc)';...
    '*.gts','GNU Trangulated Surface file (*.gts)';...
    '*.smf','Simple Model Format (*.smf)';...
    '*.json','JSON file (*.json)';'*.*','All (*.*)'};
[file,path,idx] = uigetfile(filters);
if isequal(file,0)
   return;
else
   if(regexp(file,'\.[Oo][Ff][Ff]$'))
       [nodedata.node, nodedata.face]=readoff(fullfile(path,file));
   elseif(regexp(file,'\.[Aa][Ss][Cc]$'))
       [nodedata.node, nodedata.face]=readasc(fullfile(path,file));
   elseif(regexp(file,'\.[Gg][Tt][Ss]$'))
       [nodedata.node, nodedata.face]=readgts(fullfile(path,file));
   elseif(regexp(file,'\.[Ss][Mm][Ff]$'))
       [nodedata.node, nodedata.face]=readsmf(fullfile(path,file));
   elseif(regexp(file,'\.[Jj][Mm][Ee][Ss][Hh]$'))
       nodedata=importjmesh(fullfile(path,file));
   elseif(regexp(file,'\.[Jj][Ss][Oo][Nn]$'))
       nodedata=loadjson(fullfile(path,file));
   end
end
if(exist('nodedata','var'))
    adddatatograph(handles,nodedata);
else
    warndlg('no valid mesh data found','Warning');
end

% --------------------------------------------------------------------
function nodedata=importjmesh(filename)
data=loadjson(filename);
nodedata=struct;
if(isfield(data,'MeshNode'))
   nodedata.node=data.MeshNode;
end
if(isfield(data,'MeshElem'))
   nodedata.elem=data.MeshElem;
end
if(isfield(data,'MeshSurf'))
   nodedata.face=data.MeshSurf;
end
if(isfield(data,'MeshNodeVal'))
   nodedata.node(:,end+1:end+size(data.MeshNodeVal,2))=data.MeshNodeVal;
end
if(isfield(data,'MeshTetraVal'))
   nodedata.elem(:,end+1:end+size(data.MeshTetraVal,2))=data.MeshTetraVal;
end

% --------------------------------------------------------------------
function adddatatograph(handles,nodedata)
nodetype=getnodetype(nodedata);
if(nodetype.haselem)
    addnodewithdata(handles,nodedata,nodetype,'Tet');
elseif(nodetype.hasface)
    addnodewithdata(handles,nodedata,nodetype,'Surf');
elseif(nodetype.hasnode)
    addnodewithdata(handles,nodedata,nodetype,'Point');
elseif(nodetype.hasvol)
    addnodewithdata(handles,nodedata,nodetype,'Vol');
end

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

% Hint: place code in OpeningFcn to populate axFlow

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

%--------------------------------------------------------------------
function nodetype=getnodetype(nodedata)
nodetype=dummytype;
if(~isstruct(nodedata))
    return;
end
names=fieldnames(nodedata);
for i=1:length(names)
      switch names{i}
           case 'node'
                nodetype.hasnode=1;
           case 'face'
                nodetype.hasface=1;
           case 'elem'
                nodetype.haselem=1;
           case 'vol'
                nodetype.hasvol=1;
      end
      dat=nodedata.(names{i});
      if((isnumeric(dat) || islogical(dat)) && ndims(dat)==3)
           nodetype.hasvol=1;
      end
end
% --------------------------------------------------------------------

function [key,newgraph]=addnodewithdata(handles,nodedata,nodetype,name)

root=get(handles.fgI2M,'userdata');

if(isempty(root))
    root=struct('graph',digraph,'menu',uicontextmenu);
end
if(nargin<4)
    name='x';
end

id=1;
if(~isempty(root.graph.Nodes))
  while(find(strcmp(root.graph.Nodes.Name,sprintf('%s%d',name,id))))
    id=id+1;
  end
end
key=sprintf('%s%d',name,id);

cla(handles.axPreview);
cla(handles.axFlow);
nodedata.preview=getpreview(nodedata,nodetype,[400,400]);

nodeprop=table({key},{nodedata},{nodetype},'VariableNames',{'Name','Data','Type'});
root.graph=addnode(root.graph,nodeprop);
if(nargout>1)
    newgraph=root.graph;
end
updategraph(root, handles);

% --------------------------------------------------------------------
function hobj=updatepreview(root,obj,handles)
cla(handles.axPreview);
view(handles.axPreview,2)
nx=obj.XData(:);
ny=obj.YData(:);
nn=length(nx);
hold(handles.axPreview,'on');
dx=get(handles.axFlow,'xlim');
dy=get(handles.axFlow,'ylim');
wd=min([diff(dx) diff(dy)])/15;
hobj=zeros(1,nn);
set(handles.axPreview,'xlim',dx);
set(handles.axPreview,'ylim',dy);
dim=get(handles.axPreview,'dataaspectratio');
[wfig, hfig]=getwindowsize(handles.fgI2M);
wfig=wfig*dim(2);
hfig=hfig*dim(1);

for i=1:nn
    if(isfield(root.graph.Nodes.Data{i},'preview'))
        hobj(i)=imagesc(nx(i)+[-2*wd 0], ny(i)+[-wd wd]*(wfig/hfig), imresize(root.graph.Nodes.Data{i}.preview,0.25), ...
            'parent',handles.axPreview);
    end
end
set(hobj,'userdata',obj);
set(hobj,'UIContextMenu',root.menu);
set(handles.axPreview,'xlim',dx);
set(handles.axPreview,'ylim',dy);
axis(handles.axPreview,'off');
hold(handles.axPreview,'off');
% --------------------------------------------------------------------

function [width, height]=getwindowsize(fig)
oldunits = get(fig, 'Units');
set(fig, 'Units', 'pixels');
figpos = get(fig, 'Position');
set(fig, 'Units', oldunits);
width=figpos(3);
height=figpos(4);

function [hg,hobj]=updategraph(root, handles)
set(handles.fgI2M,'userdata',root);
hg=plot(root.graph,'parent',handles.axFlow,'ArrowSize',15);
hobj=updatepreview(root,hg,handles);
% set(hg,'Selected','on');
axis(handles.axFlow,'off');
set(handles.axFlow,'XColor','none')
set(hg,'UIContextMenu',root.menu);

% --------------------------------------------------------------------
function miEllipsoid_Callback(hObject, eventdata, handles)
prompt = {'Center (1x3 vector):',...
    'Radii (a scalar, or 1x3 or 1x5 vector):',...
    'Max element volume (scalar, 0 - only create surface):',...
    'Circle division:'};
title = 'Create an Ellipsoid Mesh';
dims = [1 1 1 1];
definput = {'[0 0 0]','[50 30 20]','3','30'};
res = inputdlg(prompt,title,dims,definput);
if(isempty(res))
    return;
end
newtype=dummytype;
opt=str2num(res{3});
maxvol=str2num(res{4});

if(maxvol==0)
   [newdata.node,newdata.face]=meshanellip(eval(res{1}),eval(res{2}),opt);
else
   [newdata.node,newdata.face,newdata.elem]=meshanellip(eval(res{1}),...
     eval(res{2}),opt, maxvol);
   newtype.haselem=1;
end
newtype.hasnode=1;
newtype.hasface=1;

if(exist('newdata','var') && exist('newtype','var'))
    newkey=addnodewithdata(handles,newdata,newtype,'Cyl');
end

% --------------------------------------------------------------------
function miLattice_Callback(hObject, eventdata, handles)
prompt = {'X-lattice range (a vector):',...
    'Y-lattice range (a vector):',...
    'Z-lattice range (a vector):',...
    'Max element volume (scalar, 0 - only create surface):'};
title = 'Create Lattice Grid Mesh';
dims = [1 1 1 1];
definput = {'[1 100]','[1 50]','[1 10 30]','30'};
res = inputdlg(prompt,title,dims,definput);
if(isempty(res))
    return;
end
newtype=dummytype;
maxvol=str2num(res{4});
if(maxvol==0)
   [newdata.node,newdata.face]=latticegrid(eval(res{1}),eval(res{2}),eval(res{3}));
else
   [no,fc,c0]=latticegrid(eval(res{1}),eval(res{2}),eval(res{3}));
   [newdata.node,newdata.elem,newdata.face]=surf2mesh(no,fc,[],[],1,maxvol,c0);
   newtype.haselem=1;
end
newtype.hasnode=1;
newtype.hasface=1;

if(exist('newdata','var') && exist('newtype','var'))
    newkey=addnodewithdata(handles,newdata,newtype,'Lattice');
end

% --------------------------------------------------------------------
function miMeshgrid5_Callback(hObject, eventdata, handles)
prompt = {'X-lattice range (a vector):',...
    'Y-lattice range (a vector):',...
    'Z-lattice range (a vector):'};
title = 'Create Meshgrid (5 tet/cell) Mesh';
dims = [1 1 1];
definput = {'1:10','1:8','1:5'};
res = inputdlg(prompt,title,dims,definput);
if(isempty(res))
    return;
end
newtype=dummytype;

[newdata.node,newdata.elem]=meshgrid5(eval(res{1}),eval(res{2}),eval(res{3}));
newdata.face=volface(newdata.elem);
newtype.hasnode=1;
newtype.hasface=1;
newtype.haselem=1;

if(exist('newdata','var') && exist('newtype','var'))
    newkey=addnodewithdata(handles,newdata,newtype,'Meshgrid5_');
end

% --------------------------------------------------------------------
function miMeshgrid6_Callback(hObject, eventdata, handles)
prompt = {'X-lattice range (a vector):',...
    'Y-lattice range (a vector):',...
    'Z-lattice range (a vector):'};
title = 'Create Meshgrid (6 tet/cell) Mesh';
dims = [1 1 1];
definput = {'1:10','1:8','1:5'};
res = inputdlg(prompt,title,dims,definput);
if(isempty(res))
    return;
end
newtype=dummytype;

[newdata.node,newdata.elem]=meshgrid5(eval(res{1}),eval(res{2}),eval(res{3}));
newdata.face=volface(newdata.elem);
newtype.hasnode=1;
newtype.hasface=1;
newtype.haselem=1;

if(exist('newdata','var') && exist('newtype','var'))
    newkey=addnodewithdata(handles,newdata,newtype,'Meshgrid6_');
end

% --------------------------------------------------------------------
function miOpen_Callback(hObject, eventdata, handles)
filter = {'*.mat';'*.*'};
root=get(handles.fgI2M,'userdata');

[file, path] = uigetfile(filter,'Load workspace');
if isequal(file,0)
   return;
else
   data=load(fullfile(path,file));
end
if(isfield(data,'i2mworkspace'))
    root.graph=data.i2mworkspace;
    updategraph(root,handles);
else
    warndlg('no saved workspace found','Warning');
end

% --------------------------------------------------------------------
function miSaveAll_Callback(hObject, eventdata, handles)
root=get(handles.fgI2M,'userdata');
i2mworkspace=root.graph;
filter = {'*.mat';'*.*'};
[file, path] = uiputfile(filter,'Save workspace');
if ~isequal(file,0) && ~isequal(path,0)
   save(fullfile(path,file),'i2mworkspace');
end

% --------------------------------------------------------------------
function miLoadVar_Callback(hObject, eventdata, handles)

nodedata=struct;
[file,path] = uigetfile({'*.mat','MATLAB data (*.mat)'});
if isequal(file,0)
   return;
else
   data=load(fullfile(path,file));
   vars=fieldnames(data);
   [idx, isok]=listdlg('ListString',vars,...
       'PromptString','Select a 3D array:');
   if(~isok)
       return;
   end
   for i=1:length(idx)
       dat=data.(vars{idx(i)});
       if(ndims(dat)==3 && ~isfield(nodedata,'vol'))
           nodedata.vol=dat;
       else
           nodedata.(vars{idx(i)})=dat;
       end
   end
end
adddatatograph(handles,nodedata);

% --------------------------------------------------------------------
function miExit_Callback(hObject, eventdata, handles)
close(handles.fgI2M);

% --------------------------------------------------------------------
function miRefresh_Callback(hObject, eventdata, handles)
root=get(handles.fgI2M,'userdata');
updategraph(root, handles);


function v = cvx_value( x )
global cvx___
try
    tv = subsref( cvx___.problems( x.problem_ ).duals, x.name_ );
catch
    v = NaN;
    return
end
v = value_( tv, cvx___.y );
function y = value_( x, y )
switch class( x ),
    case 'struct', y = cell2struct( value_( struct2cell( x ), y ), fieldnames( x ), 1 );
    case 'cell',   y = cellfun( @(z)value_( z, y ), x, 'UniformOutput', false );
    case 'cvx',    y = value( x, y );
    otherwise,     y = x;
end

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


% Buttons for loading/saving a prgram from commandLine
function interface_save_load_CommandLine_program_panel(h,xPos,yPos,loadSave_commandLine_Panel_width,...
    loadSave_commandLine_Panel_height)
%% About:
% Construct the interface-panel for load/save a program from commandLine
% interface

%% Areguments:
% h: handle of the main frame
% frame_width: width of the main frame (pixels)
% frame_height: height of the main frame (pixels)

% Copyright: Mohammad SAFEEA, 20th-July-2018

panel_Width=loadSave_commandLine_Panel_width;
panel_height=loadSave_commandLine_Panel_height;

x0=xPos;
y0=yPos;

pnl_h = uipanel(h,'Title','My Programs',...
                'Units','pixels');
            %     'FontSize',12,...
            %    'BackgroundColor','white',...
pnl_h.Position=[x0 y0 panel_Width panel_height];

% number of buttons
I=2;
J=1;
% separation ratio
rh=0.1;
rv=0.3;
btns_width=panel_Width/(J+(J+1)*rh);
btns_height=panel_height/(I+(I+1)*rv);

texts={'Load Program';
        'Save program'};

callback_functions={'fcnCallback_cmd_Load_coammnd_line_Program';
    'fcnCallback_cmd_save_coammnd_line_Program'};

icon_image={'icon_load.jpeg';
    'icon_save.jpeg'};
handles_Array=[];
for i=1:I
    for j=1:J
        labels_text=texts{i,j};
        btn_handle= uicontrol(pnl_h,'Style', 'pushbutton', 'String', labels_text,...
                'Units','pixels',...
                'Callback', callback_functions{i,j});
        x0=panel_Width-(btns_width*(1+rh))*(J+1-j);
        y0=panel_height-(btns_height*(1+rv))*(i)-0.5*rv*btns_height;
        btn_handle.HorizontalAlignment='center';
        btn_handle.Position=[x0 y0 btns_width btns_height];
        btn_handle.FontWeight='bold';
        % Add an icon to the button
        cd icons;
        d1=0;
        if btns_width<btns_height
            d1=btns_width;
        else
            d1=btns_height;
        end
        imageName=icon_image{i,j};
        addImageToButton(btn_handle,imageName,d1);
    end
end

end

function addImageToButton(btn_handle,imageName,d1)
        im=imread(imageName);
        scaleFactor=d1/max(max(max(size(im))));
        width=scaleFactor*size(im,2);
        width=floor(width);
        height=scaleFactor*size(im,1);
        height=floor(height);
        im2 = imresize(im,[width,height]);
        set(btn_handle,'CData',im2);
        cd ..;
end


function eeg_plot_metric

% eeg_plot_metric - create TeX plot label (Y is uV, X is msec)

% $Revision: 1.1 $ $Date: 2009-04-28 22:13:52 $

% Licence:  GNU GPL, no express or implied warranties
% History:  07/2000, Darren.Weber_at_radiology.ucsf.edu
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Font.FontName   = 'Helvetica';
Font.FontUnits  = 'Pixels';
Font.FontSize   = 12;
Font.FontWeight = 'normal';
Font.FontAngle  = 'normal';

ylab = get(gca,'ylabel');
set(ylab,'string','\muV','Rotation',0,Font,'units','normalized',...
    'Position',[-0.10  0.95 0]);
xlab = get(gca,'xlabel');
set(xlab,'string','msec','Rotation',0,Font,'units','normalized',...
    'Position',[ 1.07 -0.01 0]);

return


% SLAMTBSLAVE  A slave version of SLAMTB.
%
%   SLAMTBSLAVE is intended to be invoked by other scripts initializing
%   some of the parameters. By now it is NEESANALYSIS the only one to do
%   so.
%
%   See also NEESANALYSIS, NEESPLOTS.

%   Created and maintained by
%   Copyright 2008-2009 Joan Sola @ LAAS-CNRS.
%   Programmers:
%   Copyright David Marquez and Jean-Marie Codol @ LAAS-CNRS

%% OK we start here

% clear workspace and declare globals
%clear
global Map          %#ok<NUSED>

%% I. Specify user-defined options - EDIT USER DATA FILE userData.m

userDataPnt;        % user-defined data. SCRIPT.
% userDataLin;        % user-defined data. SCRIPT.

% These inputs come from neesAnalysis and overwrite some userData values:
Time.lastFrame            = numFrames;
Opt.init.initType         = lmkType;
Opt.correct.reparametrize = reparametrize;
SimOpt.random.newSeed     = false;
SimOpt.random.fixedSeed   = randSeeds(nRun);
FigOpt.rendPeriod         = rendPeriod;
Sensor{1}.pixErrorStd     = pixelNoise;

%% II. Initialize all data structures from user-defined data in userData.m
% SLAM data
[Rob,Sen,Raw,Lmk,Obs,Tim]     = createSlamStructures(...
    Robot,...
    Sensor,...      % all user data
    Time,...
    Opt);

% Simulation data
[SimRob,SimSen,SimLmk,SimOpt] = createSimStructures(...
    Robot,...
    Sensor,...      % all user data
    World,...
    SimOpt);

% Graphics handles
[MapFig,SenFig]               = createGraphicsStructures(...
    Rob, Sen, Lmk, Obs,...      % SLAM data
    SimRob, SimSen, SimLmk,...  % Simulator data
    FigOpt);                    % User-defined graphic options

%% III. Init data logging
% TODO: Create source and/or destination files and paths for data input and
% logs.
% TODO: do something here to collect data for post-processing or
% plotting. Think about collecting data in files using fopen, fwrite,
% etc., instead of creating large Matlab variables for data logging.

logFile = openLogFile(logFileName,'w');
writeLogHeader(logFile,logFileHeader);

% Clear user data - not needed anymore
clear Robot Sensor World Time   % clear all user data

%% IV. Main loop
for currentFrame = Tim.firstFrame : Tim.lastFrame

    % 1. SIMULATION
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    % Simulate robots
    for rob = [SimRob.rob]

        % Robot motion
        SimRob(rob) = simMotion(SimRob(rob),Tim);

        % Simulate sensor observations
        for sen = SimRob(rob).sensors

            % Observe simulated landmarks
            Raw(sen) = simObservation(SimRob(rob), SimSen(sen), SimLmk, SimOpt) ;

        end % end process sensors

    end % end process robots

    % 2. ESTIMATION
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    % Process robots
    for rob = [Rob.rob]

        % Robot motion
        % FIXME: see how to include noise in a clever way.
        Rob(rob).con.u = SimRob(rob).con.u + Rob(rob).con.uStd.*randn(6,1)*noiseFactor;

        Rob(rob) = motion(Rob(rob),Tim);

        % Process sensor observations
        for sen = Rob(rob).sensors

            %TODO: see how to pass only used Lmks and Obs.
            % Observe knowm landmarks
            [Rob(rob),Sen(sen),Lmk,Obs(sen,:)] = correctKnownLmks( ...
                Rob(rob),   ...
                Sen(sen),   ...
                Raw(sen),   ...
                Lmk,        ...
                Obs(sen,:), ...
                Opt) ;

            % Initialize new landmarks
            if currentFrame == Tim.firstFrame
                numInit = Opt.init.nbrInits(1);
            else
                numInit = Opt.init.nbrInits(2);
            end
            for ini = 1:numInit
                [Lmk,Obs(sen,:)] = initNewLmk(...
                    Rob(rob),   ...
                    Sen(sen),   ...
                    Raw(sen),   ...
                    Lmk,        ...
                    Obs(sen,:), ...
                    Opt) ;
            end

        end % end process sensors

    end % end process robots

    % 3. VISUALIZATION
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    if currentFrame == Tim.firstFrame ...
            || currentFrame == Tim.lastFrame ...
            || mod(currentFrame,FigOpt.rendPeriod) == 0

        % Figure of the Map:
        MapFig = drawMapFig(MapFig,  ...
            Rob, Sen, Lmk,  ...
            SimRob, SimSen, ...
            FigOpt);

        makeVideoFrame(MapFig, ...
            sprintf('map-%04d.png',currentFrame), ...
            FigOpt, ExpOpt);

        % Figures for all sensors
        for sen = [Sen.sen]
            SenFig(sen) = drawSenFig(SenFig(sen), ...
                Sen(sen), Raw(sen), Obs(sen,:), ...
                FigOpt);

            makeVideoFrame(SenFig(sen), ...
                sprintf('sen%02d-%04d.png', sen, currentFrame),...
                FigOpt, ExpOpt);

        end

        % Do draw all objects
        drawnow;
    end

    % 4. DATA LOGGING
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % TODO: do something here to collect data for post-processing or
    % plotting. Think about collecting data in files using fopen, fwrite,
    % etc., instead of creating large Matlab variables for data logging.

    % NEES for robot 1
    logData = errorAnalysis(Rob(1), SimRob(1), errorAnalysisFunction);
%     logData = robotNees(Rob(1),SimRob(1));
    writeLogData(logFile,[currentFrame,logData]);

end

%% V. Post-processing

closeLogFile(logFile);

% ========== End of function - Start GPL license ==========

%   # START GPL LICENSE

%---------------------------------------------------------------------
%
%   This file is part of SLAMTB, a SLAM toolbox for Matlab.
%
%   SLAMTB 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.
%
%   SLAMTB is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with SLAMTB.  If not, see <http://www.gnu.org/licenses/>.
%
%---------------------------------------------------------------------

%   SLAMTB is Copyright:
%   Copyright (c) 2008-2010, Joan Sola @ LAAS-CNRS,
%   Copyright (c) 2010-2013, Joan Sola,
%   Copyright (c) 2014-2015, Joan Sola @ IRI-UPC-CSIC,
%   SLAMTB is Copyright 2009
%   by Joan Sola, Teresa Vidal-Calleja, David Marquez and Jean Marie Codol
%   @ LAAS-CNRS.
%   See on top of this file for its particular copyright.

%   # END GPL LICENSE


function C = mtimes(A,B)
%MTIMES tensor-scalar multiplication.
%
%   C = MTIMES(A,B) is called for the syntax 'A * B' when A or B is a
%   tensor and the other argument is a scalar.
%
%   For tensor-matrix multiplication, use TTM.
%   For tensor-tensor multiplication, use TTT.
%   For tensor-tensor array multiplication, use TIMES or 'A .* B'.
%
%   Examples
%   X = tenrand([3,4,2])
%   W = 5 * X
%
%   See also TENSOR, TENSOR/TTM, TENSOR/TTT, TENSOR/TIMES
%
%MATLAB Tensor Toolbox.
%Copyright 2015, Sandia Corporation.

% This is the MATLAB Tensor Toolbox by T. Kolda, B. Bader, and others.
% http://www.sandia.gov/~tgkolda/TensorToolbox.
% Copyright (2015) 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 isscalar(B)
    C = A;
    C.data = B * C.data;
    return;
end

if isscalar(A)
    C = B;
    C.data = A * C.data;
    return;
end

error('Mtimes only supports a tensor times a scalar');


%ISOLATE_AXES Isolate the specified axes in a figure on their own
%
% Examples:
%   fh = isolate_axes(ah)
%   fh = isolate_axes(ah, vis)
%
% This function will create a new figure containing the axes/uipanels
% specified, and also their associated legends and colorbars. The objects
% specified must all be in the same figure, but they will generally only be
% a subset of the objects in the figure.
%
% IN:
%    ah - An array of axes and uipanel handles, which must come from the
%         same figure.
%    vis - A boolean indicating whether the new figure should be visible.
%          Default: false.
%
% OUT:
%    fh - The handle of the created figure.

% Copyright (C) Oliver Woodford 2011-2013

% Thank you to Rosella Blatt for reporting a bug to do with axes in GUIs
% 16/3/2012 Moved copyfig to its own function. Thanks to Bob Fratantonio
% for pointing out that the function is also used in export_fig.m.
% 12/12/12 - Add support for isolating uipanels. Thanks to michael for
% suggesting it.
% 08/10/13 - Bug fix to allchildren suggested by Will Grant (many thanks!).
% 05/12/13 - Bug fix to axes having different units. Thanks to Remington
% Reid for reporting the issue.

function fh = isolate_axes(ah, vis)
% Make sure we have an array of handles
if ~all(ishandle(ah))
    error('ah must be an array of handles');
end
% Check that the handles are all for axes or uipanels, and are all in the same figure
fh = ancestor(ah(1), 'figure');
nAx = numel(ah);
for a = 1:nAx
    if ~ismember(get(ah(a), 'Type'), {'axes', 'uipanel'})
        error('All handles must be axes or uipanel handles.');
    end
    if ~isequal(ancestor(ah(a), 'figure'), fh)
        error('Axes must all come from the same figure.');
    end
end
% Tag the objects so we can find them in the copy
old_tag = get(ah, 'Tag');
if nAx == 1
    old_tag = {old_tag};
end
set(ah, 'Tag', 'ObjectToCopy');
% Create a new figure exactly the same as the old one
fh = copyfig(fh); %copyobj(fh, 0);
if nargin < 2 || ~vis
    set(fh, 'Visible', 'off');
end
% Reset the object tags
for a = 1:nAx
    set(ah(a), 'Tag', old_tag{a});
end
% Find the objects to save
ah = findall(fh, 'Tag', 'ObjectToCopy');
if numel(ah) ~= nAx
    close(fh);
    error('Incorrect number of objects found.');
end
% Set the axes tags to what they should be
for a = 1:nAx
    set(ah(a), 'Tag', old_tag{a});
end
% Keep any legends and colorbars which overlap the subplots
lh = findall(fh, 'Type', 'axes', '-and', {'Tag', 'legend', '-or', 'Tag', 'Colorbar'});
nLeg = numel(lh);
if nLeg > 0
    set([ah(:); lh(:)], 'Units', 'normalized');
    ax_pos = get(ah, 'OuterPosition');
    if nAx > 1
        ax_pos = cell2mat(ax_pos(:));
    end
    ax_pos(:,3:4) = ax_pos(:,3:4) + ax_pos(:,1:2);
    leg_pos = get(lh, 'OuterPosition');
    if nLeg > 1;
        leg_pos = cell2mat(leg_pos);
    end
    leg_pos(:,3:4) = leg_pos(:,3:4) + leg_pos(:,1:2);
    ax_pos = shiftdim(ax_pos, -1);
    % Overlap test
    M = bsxfun(@lt, leg_pos(:,1), ax_pos(:,:,3)) & ...
        bsxfun(@lt, leg_pos(:,2), ax_pos(:,:,4)) & ...
        bsxfun(@gt, leg_pos(:,3), ax_pos(:,:,1)) & ...
        bsxfun(@gt, leg_pos(:,4), ax_pos(:,:,2));
    ah = [ah; lh(any(M, 2))];
end
% Get all the objects in the figure
axs = findall(fh);
% Delete everything except for the input objects and associated items
delete(axs(~ismember(axs, [ah; allchildren(ah); allancestors(ah)])));
end

function ah = allchildren(ah)
ah = findall(ah);
if iscell(ah)
    ah = cell2mat(ah);
end
ah = ah(:);
end

function ph = allancestors(ah)
ph = [];
for a = 1:numel(ah)
    h = get(ah(a), 'parent');
    while h ~= 0
        ph = [ph; h];
        h = get(h, 'parent');
    end
end
end


function C=Zlevelset_color(k)

if (k==1000)
    C(1)=255;
    C(2)=0;
    C(3)=0;
end

if (k==2000)
    C(1)=0;
    C(2)=255;
    C(3)=0;
end

if (k==3000)
    C(1)=0;
    C(2)=0;
    C(3)=255;
end

if (k==4000)
    C(1)=255;
    C(2)=255;
    C(3)=0;
end

if (k==5000)
    C(1)=255;
    C(2)=0;
    C(3)=255;
end

if (k==6000)
    C(1)=0;
    C(2)=255;
    C(3)=255;
end

if (k==7000)
    C(1)=128;
    C(2)=0;
    C(3)=0;
end

if (k==8000)
    C(1)=0;
    C(2)=128;
    C(3)=0;
end

if (k==9000)
    C(1)=0;
    C(2)=0;
    C(3)=128;
end

if (k==10000)
    C(1)=128;
    C(2)=128;
    C(3)=0;
end

if (k==11000)
    C(1)=128;
    C(2)=0;
    C(3)=128;
end

if (k==12000)
    C(1)=0;
    C(2)=128;
    C(3)=128;
end

if (k==13000)
    C(1)=255;
    C(2)=128;
    C(3)=128;
end

if (k==14000)
    C(1)=255;
    C(2)=128;
    C(3)=0;
end

if (k==15000)
    C(1)=255;
    C(2)=0;
    C(3)=128;
end

if (k==16000)
    C(1)=128;
    C(2)=255;
    C(3)=128;
end

if (k==17000)
    C(1)=128;
    C(2)=255;
    C(3)=0;
end

if (k==18000)
    C(1)=0;
    C(2)=255;
    C(3)=128;
end

if (k==19000)
    C(1)=128;
    C(2)=128;
    C(3)=255;
end

if (k==20000)
    C(1)=128;
    C(2)=0;
    C(3)=255;
end

if (k==21000)
    C(1)=0;
    C(2)=128;
    C(3)=255;
end


function xyzl_data_print ( point_num, line_num, line_data_num, ...
  line_pointer, line_data )

%*****************************************************************************80
%
%% XYZL_DATA_PRINT prints the data of an XYZL file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    08 January 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer POINT_NUM, the number of points.
%
%    Input, integer LINE_NUM, the number of lines.
%
%    Input, integer LINE_DATA_NUM, the number of line items.
%
%    Input, integer LINE_POINTER(LINE_NUM+1), pointers to the
%    first line item for each line.
%
%    Input, integer LINE_DATA(LINE_DATA_NUM), indices
%    of points that form lines.
%
  fprintf ( 1, '\n' );
  for line = 1 : line_num
    fprintf ( 1, '  %4d  %8d  %8d\n', ...
      line, line_pointer(line) : line_pointer(line+1) - 1 );
  end

  fprintf ( 1, '\n' );
  for line = 1 : line_num
    for i = line_pointer(line) : line_pointer(line+1) - 1
      fprintf ( 1, '  %d', line_data(i) );
    end
    fprintf ( 1, '\n' );
  end

  return
end


function [trl, event] = ft_trialfun_brainvision_segmented(cfg)

% FT_TRIALFUN_BRAINVISION_SEGMENTED creates trials for a Brain Vision Analyzer
% dataset that was segmented in the BVA software.
%
% Use as
%   cfg          = [];
%   cfg.dataset  = 'filename.vhdr';
%   cfg.trialfun = 'ft_trialfun_brainvision_segmented';
%   cfg  = ft_definetrial(cfg);
%   data = ft_preprocessing(cfg);
%
% Optionally, you can specify:
%   cfg.stimformat = 'S %d'
%
% The stimformat instruct this function to parse stimulus triggers according to
% the specific format. The default is 'S %d'. The cfg.stimformat always
% needs to contain exactly one %d code. The trigger values parsed in this way
% will be stored in columns 4 and upwards of the output 'trl' matrix, and
% after FT_PREPROCESSING will end up in data.trialinfo.
%
% A BrainVision dataset consists of three files: an .eeg, .vhdr, and a .vmrk
% file. The option cfg.dataset should refer to the .vhdr file.
%
% See also FT_DEFINETRIAL, FT_PREPROCESSING

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

hdr = ft_read_header(cfg.dataset);
event = ft_read_event(cfg.dataset);

% for backward compatibility
cfg = ft_checkconfig(cfg, 'renamed', {'trigformat', 'stimformat'});

% set the defaults
cfg.stimformat = ft_getopt(cfg, 'stimformat', 'S %d');

sel = find(strcmp({event.type}, 'New Segment'));
ntrial = length(sel);
fprintf('found %d segments in the data\n', ntrial);

sample = [event.sample];
if any(diff(sample)<0)
  % events should be ordered according to the sample in the file at which they occur
  ft_warning('reordering events based on their sample number');
  [sample, order] = sort(sample);
  event = event(order);
end

% for Brain Vision Analyzer the event type and value are strings
type  = {event.type};
value = {event.value};

begsample = nan(1,ntrial);
endsample = nan(1,ntrial);
offset    = nan(1,ntrial);
stim      = cell(1,ntrial);

for i=1:ntrial
  begevt = sel(i);
  if i<ntrial
    endevt = sel(i+1);
  else
    endevt = length(event);
  end

  % specify at which data sample the trial begins
  begsample(i) = sample(sel(i));

  % find the sample on which the trial is time-locked
  t0 = find(strcmp(type((begevt+1):endevt), 'Time 0'));
  t0 = t0(1); % take the first one in case there are multiple
  offset(i) = -(sample(begevt+t0) - begsample(i));

  % construct a list of all stimulus events in each segment
  stim{i} = find(strcmp(type((begevt+1):endevt), 'Stimulus'))+begevt;
end

% the endsample of each trial aligns with the beginsample of the next one
endsample(1:end-1) = begsample(2:end) - 1;
% the last endsample corresponds to the end of the file
endsample(end)     = hdr.nSamples*hdr.nTrials;

% add the stimulus events to the output, if possible
numstim = cellfun(@length, stim);
if (numstim > 0)
  if all(numstim==numstim(1))
    for i=1:length(stim)
      for j=1:numstim(i)
        if isempty(value{stim{i}(j)})
          ft_error('missing a stimulus type definition in the related *.vmrk file');
        end
        stimvalue  = sscanf(value{stim{i}(j)}, cfg.stimformat);
        stimsample = sample(stim{i}(j));
        stimtime   = (stimsample - begsample(i) + offset(i))/hdr.Fs; % relative to 'Time 0'
        if isempty(stimvalue)
          ft_error('the upper case letter of the stimulus value does not match with definition of "cfg.stimformat"');
        end
        trialinfo(i,2*(j-1)+1) = stimvalue;
        trialinfo(i,2*(j-1)+2) = stimtime;
      end % j
    end % i
  else
    ft_warning('the trials have a varying number of stimuli, not adding them to the "trl" matrix');
    trialinfo = [];
  end
else
  ft_warning('the trials have no stimuli, no "trialinfo" will be added to the "trl" matrix');
  trialinfo = [];
end

% combine the sample information and the trial information
trl = cat(2, [begsample(:) endsample(:) offset(:)], trialinfo);